@oddessentials/agent-guild 1.21.2 → 1.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/agent-guild.mjs +2 -0
- package/bin/native/win32-arm64/agent-guild-report.exe +0 -0
- package/bin/native/win32-x64/agent-guild-report.exe +0 -0
- package/bin/windows/arm64/agent-guild-start.exe +0 -0
- package/bin/windows/x64/agent-guild-start.exe +0 -0
- package/config/providers.default.json +4 -0
- package/docs/api.md +34 -3
- package/examples/terminal-ai-chat.json +27 -0
- package/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/node_modules/smol-toml/LICENSE +24 -0
- package/node_modules/smol-toml/README.md +605 -0
- package/node_modules/smol-toml/dist/date.d.ts +41 -0
- package/node_modules/smol-toml/dist/date.js +156 -0
- package/node_modules/smol-toml/dist/error.d.ts +37 -0
- package/node_modules/smol-toml/dist/error.js +67 -0
- package/node_modules/smol-toml/dist/extract.js +293 -0
- package/node_modules/smol-toml/dist/index.cjs +771 -0
- package/node_modules/smol-toml/dist/index.d.ts +44 -0
- package/node_modules/smol-toml/dist/index.js +34 -0
- package/node_modules/smol-toml/dist/parse.d.ts +73 -0
- package/node_modules/smol-toml/dist/parse.js +164 -0
- package/node_modules/smol-toml/dist/primitive.js +151 -0
- package/node_modules/smol-toml/dist/stringify.d.ts +32 -0
- package/node_modules/smol-toml/dist/stringify.js +219 -0
- package/node_modules/smol-toml/dist/struct.js +156 -0
- package/node_modules/smol-toml/dist/util.d.ts +43 -0
- package/node_modules/smol-toml/dist/util.js +57 -0
- package/node_modules/smol-toml/package.json +68 -0
- package/package.json +2 -1
- package/src/manager/config.mjs +10 -10
- package/src/manager/install-channels.mjs +3 -0
- package/src/manager/main.mjs +4 -0
- package/src/manager/mcp-connect.mjs +483 -0
- package/src/manager/providers.mjs +23 -4
- package/src/manager/server.mjs +16 -1
- package/src/manager/session-manager.mjs +2 -2
- package/web/app.js +92 -2
- package/web/index.html +11 -1
- package/web/styles.css +13 -2
- package/web/yard/art.json +1 -1
- package/web/yard/renderer.js +110 -36
- package/web/yard/view.js +13 -3
package/web/app.js
CHANGED
|
@@ -1624,6 +1624,7 @@ function selectAccount(provider, id) {
|
|
|
1624
1624
|
renderAccounts(card, provider);
|
|
1625
1625
|
renderUsage(card, provider);
|
|
1626
1626
|
renderReportingSetup(card, provider);
|
|
1627
|
+
renderMcpSetup(card, provider);
|
|
1627
1628
|
}
|
|
1628
1629
|
refreshPendingActions();
|
|
1629
1630
|
notifyViews();
|
|
@@ -1966,6 +1967,7 @@ function renderAccounts(card, provider) {
|
|
|
1966
1967
|
renderAccounts(card, provider);
|
|
1967
1968
|
renderUsage(card, provider);
|
|
1968
1969
|
renderReportingSetup(card, provider);
|
|
1970
|
+
renderMcpSetup(card, provider);
|
|
1969
1971
|
});
|
|
1970
1972
|
return chip;
|
|
1971
1973
|
}));
|
|
@@ -2265,6 +2267,91 @@ function renderReportingSetup(card, provider) {
|
|
|
2265
2267
|
};
|
|
2266
2268
|
}
|
|
2267
2269
|
|
|
2270
|
+
const openMcp = new Set();
|
|
2271
|
+
const mcpBusy = new Set();
|
|
2272
|
+
|
|
2273
|
+
/** What the card's Agent Guild MCP section says about one account, and the change it offers. */
|
|
2274
|
+
function mcpView(provider, entry) {
|
|
2275
|
+
const tool = provider.tool;
|
|
2276
|
+
const from = entry.from ? `${tool} takes it from ${entry.from}'s settings. ` : '';
|
|
2277
|
+
const yours = !entry.managed && !entry.from ? 'You added it yourself. ' : '';
|
|
2278
|
+
const typing = entry.allowInput ? ' It can also type into sessions.' : '';
|
|
2279
|
+
if (entry.state === 'checking') return { label: 'Checking…', status: `Reading ${tool}'s MCP settings.` };
|
|
2280
|
+
if (entry.state === 'off') {
|
|
2281
|
+
return { label: 'Off', status: entry.detail ? `${entry.detail} Turn on adds Agent Guild's own server to ${tool}'s settings.` : `Not added to ${tool}.`, action: 'on', button: 'Turn on' };
|
|
2282
|
+
}
|
|
2283
|
+
if (entry.state === 'on') {
|
|
2284
|
+
return {
|
|
2285
|
+
label: 'On', status: `${from}${yours}New ${tool} sessions can use it.${typing}`, action: 'off', button: 'Turn off',
|
|
2286
|
+
ask: yours ? { message: `Remove the agent-guild server you added to ${tool}'s settings?\n\n${entry.command}`, ok: 'Remove' } : null,
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
if (entry.state === 'disabled') {
|
|
2290
|
+
const replace = provider.mcp.mode === 'codex' && !entry.managed;
|
|
2291
|
+
return {
|
|
2292
|
+
label: 'Turned off', status: `${from}${yours}It is turned off in ${tool}.`, action: replace ? 'replace' : 'on', button: replace ? 'Replace…' : 'Turn on',
|
|
2293
|
+
ask: replace ? { message: `${tool} can turn this server on only by replacing it with Agent Guild's own. Replace it?\n\nNow: ${entry.command}`, ok: 'Replace' } : null,
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
if (entry.state === 'conflict') {
|
|
2297
|
+
return {
|
|
2298
|
+
label: 'Conflict', warn: true, action: 'replace', button: 'Replace…',
|
|
2299
|
+
status: `${entry.from ? `${tool} takes a server named agent-guild from ${entry.from}'s settings that` : `${tool} already has a server named agent-guild that`} ${entry.detail}.`,
|
|
2300
|
+
ask: entry.from
|
|
2301
|
+
? { message: `Add Agent Guild's own MCP server to ${tool}'s settings? ${tool} then uses it instead of the one in ${entry.from}'s settings, which stays as it is.`, ok: 'Add' }
|
|
2302
|
+
: { message: `Replace the agent-guild server in ${tool}'s settings with Agent Guild's own?${entry.command ? `\n\nNow: ${entry.command}` : ''}`, ok: 'Replace' },
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
return { label: 'Unreadable', warn: true, status: `Agent Guild can't read ${tool}'s MCP settings: ${entry.detail}.` };
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
function renderMcpSetup(card, provider) {
|
|
2309
|
+
const box = card.querySelector('.mcp');
|
|
2310
|
+
const account = selectedAccount(provider);
|
|
2311
|
+
const entry = provider.mcp?.accounts.find((a) => a.id === account.id);
|
|
2312
|
+
box.hidden = !provider.available || !entry;
|
|
2313
|
+
if (box.hidden) return;
|
|
2314
|
+
const view = mcpView(provider, entry);
|
|
2315
|
+
const key = `${provider.id}:${entry.id}`;
|
|
2316
|
+
box.open = openMcp.has(provider.id);
|
|
2317
|
+
box.ontoggle = () => (box.open ? openMcp.add(provider.id) : openMcp.delete(provider.id));
|
|
2318
|
+
box.classList.toggle('warned', Boolean(view.warn));
|
|
2319
|
+
box.querySelector('.mcp-state').textContent = view.label;
|
|
2320
|
+
box.querySelector('.mcp-about').textContent = `Lets ${provider.tool} see your Agent Guild sessions, read their replies and screens, and start or stop sessions when you approve.`;
|
|
2321
|
+
box.querySelector('.mcp-status').textContent = (provider.mcp.accounts.length > 1 ? `${entry.label} account: ` : '') + view.status;
|
|
2322
|
+
const command = box.querySelector('.mcp-command');
|
|
2323
|
+
command.hidden = !entry.command || entry.managed;
|
|
2324
|
+
command.textContent = entry.command ?? '';
|
|
2325
|
+
const button = box.querySelector('.mcp-action');
|
|
2326
|
+
button.hidden = !view.action;
|
|
2327
|
+
button.textContent = view.button ?? '';
|
|
2328
|
+
button.disabled = mcpBusy.has(key);
|
|
2329
|
+
button.onclick = () => changeMcp(provider, entry, view);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
function repaintMcp(id) {
|
|
2333
|
+
const provider = state.providers.find((p) => p.id === id);
|
|
2334
|
+
if (!provider) return;
|
|
2335
|
+
for (const card of document.querySelectorAll('.provider[data-id]')) if (card.dataset.id === id) renderMcpSetup(card, provider);
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
async function changeMcp(provider, entry, view) {
|
|
2339
|
+
if (view.ask && !(await ask(view.ask.message, { ok: view.ask.ok }))) return;
|
|
2340
|
+
const key = `${provider.id}:${entry.id}`;
|
|
2341
|
+
mcpBusy.add(key);
|
|
2342
|
+
repaintMcp(provider.id);
|
|
2343
|
+
try {
|
|
2344
|
+
const { result } = await api('POST', `/providers/${provider.id}/mcp`, { account: entry.id, action: view.action, expect: entry.fingerprint });
|
|
2345
|
+
if (result.outcome === 'failed') toast(result.detail, 12000);
|
|
2346
|
+
} catch (err) {
|
|
2347
|
+
if (err instanceof AuthError) return showAuth(err.message);
|
|
2348
|
+
toast(err.message, 10000);
|
|
2349
|
+
} finally {
|
|
2350
|
+
mcpBusy.delete(key);
|
|
2351
|
+
repaintMcp(provider.id);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2268
2355
|
let dealt = false;
|
|
2269
2356
|
|
|
2270
2357
|
// Both layouts mount these same controls with these same command handlers.
|
|
@@ -2311,7 +2398,8 @@ function buildProvider(provider) {
|
|
|
2311
2398
|
if (provider.available && provider.instructionsSource && !instructionCounts.has(instructionKey(provider))) refreshInstructionCounts();
|
|
2312
2399
|
const install = node.querySelector('.install');
|
|
2313
2400
|
install.hidden = provider.available || !provider.installable;
|
|
2314
|
-
install.title = provider.
|
|
2401
|
+
install.title = provider.plugin ? `Downloads the latest ${provider.tool} release into Docker's plugin folder, in a session.`
|
|
2402
|
+
: provider.installCommand ? `Run "${provider.installCommand}" in a session` : `Install ${provider.tool} using npm.${provider.npmNote ? ` ${provider.npmNote}` : ''}`;
|
|
2315
2403
|
install.addEventListener('click', () => installProvider(provider, node));
|
|
2316
2404
|
const update = node.querySelector('.update');
|
|
2317
2405
|
update.hidden = !(provider.available && provider.updateCommand && (provider.updateAvailable || checkFailed));
|
|
@@ -2336,6 +2424,7 @@ function buildProvider(provider) {
|
|
|
2336
2424
|
renderMultiplexers(node, provider);
|
|
2337
2425
|
renderUsage(node, provider);
|
|
2338
2426
|
renderReportingSetup(node, provider);
|
|
2427
|
+
renderMcpSetup(node, provider);
|
|
2339
2428
|
renderModelStats(node, provider);
|
|
2340
2429
|
renderProviderPending(node, provider);
|
|
2341
2430
|
paintManagerActions(node);
|
|
@@ -3830,7 +3919,7 @@ function installNote(provider) {
|
|
|
3830
3919
|
}
|
|
3831
3920
|
if (last.kind === 'uninstall') return last.outcome === 'remaining' ? 'Uninstalled copy is still present' : '';
|
|
3832
3921
|
if (last.verification === 'failed') return `Installation completed, but ${provider.tool} verification failed`;
|
|
3833
|
-
if (last.outcome === 'missing') return provider.
|
|
3922
|
+
if (last.outcome === 'missing') return provider.plugin ? 'Installed, but docker does not list it' : 'Installed, but not found on PATH';
|
|
3834
3923
|
if (last.outcome === 'unchanged') return 'No version change after update';
|
|
3835
3924
|
return '';
|
|
3836
3925
|
}
|
|
@@ -8546,6 +8635,7 @@ yardUi = initYard({
|
|
|
8546
8635
|
renderLaunchFlags(node, provider);
|
|
8547
8636
|
renderUsage(node, provider);
|
|
8548
8637
|
renderReportingSetup(node, provider);
|
|
8638
|
+
renderMcpSetup(node, provider);
|
|
8549
8639
|
renderModelStats(node, provider);
|
|
8550
8640
|
node.dataset.contentSignature = contentSignature;
|
|
8551
8641
|
}
|
package/web/index.html
CHANGED
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
<div class="yard-overlay">
|
|
138
138
|
<div id="yard-loading" class="yard-loading" role="status" data-mode="scene"><span id="yard-loading-text">Preparing your yard…</span><span id="yard-loading-size" class="yard-loading-size" aria-hidden="true"></span><span class="yard-loading-bar" aria-hidden="true"></span></div>
|
|
139
139
|
<div id="yard-swap-failure" class="yard-swap-failure" hidden role="status"><span id="yard-swap-failure-text"></span><button id="yard-swap-retry" class="btn" type="button">Retry</button></div>
|
|
140
|
-
<div class="yard-camera" role="group" aria-label="
|
|
140
|
+
<div class="yard-camera" role="group" aria-label="Yard controls"><button id="yard-zoom-in" type="button" class="btn" aria-label="Zoom in">+</button><button id="yard-zoom-out" type="button" class="btn" aria-label="Zoom out">−</button><button id="yard-fit" type="button" class="btn">Overview</button><button id="yard-focus" type="button" class="btn" disabled>Focus selected</button><button id="yard-photo" type="button" class="btn" aria-haspopup="dialog" aria-label="Save a picture of the Yard" title="Save a picture of the Yard" disabled hidden><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M4 8.5A1.5 1.5 0 0 1 5.5 7h2.3l1.4-2h5.6l1.4 2h2.3A1.5 1.5 0 0 1 20 8.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 17.5z"/><circle cx="12" cy="12.75" r="3.25"/></svg></button><button id="yard-fireworks" type="button" class="btn" aria-label="Fireworks in this Yard only" title="Fireworks in this Yard only" disabled><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M12 3v3m0 9v6M3 10h3m12 0h3M5.6 3.6l2.2 2.2m8.4 8.4 2.2 2.2M18.4 3.6l-2.2 2.2m-8.4 8.4-2.2 2.2"/><circle cx="12" cy="10" r="1"/></svg></button></div>
|
|
141
141
|
<p id="yard-help"><span class="yard-help-pointer">Drag to explore · Scroll to zoom · Select to inspect · Double-click a session to open</span><span class="yard-help-touch">Drag to explore · Pinch to zoom · Tap to inspect · Open from the Inspector</span></p>
|
|
142
142
|
</div>
|
|
143
143
|
</div>
|
|
@@ -832,6 +832,16 @@
|
|
|
832
832
|
<button class="btn multiplexer-refresh" type="button">Refresh</button>
|
|
833
833
|
<div class="multiplexer-list"></div>
|
|
834
834
|
</details>
|
|
835
|
+
<details class="mcp" hidden>
|
|
836
|
+
<summary><span class="mcp-title">Agent Guild MCP</span><span class="mcp-state"></span></summary>
|
|
837
|
+
<p class="mcp-about"></p>
|
|
838
|
+
<p class="mcp-status"></p>
|
|
839
|
+
<code class="mcp-command" hidden></code>
|
|
840
|
+
<div class="mcp-actions">
|
|
841
|
+
<a class="console-link" href="https://github.com/oddessentials/agent-guild/blob/main/docs/mcp.md" target="_blank" rel="noopener noreferrer">How it works</a>
|
|
842
|
+
<button class="btn mcp-action" type="button" hidden></button>
|
|
843
|
+
</div>
|
|
844
|
+
</details>
|
|
835
845
|
<p class="hint" hidden></p>
|
|
836
846
|
<div class="provider-actions">
|
|
837
847
|
<button class="btn primary new" type="button">New</button>
|
package/web/styles.css
CHANGED
|
@@ -243,7 +243,7 @@ main { max-width: calc(1200px + var(--dock-space, 0px)); margin: 0 auto; padding
|
|
|
243
243
|
font: inherit; font-size: 0.78rem; text-align: left; cursor: pointer;
|
|
244
244
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
245
245
|
}
|
|
246
|
-
.model-stats-head::after, .console-link::after, .menu-button::after, .model-name::before, .provider .copies summary::before {
|
|
246
|
+
.model-stats-head::after, .console-link::after, .menu-button::after, .model-name::before, .provider .copies summary::before, .provider .mcp summary::before {
|
|
247
247
|
content: ""; display: inline-block; flex: none; width: 0.75em; height: 0.75em; margin-left: 0.3em; vertical-align: -0.05em;
|
|
248
248
|
background: currentColor; mask: var(--icon-chevron) center / contain no-repeat;
|
|
249
249
|
}
|
|
@@ -336,6 +336,17 @@ main { max-width: calc(1200px + var(--dock-space, 0px)); margin: 0 auto; padding
|
|
|
336
336
|
.provider .copies li span { display: block; }
|
|
337
337
|
.provider .copies .copy-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 24px; }
|
|
338
338
|
.provider .copies .copy-name { color: var(--text); min-width: 0; }
|
|
339
|
+
.provider .mcp { font-size: 0.78rem; color: var(--muted); overflow-wrap: anywhere; }
|
|
340
|
+
.provider .mcp summary { display: flex; align-items: baseline; cursor: pointer; list-style: none; white-space: nowrap; }
|
|
341
|
+
.provider .mcp summary::-webkit-details-marker { display: none; }
|
|
342
|
+
.provider .mcp summary::before { margin: 0 0.3em 0 0; align-self: center; transition: transform 0.15s var(--ease); }
|
|
343
|
+
.provider .mcp[open] summary::before { transform: rotate(90deg); }
|
|
344
|
+
.provider .mcp .mcp-state { margin-left: auto; padding-left: 8px; font-weight: 600; white-space: nowrap; }
|
|
345
|
+
.provider .mcp.warned .mcp-state { color: var(--warn); }
|
|
346
|
+
.provider .mcp p { margin: 6px 0 0; line-height: 1.45; }
|
|
347
|
+
.provider .mcp .mcp-command { display: block; margin-top: 4px; font-size: 0.72rem; color: var(--text); }
|
|
348
|
+
.provider .mcp .mcp-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; }
|
|
349
|
+
.provider .mcp .mcp-action { padding: 2px 10px; font-size: 0.75rem; white-space: nowrap; }
|
|
339
350
|
.provider .copies .copy-path { font-family: var(--font-mono); font-size: 0.72rem; }
|
|
340
351
|
.provider .copies .copy-uninstall { flex: none; padding: 2px 10px; font-size: 0.75rem; }
|
|
341
352
|
.provider.busy { opacity: 0.6; pointer-events: none; }
|
|
@@ -1316,7 +1327,7 @@ body:has(#terminal-panel:not([hidden]) .terminal-controls:not([hidden])) .toast
|
|
|
1316
1327
|
|
|
1317
1328
|
@media (prefers-reduced-motion: reduce) {
|
|
1318
1329
|
.status-pill.active::before, .agent.working::after, .model-detail .stat-fill, .toast:not([hidden]), .tip:not([hidden]), .run-failed:not([hidden]), .menu:popover-open { animation: none; }
|
|
1319
|
-
.model-name::before, .provider .copies summary::before, .menu-button::after, .btn, .videos-play img, .videos-play-icon, .models, .news-panel, .models::backdrop, .news-panel::backdrop { transition: none; }
|
|
1330
|
+
.model-name::before, .provider .copies summary::before, .provider .mcp summary::before, .menu-button::after, .btn, .videos-play img, .videos-play-icon, .models, .news-panel, .models::backdrop, .news-panel::backdrop { transition: none; }
|
|
1320
1331
|
.github-waiting::before, .github-running, body:has(#app[hidden]):has(#auth[hidden]):has(#stopped[hidden])::after { animation: none; }
|
|
1321
1332
|
.btn:active:not(:disabled):not([aria-disabled="true"]) { transform: none; }
|
|
1322
1333
|
.btn.voice[aria-pressed="true"]::before { animation: none; }
|