ai-agentmanager 0.0.0-stage → 1.0.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/CHANGELOG.md +48 -0
- package/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +768 -2
- package/SECURITY.md +44 -0
- package/bin/agentmgr-hub.js +16 -0
- package/bin/agentmgr.js +4 -0
- package/docs/architecture.md +67 -0
- package/docs/distributed.md +147 -0
- package/docs/engines.md +177 -0
- package/docs/images/agents.jpg +0 -0
- package/docs/images/conflict-radar.jpg +0 -0
- package/docs/plugins.md +81 -0
- package/package.json +58 -4
- package/public/app.js +3138 -0
- package/public/hub/hub.css +230 -0
- package/public/hub/hub.js +766 -0
- package/public/hub/index.html +146 -0
- package/public/hub/term.js +147 -0
- package/public/index.html +354 -0
- package/public/share.html +34 -0
- package/public/share.js +41 -0
- package/public/style.css +550 -0
- package/public/touchscroll.js +73 -0
- package/public/transport.js +78 -0
- package/scripts/build-release.sh +58 -0
- package/scripts/fix-pty.js +15 -0
- package/src/about.js +70 -0
- package/src/backlog.js +413 -0
- package/src/brief.js +512 -0
- package/src/cli.js +1471 -0
- package/src/client.js +49 -0
- package/src/config.js +109 -0
- package/src/conflicts.js +105 -0
- package/src/engines/antigravity.js +296 -0
- package/src/engines/claude.js +98 -0
- package/src/engines/codex.js +331 -0
- package/src/engines/index.js +37 -0
- package/src/fleet.js +176 -0
- package/src/git.js +340 -0
- package/src/hub.js +857 -0
- package/src/hubactions.js +107 -0
- package/src/hubbacklog.js +373 -0
- package/src/hublink.js +437 -0
- package/src/inbox.js +94 -0
- package/src/judge.js +278 -0
- package/src/livebrowser.js +637 -0
- package/src/manager.js +2554 -0
- package/src/notify.js +284 -0
- package/src/plugins.js +119 -0
- package/src/preview.js +334 -0
- package/src/races.js +192 -0
- package/src/remote.js +284 -0
- package/src/server.js +762 -0
- package/src/service.js +150 -0
- package/src/sessions.js +160 -0
- package/src/store.js +104 -0
- package/src/stuck.js +160 -0
- package/src/tracker.js +311 -0
- package/src/trust.js +44 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
7
|
+
<title>AI Agent Manager</title>
|
|
8
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 16 16%22%3E%3Cpath d=%22M8 1l7 7-7 7-7-7z%22 fill=%22%233b5bdb%22/%3E%3C/svg%3E" />
|
|
9
|
+
<link rel="stylesheet" href="/vendor/xterm/css/xterm.css" />
|
|
10
|
+
<link rel="stylesheet" href="/style.css" />
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<header class="topbar">
|
|
14
|
+
<div class="brand">
|
|
15
|
+
<span class="logo" aria-hidden="true">◆</span>
|
|
16
|
+
<h1>AI Agent Manager</h1>
|
|
17
|
+
<button id="about-btn" class="about-btn" type="button" title="About AI Agent Manager: version, release, links">About</button>
|
|
18
|
+
<span id="conn" class="conn" title="Daemon connection">connecting…</span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="top-actions">
|
|
21
|
+
<input id="filter" type="search" placeholder="Filter agents" aria-label="Filter agents" />
|
|
22
|
+
<button id="alerts-btn" class="local-only" title="Slack alerts when an agent needs you">Alerts</button>
|
|
23
|
+
<button id="remote-btn" class="local-only" title="Open AI Agent Manager from your phone">Remote access</button>
|
|
24
|
+
<button id="ask-btn" title="A general Claude session with no repo or folder">Ask Claude</button>
|
|
25
|
+
<button id="new-btn" class="primary">+ New agents</button>
|
|
26
|
+
</div>
|
|
27
|
+
</header>
|
|
28
|
+
|
|
29
|
+
<main class="layout">
|
|
30
|
+
<aside class="sidebar">
|
|
31
|
+
<div class="side-tabs" role="tablist">
|
|
32
|
+
<button class="side-tab active" data-tab="agents" role="tab">Agents</button>
|
|
33
|
+
<button class="side-tab" data-tab="inbox" role="tab" title="Everything waiting on you: prompts, questions, stuck agents, overlaps">Inbox <span id="inbox-count" class="badge"></span></button>
|
|
34
|
+
<button class="side-tab" data-tab="backlog" role="tab">Backlog <span id="backlog-count" class="badge"></span></button>
|
|
35
|
+
</div>
|
|
36
|
+
<div id="agents-view">
|
|
37
|
+
<div class="counts" id="counts"></div>
|
|
38
|
+
<ul id="agent-list" class="agent-list" aria-label="Agents"></ul>
|
|
39
|
+
</div>
|
|
40
|
+
<div id="backlog-view" hidden></div>
|
|
41
|
+
<div id="inbox-view" hidden></div>
|
|
42
|
+
<div id="empty" class="empty" hidden>
|
|
43
|
+
<p>No agents yet.</p>
|
|
44
|
+
<p>Add one or more intents and a repo or folder to get started.</p>
|
|
45
|
+
</div>
|
|
46
|
+
</aside>
|
|
47
|
+
|
|
48
|
+
<section class="detail" id="detail">
|
|
49
|
+
<div class="placeholder" id="placeholder">Select an agent to see its session, folder, repo, PRs and bugs.</div>
|
|
50
|
+
<div id="detail-body" hidden></div>
|
|
51
|
+
<div class="term-wrap" id="term-wrap" hidden>
|
|
52
|
+
<div class="term-bar">
|
|
53
|
+
<div class="term-tabs" role="tablist">
|
|
54
|
+
<button class="term-tab" data-kind="claude" role="tab">Claude</button>
|
|
55
|
+
<span id="shell-tabs" class="term-tabs"></span>
|
|
56
|
+
<button class="term-tab term-add" id="shell-new" title="Open another shell in the agent's folder">+ Shell</button>
|
|
57
|
+
<span id="browser-tabs" class="term-tabs"></span>
|
|
58
|
+
<button class="term-tab term-add" id="browser-new" title="View a page as this machine sees it (a dev server on localhost, or any address), from any device">+ Browser</button>
|
|
59
|
+
</div>
|
|
60
|
+
<span id="term-title"></span>
|
|
61
|
+
<span class="spacer"></span>
|
|
62
|
+
<button id="term-attach" class="ghost small" title="Attach files or images (you can also drop or paste them into the terminal)">📎 Attach</button>
|
|
63
|
+
<input type="file" id="term-file" multiple hidden>
|
|
64
|
+
<button id="term-fit" class="ghost small" title="Refit the terminal to the panel">Fit</button>
|
|
65
|
+
<button id="term-close" class="ghost small" title="Hide the terminal (the agent keeps running)">Hide terminal</button>
|
|
66
|
+
</div>
|
|
67
|
+
<div id="signin-bar" class="signin-bar" hidden></div>
|
|
68
|
+
<div id="terminal" class="terminal"></div>
|
|
69
|
+
<div id="browser" class="browser">
|
|
70
|
+
<form id="browser-bar" class="browser-bar" autocomplete="off">
|
|
71
|
+
<button type="button" id="browser-back" class="ghost small live-only" title="Back">◀</button>
|
|
72
|
+
<button type="button" id="browser-fwd" class="ghost small live-only" title="Forward">▶</button>
|
|
73
|
+
<button type="button" id="browser-reload" class="ghost small" title="Reload the page">⟳</button>
|
|
74
|
+
<input id="browser-url" placeholder="localhost:5173, a port, or any address" spellcheck="false" autocapitalize="off" autocorrect="off" enterkeyhint="go">
|
|
75
|
+
<button class="small">Go</button>
|
|
76
|
+
<button type="button" id="browser-sound" class="ghost small live-only" title="Hear the page: sound from videos and audio playing on that machine">🔇</button>
|
|
77
|
+
<button type="button" id="browser-keys" class="ghost small live-only touch-only" title="Show the keyboard to type into the page">⌨</button>
|
|
78
|
+
<button type="button" id="browser-mode" class="ghost small" hidden></button>
|
|
79
|
+
<a id="browser-pop" class="ghost small button" target="_blank" rel="noopener" title="Open in a new browser tab on this device" hidden>↗</a>
|
|
80
|
+
</form>
|
|
81
|
+
<div id="browser-hint" class="browser-hint" hidden>Blank? Many sites refuse to show inside another page. Open it with ↗ instead.</div>
|
|
82
|
+
<div id="browser-cert" class="browser-start" hidden>
|
|
83
|
+
<p><b>One more step on this device.</b> Each browser tab goes through its own port, and this device hasn't accepted AI Agent Manager's certificate for this one yet.</p>
|
|
84
|
+
<p>Open it, accept the warning the same way you did for AI Agent Manager (Safari: Show Details → visit this website), then come back here. You only do this once per site; it keeps its port.</p>
|
|
85
|
+
<div><a id="browser-cert-open" class="button primary small" target="_blank" rel="noopener">Open and accept</a> <button type="button" id="browser-cert-retry" class="small">Done, load it</button></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div id="browser-start" class="browser-start" hidden>
|
|
88
|
+
<p>Open a page as this machine sees it: the agent's dev server, a site on its network or VPN, or any address. It works from your phone or laptop too: AI Agent Manager relays it over its own secure connection, for signed-in devices only.</p>
|
|
89
|
+
<div id="browser-suggest"></div>
|
|
90
|
+
</div>
|
|
91
|
+
<div id="browser-frames" class="browser-frames"></div>
|
|
92
|
+
<div id="browser-live" class="browser-live" hidden>
|
|
93
|
+
<img id="browser-live-img" alt="" draggable="false">
|
|
94
|
+
<textarea id="browser-live-keys" class="browser-live-keys" autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" aria-label="Type into the page"></textarea>
|
|
95
|
+
<div id="browser-live-msg" class="browser-live-msg" hidden></div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
<div id="term-drop" class="term-drop" hidden>Drop files to attach</div>
|
|
99
|
+
<div class="keybar" id="keybar" aria-label="Terminal keys">
|
|
100
|
+
<button data-key="esc">Esc</button>
|
|
101
|
+
<button data-key="tab">Tab</button>
|
|
102
|
+
<button data-key="stab" title="Shift+Tab: cycle permission mode">⇧Tab</button>
|
|
103
|
+
<button data-key="up">↑</button>
|
|
104
|
+
<button data-key="down">↓</button>
|
|
105
|
+
<button data-key="left">←</button>
|
|
106
|
+
<button data-key="right">→</button>
|
|
107
|
+
<button data-key="enter">⏎</button>
|
|
108
|
+
<button data-key="ctrlc">^C</button>
|
|
109
|
+
<button data-key="1">1</button>
|
|
110
|
+
<button data-key="2">2</button>
|
|
111
|
+
<button data-key="3">3</button>
|
|
112
|
+
<button data-key="4">4</button>
|
|
113
|
+
</div>
|
|
114
|
+
<form class="compose" id="compose" autocomplete="off">
|
|
115
|
+
<textarea id="compose-text" rows="1" placeholder="Reply to the agent…" enterkeyhint="send"></textarea>
|
|
116
|
+
<button class="primary">Send</button>
|
|
117
|
+
</form>
|
|
118
|
+
<div id="term-overlay" class="term-overlay" hidden>
|
|
119
|
+
<p id="term-overlay-msg">This agent's session is closed.</p>
|
|
120
|
+
<button id="term-resume" class="primary">Resume session</button>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</section>
|
|
124
|
+
</main>
|
|
125
|
+
|
|
126
|
+
<dialog id="new-dialog">
|
|
127
|
+
<form id="new-form" method="dialog">
|
|
128
|
+
<h2>New agents</h2>
|
|
129
|
+
<label>
|
|
130
|
+
Intents <span class="hint">one per line; each gets its own agent</span>
|
|
131
|
+
<textarea name="intents" rows="6" required placeholder="Add a dark mode toggle that remembers the user's choice Make search results show up as you type Find out why the dashboard takes 5 seconds to load and speed it up Add a one-click CSV export to the reports page"></textarea>
|
|
132
|
+
</label>
|
|
133
|
+
<div class="row">
|
|
134
|
+
<label>
|
|
135
|
+
Git repository URL
|
|
136
|
+
<input name="repo" placeholder="https://github.com/org/repo.git" />
|
|
137
|
+
</label>
|
|
138
|
+
<label>
|
|
139
|
+
or working folder
|
|
140
|
+
<input name="dir" placeholder="~/projects/my-repo" />
|
|
141
|
+
</label>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="row">
|
|
144
|
+
<label>
|
|
145
|
+
Permission mode
|
|
146
|
+
<select name="permissionMode">
|
|
147
|
+
<option value="">Default</option>
|
|
148
|
+
<option value="acceptEdits">Accept edits</option>
|
|
149
|
+
<option value="plan">Plan</option>
|
|
150
|
+
<option value="auto">Auto</option>
|
|
151
|
+
<option value="bypassPermissions">Bypass permissions</option>
|
|
152
|
+
</select>
|
|
153
|
+
</label>
|
|
154
|
+
<label>
|
|
155
|
+
Model <span class="hint">optional</span>
|
|
156
|
+
<input name="model" placeholder="e.g. opus" />
|
|
157
|
+
</label>
|
|
158
|
+
<label id="engine-field" hidden>
|
|
159
|
+
Engine
|
|
160
|
+
<select name="engine"><option value="">Claude Code</option></select>
|
|
161
|
+
</label>
|
|
162
|
+
</div>
|
|
163
|
+
<label>
|
|
164
|
+
Project <span class="hint">optional; a shortcut like <code>cc</code> fills in its repo, or name a new project</span>
|
|
165
|
+
<input name="project" placeholder="shortcut or name (default: from the repo)" list="project-options" autocomplete="off" />
|
|
166
|
+
<datalist id="project-options"></datalist>
|
|
167
|
+
</label>
|
|
168
|
+
<label>
|
|
169
|
+
Base branch <span class="hint">optional; each agent branches from this. Default: the repo's default branch, freshly fetched</span>
|
|
170
|
+
<input name="base" placeholder="main" />
|
|
171
|
+
</label>
|
|
172
|
+
<label class="check">
|
|
173
|
+
<input type="checkbox" name="worktree" checked />
|
|
174
|
+
Give each agent its own git worktree and branch <span class="hint">(for a git folder; always on when cloning a repo URL)</span>
|
|
175
|
+
</label>
|
|
176
|
+
<label class="check">
|
|
177
|
+
<input type="checkbox" name="plan" checked />
|
|
178
|
+
Plan with Claude while the repo clones <span class="hint">(repo URLs only; the session moves into the repo when it's ready)</span>
|
|
179
|
+
</label>
|
|
180
|
+
<label class="check">
|
|
181
|
+
<input type="checkbox" name="planReview" />
|
|
182
|
+
Review the implementation plan first <span class="hint">(the agent writes a plan and waits for your approval before changing anything)</span>
|
|
183
|
+
</label>
|
|
184
|
+
<div class="row when">
|
|
185
|
+
<label class="check"><input type="radio" name="when" value="now" checked /> Start now</label>
|
|
186
|
+
<label class="check"><input type="radio" name="when" value="backlog" /> Queue in backlog</label>
|
|
187
|
+
<label class="check" title="Several agents try the same intent; compare and keep the best"><input type="radio" name="when" value="race" /> Race variants</label>
|
|
188
|
+
<label class="check">Priority
|
|
189
|
+
<select name="priority" aria-label="Priority">
|
|
190
|
+
<option value="0">P0 urgent</option>
|
|
191
|
+
<option value="1">P1 high</option>
|
|
192
|
+
<option value="2" selected>P2 normal</option>
|
|
193
|
+
<option value="3">P3 low</option>
|
|
194
|
+
</select>
|
|
195
|
+
</label>
|
|
196
|
+
</div>
|
|
197
|
+
<div class="race-only" hidden>
|
|
198
|
+
<label>
|
|
199
|
+
Variants <span class="hint">one per line: <code>model</code>, <code>model | approach</code>, or <code>| approach</code>. At least two.</span>
|
|
200
|
+
<textarea name="variants" rows="3" placeholder="opus sonnet | Keep the change as small as possible"></textarea>
|
|
201
|
+
</label>
|
|
202
|
+
<label>
|
|
203
|
+
Test command <span class="hint">optional; run in each attempt's worktree to compare</span>
|
|
204
|
+
<input name="testCommand" placeholder="npm test" />
|
|
205
|
+
</label>
|
|
206
|
+
</div>
|
|
207
|
+
<label class="check now-only">
|
|
208
|
+
<input type="checkbox" name="start" checked />
|
|
209
|
+
Launch immediately
|
|
210
|
+
</label>
|
|
211
|
+
<p id="new-error" class="error" hidden></p>
|
|
212
|
+
<div class="dialog-actions">
|
|
213
|
+
<button type="button" id="new-cancel" class="ghost">Cancel</button>
|
|
214
|
+
<button type="submit" class="primary">Create agents</button>
|
|
215
|
+
</div>
|
|
216
|
+
</form>
|
|
217
|
+
</dialog>
|
|
218
|
+
|
|
219
|
+
<dialog id="ask-dialog">
|
|
220
|
+
<form id="ask-form" method="dialog">
|
|
221
|
+
<h2>Ask Claude</h2>
|
|
222
|
+
<p class="hint">A general session with no repo or folder. It is tracked and resumable like any other agent.</p>
|
|
223
|
+
<label>
|
|
224
|
+
Question <span class="hint">optional; you can also just type in the terminal</span>
|
|
225
|
+
<textarea name="question" rows="4" placeholder="How do I tune GC for a JVM with a 32 GB heap?"></textarea>
|
|
226
|
+
</label>
|
|
227
|
+
<label>
|
|
228
|
+
Name <span class="hint">optional</span>
|
|
229
|
+
<input name="name" placeholder="jvm-gc-questions" />
|
|
230
|
+
</label>
|
|
231
|
+
<p id="ask-error" class="error" hidden></p>
|
|
232
|
+
<div class="dialog-actions">
|
|
233
|
+
<button type="button" id="ask-cancel" class="ghost">Cancel</button>
|
|
234
|
+
<button type="submit" class="primary">Start session</button>
|
|
235
|
+
</div>
|
|
236
|
+
</form>
|
|
237
|
+
</dialog>
|
|
238
|
+
|
|
239
|
+
<dialog id="login-dialog">
|
|
240
|
+
<form id="login-form" method="dialog">
|
|
241
|
+
<h2>Sign in</h2>
|
|
242
|
+
<p class="hint">Scan the QR code under <b>Remote access</b> on your computer, or paste the access token (or the whole sign-in link) here.</p>
|
|
243
|
+
<input name="token" placeholder="Access token" autocomplete="off" autocapitalize="off" spellcheck="false" required />
|
|
244
|
+
<p id="login-error" class="error" hidden></p>
|
|
245
|
+
<div class="dialog-actions"><button class="primary">Sign in</button></div>
|
|
246
|
+
</form>
|
|
247
|
+
</dialog>
|
|
248
|
+
|
|
249
|
+
<dialog id="doc-dialog" class="doc-dialog">
|
|
250
|
+
<div class="doc-head">
|
|
251
|
+
<h2 id="doc-title"></h2>
|
|
252
|
+
<span class="spacer"></span>
|
|
253
|
+
<button type="button" id="doc-bg" class="small" hidden title="Close this and keep writing; you'll be told when it's ready">Continue in background</button>
|
|
254
|
+
<button type="button" id="doc-regen" class="small" title="Write it again from the agent's latest work">Regenerate</button>
|
|
255
|
+
<button type="button" id="doc-copy" class="small" title="Copy as Markdown">Copy Markdown</button>
|
|
256
|
+
<button type="button" id="doc-download" class="small">Download .md</button>
|
|
257
|
+
<button type="button" id="doc-print" class="small primary" title="Open a print-ready page (Save as PDF)">Print / PDF</button>
|
|
258
|
+
<button type="button" id="doc-close" class="small ghost">Close</button>
|
|
259
|
+
</div>
|
|
260
|
+
<p id="doc-meta" class="hint"></p>
|
|
261
|
+
<article id="doc-body" class="md doc-body"></article>
|
|
262
|
+
<div id="doc-foot" class="doc-foot" hidden></div>
|
|
263
|
+
</dialog>
|
|
264
|
+
|
|
265
|
+
<dialog id="import-dialog" class="doc-dialog">
|
|
266
|
+
<div class="doc-head">
|
|
267
|
+
<h2>Continue a Claude session</h2>
|
|
268
|
+
<span class="spacer"></span>
|
|
269
|
+
<select id="import-days" class="small" title="How far back">
|
|
270
|
+
<option value="7">Last 7 days</option>
|
|
271
|
+
<option value="30" selected>Last 30 days</option>
|
|
272
|
+
<option value="90">Last 90 days</option>
|
|
273
|
+
</select>
|
|
274
|
+
<button type="button" id="import-close" class="small ghost">Close</button>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="import-body">
|
|
277
|
+
<p class="hint">Sessions you started with <code>claude</code> in a terminal on this machine. Each one you pick becomes an agent in the same folder that continues the same conversation, with the brief, inbox, PRs and usage tracked here.</p>
|
|
278
|
+
<input id="import-filter" placeholder="Filter by folder, title or what you asked" autocomplete="off">
|
|
279
|
+
<div id="import-list" class="import-list"></div>
|
|
280
|
+
</div>
|
|
281
|
+
<div class="import-foot">
|
|
282
|
+
<label class="check"><input type="checkbox" id="import-start" checked> Start now</label>
|
|
283
|
+
<span class="spacer"></span>
|
|
284
|
+
<button type="button" id="import-go" class="primary" disabled>Continue</button>
|
|
285
|
+
</div>
|
|
286
|
+
</dialog>
|
|
287
|
+
|
|
288
|
+
<dialog id="race-dialog" class="doc-dialog">
|
|
289
|
+
<div class="doc-head">
|
|
290
|
+
<h2 id="race-title">Race</h2>
|
|
291
|
+
<span class="spacer"></span>
|
|
292
|
+
<button type="button" id="race-delete" class="small ghost" title="Forget this race (its agents stay)">Forget race</button>
|
|
293
|
+
<button type="button" id="race-close" class="small ghost">Close</button>
|
|
294
|
+
</div>
|
|
295
|
+
<div id="race-body" class="race-body"></div>
|
|
296
|
+
</dialog>
|
|
297
|
+
|
|
298
|
+
<dialog id="alerts-dialog">
|
|
299
|
+
<form id="alerts-form" method="dialog" class="alerts-body">
|
|
300
|
+
<h2>Slack alerts</h2>
|
|
301
|
+
<p class="hint">Get a Slack message when an agent needs you. Use a <b>Workflow Builder</b> webhook (<code>…/triggers/…</code>, with one Text variable named <code>text</code>), an app's <b>incoming webhook</b> (<code>…/services/…</code>), or a <b>bot token</b> and channel. Stored only on this computer.</p>
|
|
302
|
+
<label>Webhook URL <input name="webhookUrl" type="password" autocomplete="off" placeholder="https://hooks.slack.com/services/…" /></label>
|
|
303
|
+
<div class="row">
|
|
304
|
+
<label>or bot token <input name="botToken" type="password" autocomplete="off" placeholder="xoxb-…" /></label>
|
|
305
|
+
<label>channel <input name="channel" placeholder="#agents" /></label>
|
|
306
|
+
</div>
|
|
307
|
+
<p class="hint" id="alerts-current"></p>
|
|
308
|
+
<fieldset>
|
|
309
|
+
<legend>Alert when an agent…</legend>
|
|
310
|
+
<label class="check"><input type="checkbox" name="ev_needsInput" /> needs input (a prompt or question is unanswered) after <input name="needsInputDelaySec" type="number" min="0" class="num" />s</label>
|
|
311
|
+
<label class="check"><input type="checkbox" name="ev_review" /> finishes a backlog item (ready for review)</label>
|
|
312
|
+
<label class="check"><input type="checkbox" name="ev_error" /> fails (setup or launch error)</label>
|
|
313
|
+
<label class="check"><input type="checkbox" name="ev_blocked" /> reports it is blocked</label>
|
|
314
|
+
<label class="check"><input type="checkbox" name="ev_stuck" /> seems stuck (same failure, undoing its edits, no progress)</label>
|
|
315
|
+
<label class="check"><input type="checkbox" name="ev_conflict" /> changes the same files as another agent</label>
|
|
316
|
+
<label class="check"><input type="checkbox" name="ev_question" /> asks a question in the inbox</label>
|
|
317
|
+
<label class="check"><input type="checkbox" name="ev_waiting" /> finished its turn and is idle after <input name="waitingDelaySec" type="number" min="0" class="num" />s</label>
|
|
318
|
+
<label class="check"><input type="checkbox" name="skipWhenWatching" /> not while I have its terminal open</label>
|
|
319
|
+
<label class="check"><input type="checkbox" name="includeIntent" /> include the intent text in the message</label>
|
|
320
|
+
<label class="check"><input type="checkbox" name="enabled" /> <b>Alerts on</b></label>
|
|
321
|
+
</fieldset>
|
|
322
|
+
<div id="alerts-recent" class="hint"></div>
|
|
323
|
+
<p id="alerts-error" class="error" hidden></p>
|
|
324
|
+
<div class="dialog-actions">
|
|
325
|
+
<button type="button" id="alerts-test">Send test</button>
|
|
326
|
+
<span class="spacer"></span>
|
|
327
|
+
<button type="button" id="alerts-close" class="ghost">Close</button>
|
|
328
|
+
<button class="primary">Save</button>
|
|
329
|
+
</div>
|
|
330
|
+
</form>
|
|
331
|
+
</dialog>
|
|
332
|
+
|
|
333
|
+
<dialog id="remote-dialog">
|
|
334
|
+
<div class="remote-body">
|
|
335
|
+
<h2>Remote access</h2>
|
|
336
|
+
<div id="remote-content">Loading…</div>
|
|
337
|
+
<div class="dialog-actions"><button type="button" id="remote-close" class="ghost">Close</button></div>
|
|
338
|
+
</div>
|
|
339
|
+
</dialog>
|
|
340
|
+
|
|
341
|
+
<dialog id="about-dialog" class="about-dialog">
|
|
342
|
+
<h2>AI Agent Manager</h2>
|
|
343
|
+
<p class="hint">Run and track background coding agents, one per intent.</p>
|
|
344
|
+
<dl id="about-list" class="about-list"></dl>
|
|
345
|
+
<p id="about-update" class="hint" hidden></p>
|
|
346
|
+
<div class="dialog-actions">
|
|
347
|
+
<button type="button" id="about-check" class="ghost" title="Asks the npm registry for the newest version">Check for updates</button>
|
|
348
|
+
<button type="button" id="about-close" class="primary">Close</button>
|
|
349
|
+
</div>
|
|
350
|
+
</dialog>
|
|
351
|
+
|
|
352
|
+
<script type="module" src="/app.js"></script>
|
|
353
|
+
</body>
|
|
354
|
+
</html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Document</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { color-scheme: light; }
|
|
9
|
+
body { margin: 0; background: #f4f5f7; color: #1c2330; font: 15px/1.6 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
|
10
|
+
.bar { position: sticky; top: 0; display: flex; gap: 8px; align-items: center; padding: 10px 16px; background: #fff; border-bottom: 1px solid #dde1e7; }
|
|
11
|
+
.bar .grow { flex: 1; color: #667085; font-size: 13px; }
|
|
12
|
+
.bar button { font: inherit; padding: 6px 12px; border-radius: 6px; border: 1px solid #3b5bdb; background: #3b5bdb; color: #fff; cursor: pointer; }
|
|
13
|
+
main { max-width: 860px; margin: 24px auto; padding: 32px 40px; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, .08); }
|
|
14
|
+
h1 { font-size: 26px; margin: 0 0 14px; }
|
|
15
|
+
h2 { font-size: 19px; margin: 26px 0 8px; padding-bottom: 4px; border-bottom: 1px solid #e3e6eb; }
|
|
16
|
+
code { background: #f0f2f5; padding: 0 4px; border-radius: 4px; font-size: 13px; }
|
|
17
|
+
pre { background: #f0f2f5; padding: 10px; border-radius: 6px; overflow-x: auto; }
|
|
18
|
+
table { border-collapse: collapse; } th, td { border: 1px solid #dde1e7; padding: 4px 8px; text-align: left; }
|
|
19
|
+
.diagram { margin: 10px 0 16px; text-align: center; } .diagram svg { max-width: 100%; height: auto; }
|
|
20
|
+
.meta { color: #667085; font-size: 12.5px; margin-top: 28px; border-top: 1px solid #e3e6eb; padding-top: 8px; }
|
|
21
|
+
.error { color: #d64545; }
|
|
22
|
+
@media print {
|
|
23
|
+
body { background: #fff; } .bar { display: none; }
|
|
24
|
+
main { box-shadow: none; margin: 0; padding: 0; max-width: none; }
|
|
25
|
+
h2 { break-after: avoid; } .diagram, pre, table { break-inside: avoid; }
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
</head>
|
|
29
|
+
<body>
|
|
30
|
+
<div class="bar"><span class="grow" id="status">Loading…</span><button id="print">Print / Save as PDF</button></div>
|
|
31
|
+
<main id="doc"></main>
|
|
32
|
+
<script type="module" src="/share.js"></script>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
package/public/share.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Print-ready view of one agent document: /share.html#<agent id>/<analysis|design|flow|proposal>
|
|
2
|
+
import { marked } from '/vendor/marked/marked.esm.js';
|
|
3
|
+
import DOMPurify from '/vendor/dompurify/purify.es.mjs';
|
|
4
|
+
|
|
5
|
+
const $ = (s) => document.querySelector(s);
|
|
6
|
+
const esc = (s) => String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]);
|
|
7
|
+
const [agentId, kind] = location.hash.slice(1).split('/');
|
|
8
|
+
$('#print').onclick = () => window.print();
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}`, { credentials: 'same-origin' });
|
|
12
|
+
if (!res.ok) throw new Error(res.status === 401 ? 'Sign in to AI Agent Manager first, then reopen this page.' : `HTTP ${res.status}`);
|
|
13
|
+
const a = await res.json();
|
|
14
|
+
const d = a.docs?.[kind];
|
|
15
|
+
if (!d?.markdown) throw new Error('This document has not been written yet.');
|
|
16
|
+
const blocks = [];
|
|
17
|
+
const text = d.markdown.replace(/```mermaid\s*\n([\s\S]*?)```/g, (_, src) => {
|
|
18
|
+
blocks.push(src.trim());
|
|
19
|
+
return `\n\nMERMAIDBLOCK${blocks.length - 1}\n\n`;
|
|
20
|
+
});
|
|
21
|
+
$('#doc').innerHTML =
|
|
22
|
+
DOMPurify.sanitize(marked.parse(text, { gfm: true })).replace(/<p>MERMAIDBLOCK(\d+)<\/p>/g, (_, i) => `<div class="diagram" data-i="${i}"></div>`) +
|
|
23
|
+
`<p class="meta">${esc(a.name)} · ${esc(a.projectInfo?.name ?? '')} · written ${esc(new Date(d.at).toLocaleString())}</p>`;
|
|
24
|
+
document.title = (d.markdown.match(/^#\s+(.+)$/m)?.[1] ?? `${kind} · ${a.name}`).slice(0, 120);
|
|
25
|
+
if (blocks.length) {
|
|
26
|
+
const mermaid = (await import('/vendor/mermaid/mermaid.esm.min.mjs')).default;
|
|
27
|
+
mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: 'default' });
|
|
28
|
+
for (const el of document.querySelectorAll('.diagram')) {
|
|
29
|
+
try {
|
|
30
|
+
el.innerHTML = (await mermaid.render(`d${el.dataset.i}`, blocks[Number(el.dataset.i)])).svg;
|
|
31
|
+
} catch {
|
|
32
|
+
el.innerHTML = `<pre>${esc(blocks[Number(el.dataset.i)])}</pre>`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
$('#status').textContent = 'Ready to print or save as PDF.';
|
|
37
|
+
}
|
|
38
|
+
main().catch((err) => {
|
|
39
|
+
$('#status').textContent = '';
|
|
40
|
+
$('#doc').innerHTML = `<p class="error">${esc(err.message)}</p>`;
|
|
41
|
+
});
|