Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.2.2 - 2026-05-17

### Fixed
- Restored the full governor UI from the prepared release work: digit-only inputs, narrow two-column layout, safe default values, and protection against live refresh wiping unsaved edits.
- Added the missing risk-disclaimer modal linked from the governor acknowledgement text.
- Restored the compact two-line footer with activity summary and color-coded status messages.
- Added bulk tab visibility bridge methods so the header show/hide-all control can use one desktop IPC call when available.
- Made Chrome CDP the first browser backend option in the Control Center.

### Verified
- Control Center script syntax check passed.
- Public package dry-run excludes private workflows.

## 0.2.1 - 2026-05-17

### Fixed
Expand Down
31 changes: 31 additions & 0 deletions main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,37 @@ async function main() {
return { ok: true };
});

const setTabsVisible = async (visible) => {
let changed = 0;
for (const tab of tabs.listTabs()) {
try {
const win = tabs.getWindowById(tab.id);
if (visible) {
if (win.isMinimized?.()) win.restore?.();
win.show?.();
win.focus?.();
} else {
win.minimize?.();
}
changed += 1;
} catch {}
}
emitTabsChanged();
return { ok: true, changed };
};

ipcMain.handle('agentify:setTabsVisible', async (_evt, args) => {
return await setTabsVisible(!!args?.visible);
});

ipcMain.handle('agentify:showAllTabs', async () => {
return await setTabsVisible(true);
});

ipcMain.handle('agentify:hideAllTabs', async () => {
return await setTabsVisible(false);
});

ipcMain.handle('agentify:closeTab', async (_evt, args) => {
const tabId = String(args?.tabId || '').trim();
if (!tabId) throw new Error('missing_tabId');
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agentify/desktop",
"version": "0.2.1",
"version": "0.2.2",
"description": "Agentify Desktop control center and MCP server for local AI web sessions",
"license": "MPL-2.0",
"type": "module",
Expand Down
102 changes: 99 additions & 3 deletions ui/control-center.css
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ body {
grid-template-columns: 1fr 1fr;
gap: 8px 12px;
}
.governorIntro {
margin-bottom: 14px;
}
.governorGrid {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 14px;
}
.governorInput {
max-width: 112px;
text-align: right;
}
.compactNum {
max-width: 160px;
}
Expand Down Expand Up @@ -261,16 +272,95 @@ input::placeholder { color: rgba(233,236,242,0.45); }

.hint { font-size: 12px; color: rgba(233,236,242,0.66); line-height: 1.35; margin-top: 8px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
.linkButton {
border: 0;
padding: 0;
background: transparent;
color: #93c5fd;
cursor: pointer;
font: inherit;
text-decoration: underline;
text-underline-offset: 2px;
}
.linkButton:hover { color: #bfdbfe; }
.modal {
max-width: min(560px, calc(100vw - 32px));
border: 1px solid rgba(255,255,255,0.12);
border-radius: 12px;
padding: 0;
background: #10131a;
color: #e9ecf2;
box-shadow: 0 22px 70px rgba(0,0,0,0.52);
}
.modal::backdrop { background: rgba(0,0,0,0.58); }
.modalPanel { padding: 14px; }
.modalHeader {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.modalTitle { font-weight: 700; }
.modalBody {
margin-top: 12px;
color: rgba(233,236,242,0.78);
font-size: 13px;
line-height: 1.45;
}
.modalBody p { margin: 0 0 10px; }
.modalBody p:last-child { margin-bottom: 0; }
.compactBtn {
flex: 0 0 auto;
padding: 7px 10px;
border-radius: 10px;
line-height: 1;
white-space: nowrap;
}

.footer {
border-top: 1px solid rgba(255,255,255,0.08);
padding: 10px 14px;
padding: 6px 10px;
display: flex;
justify-content: flex-start;
justify-content: space-between;
align-items: center;
gap: 12px;
background: rgba(0,0,0,0.15);
min-height: 44px;
}
.footerStatus {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.activityLabel {
font-size: 12px;
font-weight: 700;
color: rgba(233,236,242,0.86);
}
.status {
font-size: 12px;
color: rgba(233,236,242,0.7);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.messageLine {
font-size: 11px;
color: #93c5fd;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.messageLine.isWarn {
color: #fbbf24;
}
.messageLine.isError {
color: #fca5a5;
}
.messageLine.isMuted {
color: rgba(233,236,242,0.52);
}
.status { font-size: 12px; color: rgba(233,236,242,0.65); }

@media (max-width: 760px) {
.header {
Expand All @@ -284,3 +374,9 @@ input::placeholder { color: rgba(233,236,242,0.45); }
font-size: 12px;
}
}

@media (max-width: 420px) {
.governorGrid {
grid-template-columns: 1fr;
}
}
51 changes: 39 additions & 12 deletions ui/control-center.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,26 @@
</section>

<section class="card">
<div class="cardTitle">Automation limits</div>
<div class="hint">
<div class="cardTitle">Settings (governor)</div>
<div class="hint governorIntro">
These defaults exist to reduce accidental high-rate automation. Automating web UIs may violate website terms; use responsibly.
</div>
<div class="grid settingsGrid">
<div class="grid governorGrid">
<label class="field">
<div class="label">Max in-flight queries</div>
<input id="setMaxInflight" class="compactNum" type="number" min="1" max="12" step="1" />
<input id="setMaxInflight" class="governorInput" type="text" inputmode="numeric" pattern="[0-9]*" autocomplete="off" data-min="1" data-max="12" value="2" />
</label>
<label class="field">
<div class="label">Max queries per minute</div>
<input id="setQpm" class="compactNum" type="number" min="1" max="600" step="1" />
<input id="setQpm" class="governorInput" type="text" inputmode="numeric" pattern="[0-9]*" autocomplete="off" data-min="1" data-max="600" value="12" />
</label>
<label class="field">
<div class="label">Min gap per tab (ms)</div>
<input id="setTabGap" class="compactNum" type="number" min="0" max="60000" step="50" />
<input id="setTabGap" class="governorInput" type="text" inputmode="numeric" pattern="[0-9]*" autocomplete="off" data-min="0" data-max="60000" value="1200" />
</label>
<label class="field">
<div class="label">Min global gap (ms)</div>
<input id="setGlobalGap" class="compactNum" type="number" min="0" max="10000" step="10" />
<input id="setGlobalGap" class="governorInput" type="text" inputmode="numeric" pattern="[0-9]*" autocomplete="off" data-min="0" data-max="10000" value="200" />
</label>
</div>
<div class="row">
Expand All @@ -176,10 +176,10 @@
</label>
</div>
<div class="row">
<label class="checkbox">
<div class="checkbox">
<input id="setAcknowledge" type="checkbox" />
<span>I understand the risks and want to change these limits</span>
</label>
<span>I understand the <button id="btnRiskDetails" class="linkButton" type="button">risks</button> and want to change these limits</span>
</div>
<div class="btnRow">
<button id="btnResetSettings" class="btn secondary">Reset</button>
<button id="btnSaveSettings" class="btn primary" disabled>Save</button>
Expand All @@ -197,8 +197,8 @@
<label class="field">
<div class="label">Browser backend</div>
<select id="setBrowserBackend">
<option value="electron">Electron embedded tabs</option>
<option value="chrome-cdp">Chrome CDP (better SSO)</option>
<option value="electron">Electron embedded tabs</option>
</select>
<div class="fieldHelp">Use `chrome-cdp` for Google/Microsoft/Apple SSO and real Chrome profile sessions.</div>
</label>
Expand All @@ -219,8 +219,35 @@
</section>
</main>

<dialog id="riskModal" class="modal">
<div class="modalPanel">
<div class="modalHeader">
<div class="modalTitle">Automation risk controls</div>
<button id="btnCloseRiskModal" class="btn secondary compactBtn" type="button" aria-label="Close">Close</button>
</div>
<div class="modalBody">
<p>
Agentify Desktop controls browser tabs on your machine. High-frequency tab automation can accidentally send repeated prompts,
trigger abuse systems, consume account quota, or violate a website's terms of use.
</p>
<p>
The governor reduces those risks by limiting concurrent prompts, capping prompts per minute, spacing requests to the same tab,
and enforcing a short global gap between sends. CAPTCHA, login, and auth challenges pause automation and bring the tab forward
so you can resolve them manually.
</p>
<p>
These controls are guardrails, not permission to ignore service limits. Keep the defaults unless you have a specific reason,
and raise limits only for websites and accounts where that activity is allowed.
</p>
</div>
</div>
</dialog>

<footer class="footer">
<div id="statusLine" class="status">Loading…</div>
<div class="footerStatus">
<div id="statusLine" class="status"><span class="activityLabel">Activity:</span> Starting Agentify Desktop…</div>
<div id="messageLine" class="messageLine">Loading…</div>
</div>
</footer>
</div>

Expand Down
Loading
Loading