@agentproto/apps 0.9.1 → 0.10.0

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/README.md CHANGED
@@ -60,10 +60,10 @@ panels" above), independent of this file and of `~/.agentproto/apps.json`.
60
60
 
61
61
  ## Builtin daemon panels
62
62
 
63
- Five of `@agentproto/runtime`'s daemon-builtin MCP-Apps widgets live here too,
64
- as house-app-quality code — but they are **not** `AppHandle`s (`defineApp`
65
- requires a non-empty `agents` array, and these are pure read-only viewers with
66
- no agent of their own):
63
+ Several of `@agentproto/runtime`'s daemon-builtin MCP-Apps widgets live here
64
+ too, as house-app-quality code — but they are **not** `AppHandle`s
65
+ (`defineApp` requires a non-empty `agents` array, and these are pure
66
+ read-only viewers/actuators with no agent of their own):
67
67
 
68
68
  | Panel | Import | MCP tool id |
69
69
  | --- | --- | --- |
@@ -72,15 +72,17 @@ no agent of their own):
72
72
  | `bureau-sessions` | `@agentproto/apps/bureau-sessions` | `agentproto_bureau_sessions` |
73
73
  | `session-story` | `@agentproto/apps/session-story` | `agentproto_session_story` |
74
74
  | `live-session` | `@agentproto/apps/live-session` | `live_session` |
75
+ | `session-chat` | `@agentproto/apps/session-chat` | `agentproto_session_chat` |
76
+ | `work-board` | `@agentproto/apps/work-board` | `agentproto_work_board` |
75
77
 
76
78
  Each exports a `make<Name>App(ops)` factory producing an `AgnoMcpApp` — the
77
79
  shape `@agentproto/runtime`'s `mcp-apps-adapter.ts` mounts on the daemon's MCP
78
- server. `@agentproto/runtime`'s `builtin-apps.ts` wraps these five with the
79
- daemon's own session registry and mounts them at boot, unconditionally — no
80
- `app_install` step, and they're always listed in `app_catalog` under
81
- `category: "builtin"`. A sixth builtin panel, the terminal, stays in
82
- `@agentproto/runtime` (`terminal-panel-app.ts`) — it needs a live PTY
83
- WebSocket, not a portable tool-call-driven `AgnoMcpApp`.
80
+ server. `@agentproto/runtime`'s `builtin-apps.ts` wraps these with the
81
+ daemon's own session registry (and, for `work-board`, its Task ledger) and
82
+ mounts them at boot, unconditionally — no `app_install` step, and they're
83
+ always listed in `app_catalog` under `category: "builtin"`. One more builtin
84
+ panel, the terminal, stays in `@agentproto/runtime` (`terminal-panel-app.ts`)
85
+ — it needs a live PTY WebSocket, not a portable tool-call-driven `AgnoMcpApp`.
84
86
 
85
87
  ## Generic by design
86
88
 
package/dist/index.d.ts CHANGED
@@ -16,9 +16,10 @@
16
16
  * folder (`code-team/`, `content-team/`) with `agents/` + `workflows/`, and is
17
17
  * re-exported here + as a subpath (`@agentproto/apps/<team>`).
18
18
  *
19
- * This package also carries five daemon-builtin panels (`sessions-panel`,
20
- * `agents-overview`, `bureau-sessions`, `session-story`, `live-session`) —
21
- * @agentproto/runtime's house-app-quality UI widgets. Each ships in two
19
+ * This package also carries the daemon-builtin panels (`sessions-panel`,
20
+ * `agents-overview`, `bureau-sessions`, `session-story`, `live-session`,
21
+ * `session-chat`, `work-board`) — @agentproto/runtime's house-app-quality UI
22
+ * widgets. Each ships in two
22
23
  * forms: a real `AppHandle` (`agents: []`, UI-only — the catalog/emit/
23
24
  * `app_install` path, e.g. `sessionsPanelApp`) AND a separate
24
25
  * `make<Name>App(ops)` factory producing the `AgnoMcpApp` shape
@@ -46,4 +47,8 @@ export { makeSessionStoryPanelApp, sessionStoryApp } from "./session-story/index
46
47
  export type { SessionStoryOps, SessionStoryInput, SessionStoryOutput } from "./session-story/index.js";
47
48
  export { makeLiveSessionApp, liveSessionApp } from "./live-session/index.js";
48
49
  export type { LiveSessionOps, LiveSessionInput, LiveSessionOutput } from "./live-session/index.js";
50
+ export { makeSessionChatApp, sessionChatApp, sessionChatAppUrl, SESSION_CHAT_APP_ID, SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml, } from "./session-chat/index.js";
51
+ export type { SessionChatOps, SessionChatInput, SessionChatOutput, } from "./session-chat/index.js";
52
+ export { makeWorkBoardApp, workBoardApp } from "./work-board/index.js";
53
+ export type { WorkBoardOps, WorkBoardInput, WorkBoardOutput } from "./work-board/index.js";
49
54
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAClF,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAChG,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAC9G,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAC9G,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACpF,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AACtG,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC5E,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAClF,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAChG,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAC9G,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAC9G,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACpF,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AACtG,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC5E,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAClG,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACtE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA"}
package/dist/index.mjs CHANGED
@@ -5490,6 +5490,447 @@ var liveSessionApp = defineApp({
5490
5490
  }
5491
5491
  });
5492
5492
 
5493
- export { agentsOverviewApp, bureauSessionsApp, codeTeam, contentTeam, liveSessionApp, mailTriage, makeAgentsOverviewApp, makeBureauSessionsApp, makeLiveSessionApp, makeSessionStoryPanelApp, makeSessionsPanelApp, mediaViewer, opsPanel, panelBridgeScript, sessionStoryApp, sessionViewer, sessionsPanelApp };
5493
+ // src/session-chat/panel.ts
5494
+ function escapeAttr(text) {
5495
+ return text.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
5496
+ }
5497
+ function sessionChatEmbedHtml(initData) {
5498
+ const url = initData.url;
5499
+ const link = url != null ? `<a href="${escapeAttr(url)}" target="_blank" rel="noreferrer">open in a tab</a>` : "app not installed";
5500
+ const iframe = url != null ? `<iframe id="chat" title="Session Chat" src="${escapeAttr(url)}"></iframe>` : "";
5501
+ return `<!DOCTYPE html>
5502
+ <html lang="en">
5503
+ <head>
5504
+ <meta charset="UTF-8">
5505
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5506
+ <title>Session Chat</title>
5507
+ <style>
5508
+ *{box-sizing:border-box;margin:0;padding:0}
5509
+ html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3;overflow:hidden}
5510
+ #bar{padding:6px 12px;font-size:12px;color:#8b949e;background:#161b22;border-bottom:1px solid #30363d}
5511
+ #bar a{color:#58a6ff}
5512
+ #chat{border:0;display:block;width:100%;height:calc(100% - 29px)}
5513
+ </style>
5514
+ </head>
5515
+ <body>
5516
+ <div id="bar">Session Chat &#183; ${link}</div>
5517
+ ${iframe}
5518
+ </body>
5519
+ </html>`;
5520
+ }
5521
+ var SESSION_CHAT_FALLBACK_HTML = `<!DOCTYPE html>
5522
+ <html lang="en">
5523
+ <head>
5524
+ <meta charset="UTF-8">
5525
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5526
+ <title>Session Chat \u2014 not installed</title>
5527
+ <style>
5528
+ *{box-sizing:border-box;margin:0;padding:0}
5529
+ html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}
5530
+ #wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}
5531
+ h1{font-size:18px;margin-bottom:12px}
5532
+ code{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}
5533
+ p{margin:8px 0;color:#8b949e;font-size:13px}
5534
+ </style>
5535
+ </head>
5536
+ <body>
5537
+ <div id="wrap">
5538
+ <h1>Session Chat is not installed</h1>
5539
+ <p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app &#8212;
5540
+ it does not bundle the chat UI itself.</p>
5541
+ <p>To use it, install the app into this daemon:</p>
5542
+ <p><code>agentproto app install @agentik/session-chat</code></p>
5543
+ <p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a
5544
+ <code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that
5545
+ session.</p>
5546
+ </div>
5547
+ </body>
5548
+ </html>`;
5549
+
5550
+ // src/session-chat/index.ts
5551
+ var SESSION_CHAT_APP_ID = "@agentik/session-chat";
5552
+ var sessionChatInputSchema = z.object({
5553
+ sessionId: z.string().optional().describe(
5554
+ "Deep-link the chat to an existing session by id (e.g. `sess_xxx`). Omit to open the app with its session picker."
5555
+ )
5556
+ });
5557
+ function sessionChatAppUrl(httpBaseUrl, sessionId) {
5558
+ const base = `${httpBaseUrl.replace(/\/+$/, "")}/apps/${SESSION_CHAT_APP_ID}/ui`;
5559
+ const params = new URLSearchParams();
5560
+ if (sessionId) params.set("session", sessionId);
5561
+ params.set("embed", "1");
5562
+ return `${base}?${params.toString()}`;
5563
+ }
5564
+ function frameOrigin(httpBaseUrl) {
5565
+ return new URL(httpBaseUrl).origin;
5566
+ }
5567
+ function makeSessionChatApp(ops) {
5568
+ const installed = ops.isSessionChatInstalled?.() ?? false;
5569
+ return {
5570
+ id: "agentproto_session_chat",
5571
+ title: "Session Chat",
5572
+ description: "Open the Session Chat app \u2014 a chat-thread view of any agentproto daemon session: full transcript replay, live follow-over SSE, and a composer that sends prompts into the same session. Requires the `@agentik/session-chat` app to be installed; without it the panel shows install instructions. Pass `sessionId` to deep-link straight into a known session.",
5573
+ inputSchema: sessionChatInputSchema,
5574
+ execute: async (input) => ({
5575
+ installed,
5576
+ url: installed ? sessionChatAppUrl(ops.httpBaseUrl, input.sessionId) : null
5577
+ }),
5578
+ html: (initData) => sessionChatEmbedHtml(initData),
5579
+ csp: { frameDomains: [frameOrigin(ops.httpBaseUrl)] }
5580
+ };
5581
+ }
5582
+ var sessionChatApp = defineApp({
5583
+ id: "@agentproto/session-chat-widget",
5584
+ name: "Session Chat",
5585
+ description: "Open the Session Chat app \u2014 a chat-thread view of any agentproto daemon session, deep-linked by sessionId. A thin builtin launcher for the installed @agentik/session-chat app.",
5586
+ agents: [],
5587
+ ui: {
5588
+ html: SESSION_CHAT_FALLBACK_HTML,
5589
+ title: "Session Chat",
5590
+ tools: ["session_list", "agent_start", "adapter_list", "conversation_read"]
5591
+ }
5592
+ });
5593
+
5594
+ // src/work-board/panel.ts
5595
+ var WORK_BOARD_HTML = `<!DOCTYPE html>
5596
+ <html lang="en">
5597
+ <head>
5598
+ <meta charset="UTF-8">
5599
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5600
+ <title>agentproto work board</title>
5601
+ <style>
5602
+ *{box-sizing:border-box;margin:0;padding:0}
5603
+ :root{
5604
+ --bg:#0d1117;--bg2:#161b22;--bg3:#21262d;--border:#30363d;
5605
+ --text:#e6edf3;--text2:#8b949e;
5606
+ --green:#3fb950;--yellow:#d29922;--red:#f85149;--blue:#58a6ff;--purple:#bc8cff;
5607
+ }
5608
+ html,body{height:100%;font-family:Menlo,Monaco,'Courier New',monospace;font-size:13px;background:var(--bg);color:var(--text);overflow:hidden}
5609
+ #app{display:flex;flex-direction:column;height:100%}
5610
+ #toolbar{padding:8px 12px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;background:var(--bg2);flex-shrink:0}
5611
+ #board-label{font-size:11px;color:var(--text2)}
5612
+ #board-id{font-weight:600;color:var(--text);font-size:12px}
5613
+ #board-input{background:var(--bg3);border:1px solid var(--border);color:var(--text);padding:4px 8px;border-radius:4px;font-size:12px;font-family:inherit;width:220px}
5614
+ .tbtn{background:var(--bg3);border:1px solid var(--border);color:var(--text);padding:4px 10px;border-radius:4px;cursor:pointer;font-size:12px;font-family:inherit}
5615
+ .tbtn:hover{background:var(--border)}
5616
+ #new-title{flex:1;min-width:120px;background:var(--bg3);border:1px solid var(--border);color:var(--text);padding:4px 8px;border-radius:4px;font-size:12px;font-family:inherit}
5617
+ #columns{flex:1;display:flex;overflow-x:auto;overflow-y:hidden}
5618
+ .col{width:260px;min-width:220px;flex-shrink:0;display:flex;flex-direction:column;border-right:1px solid var(--border)}
5619
+ .col-hdr{padding:8px 10px;border-bottom:1px solid var(--border);background:var(--bg2);font-size:11px;font-weight:600;color:var(--text2);text-transform:uppercase;letter-spacing:.05em;display:flex;justify-content:space-between}
5620
+ .col-body{flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:8px}
5621
+ .card{background:var(--bg2);border:1px solid var(--border);border-radius:6px;padding:8px 10px}
5622
+ .c-title{font-size:12px;font-weight:500;margin-bottom:4px;word-break:break-word}
5623
+ .c-id{font-size:10px;color:var(--text2);margin-bottom:6px}
5624
+ .c-row{display:flex;flex-wrap:wrap;gap:4px;align-items:center;margin-bottom:6px}
5625
+ .tag{display:inline-block;padding:1px 6px;border-radius:10px;font-size:10px;font-weight:600;white-space:nowrap}
5626
+ .t-unclaimed{background:rgba(139,148,158,.15);color:var(--text2);border:1px dashed var(--text2)}
5627
+ .t-owner{background:rgba(88,166,255,.15);color:var(--blue)}
5628
+ .t-gate{background:rgba(63,185,80,.18);color:var(--green)}
5629
+ .t-self{background:rgba(210,153,34,.18);color:var(--yellow)}
5630
+ .t-human{background:rgba(88,166,255,.18);color:var(--blue)}
5631
+ .t-gated{background:rgba(139,148,158,.12);color:var(--text2)}
5632
+ .t-cancelled{background:rgba(139,148,158,.12);color:var(--text2)}
5633
+ .c-err{font-size:10px;color:var(--red);margin-bottom:6px;word-break:break-word}
5634
+ .c-actions{display:flex;flex-wrap:wrap;gap:4px}
5635
+ .abtn{background:var(--bg3);border:1px solid var(--border);color:var(--text);padding:3px 8px;border-radius:4px;cursor:pointer;font-size:11px;font-family:inherit}
5636
+ .abtn:hover{background:var(--border)}
5637
+ .abtn.danger{border-color:var(--red);color:var(--red)}
5638
+ .abtn.primary{border-color:var(--green);color:var(--green)}
5639
+ #statusbar{padding:4px 12px;font-size:11px;color:var(--text2);border-top:1px solid var(--border);background:var(--bg2);flex-shrink:0}
5640
+ .empty{padding:16px 8px;color:var(--text2);font-size:11px;text-align:center}
5641
+ </style>
5642
+ </head>
5643
+ <body>
5644
+ <div id="app">
5645
+ <div id="toolbar">
5646
+ <span id="board-label">Board:</span>
5647
+ <span id="board-id">\u2014</span>
5648
+ <input id="board-input" type="text" placeholder="tree:&lt;sessionId&gt; or ws:&lt;slug&gt;">
5649
+ <button class="tbtn" id="go-btn">Go</button>
5650
+ <button class="tbtn" id="refresh-btn" title="Refresh">&#8635;</button>
5651
+ <input id="new-title" type="text" placeholder="New task title&#8230;">
5652
+ <button class="tbtn" id="add-btn">+ Add</button>
5653
+ </div>
5654
+ <div id="columns"></div>
5655
+ <div id="statusbar">Connecting to bridge&#8230;</div>
5656
+ </div>
5657
+ <script>
5658
+ ${panelBridgeScript("agentproto-work-board-panel")}
5659
+
5660
+ // ============================================================
5661
+ // State
5662
+ // ============================================================
5663
+
5664
+ var COLUMNS = [
5665
+ {key: 'pending', label: 'Pending'},
5666
+ {key: 'in_progress', label: 'In Progress'},
5667
+ {key: 'done', label: 'Done'},
5668
+ {key: 'failed', label: 'Failed'}
5669
+ ];
5670
+
5671
+ var boardId = null;
5672
+ var tasks = [];
5673
+ var pollTimer = null;
5674
+ var pollActive = false;
5675
+
5676
+ function setStatus(msg) {
5677
+ document.getElementById('statusbar').textContent = msg;
5678
+ }
5679
+
5680
+ function esc(s) {
5681
+ return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
5682
+ }
5683
+
5684
+ // A cancelled task folds into the Failed column, tagged distinctly \u2014 v1
5685
+ // treats both as terminal scrap, and a fifth column for a rarely-used
5686
+ // status isn't worth the width.
5687
+ function columnOf(status) {
5688
+ if (status === 'cancelled') return 'failed';
5689
+ return status;
5690
+ }
5691
+
5692
+ // ============================================================
5693
+ // Verification tell \u2014 never render an unverified done as gate-passed.
5694
+ // ============================================================
5695
+
5696
+ function verificationTag(t) {
5697
+ var v = t.verification;
5698
+ if (v) {
5699
+ if (v.kind === 'gate') return '<span class="tag t-gate">&#10003; gate</span>';
5700
+ if (v.kind === 'self-report') return '<span class="tag t-self">self-report</span>';
5701
+ if (v.kind === 'human') return '<span class="tag t-human">human</span>';
5702
+ }
5703
+ if (t.status === 'in_progress' && t.verify) {
5704
+ return '<span class="tag t-gated">gated</span>';
5705
+ }
5706
+ return '';
5707
+ }
5708
+
5709
+ function ownerTag(t) {
5710
+ if (!t.owner) return '<span class="tag t-unclaimed">Unclaimed</span>';
5711
+ return '<span class="tag t-owner">' + esc(t.owner) + '</span>';
5712
+ }
5713
+
5714
+ // ============================================================
5715
+ // Card actions \u2014 explicit status moves, no drag-and-drop (read-only-safe
5716
+ // first: see module docblock).
5717
+ // ============================================================
5718
+
5719
+ function actionsFor(t) {
5720
+ var a = [];
5721
+ if (t.status === 'pending') {
5722
+ if (!t.owner) a.push({label: 'Claim', action: 'claim', cls: 'primary'});
5723
+ else a.push({label: 'Start', action: 'start', cls: 'primary'});
5724
+ a.push({label: 'Cancel', action: 'cancel', cls: 'danger'});
5725
+ } else if (t.status === 'in_progress') {
5726
+ a.push({label: 'Done', action: 'done', cls: 'primary'});
5727
+ a.push({label: 'Fail', action: 'fail', cls: 'danger'});
5728
+ a.push({label: 'Release', action: 'release', cls: ''});
5729
+ a.push({label: 'Cancel', action: 'cancel', cls: 'danger'});
5730
+ } else if (t.status === 'done') {
5731
+ a.push({label: 'Reopen', action: 'reopen', cls: ''});
5732
+ }
5733
+ return a;
5734
+ }
5735
+
5736
+ function applyAction(taskId, action) {
5737
+ var t = null;
5738
+ for (var i = 0; i < tasks.length; i++) {
5739
+ if (tasks[i].taskId === taskId) { t = tasks[i]; break; }
5740
+ }
5741
+ if (!t) return;
5742
+ var p;
5743
+ if (action === 'claim') {
5744
+ p = callTool('task_claim', {taskId: t.taskId, rev: t.rev});
5745
+ } else if (action === 'start') {
5746
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, status: 'in_progress'});
5747
+ } else if (action === 'done') {
5748
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, status: 'done'});
5749
+ } else if (action === 'fail') {
5750
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, status: 'failed'});
5751
+ } else if (action === 'release') {
5752
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, owner: null});
5753
+ } else if (action === 'cancel') {
5754
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, status: 'cancelled'});
5755
+ } else if (action === 'reopen') {
5756
+ p = callTool('task_update', {taskId: t.taskId, rev: t.rev, status: 'pending'});
5757
+ } else {
5758
+ return;
5759
+ }
5760
+ p.then(function (result) {
5761
+ if (result && result.conflict) {
5762
+ setStatus('Someone else moved "' + t.title + '" first \u2014 refreshed.');
5763
+ } else if (result && result.error) {
5764
+ setStatus('Action failed: ' + result.error);
5765
+ } else {
5766
+ setStatus('Updated "' + t.title + '".');
5767
+ }
5768
+ return loadBoard();
5769
+ }).catch(function (e) {
5770
+ setStatus('Action failed: ' + e.message);
5771
+ });
5772
+ }
5773
+
5774
+ // ============================================================
5775
+ // Render
5776
+ // ============================================================
5777
+
5778
+ function renderCard(t) {
5779
+ var html = '<div class="card" data-taskid="' + esc(t.taskId) + '">';
5780
+ html += '<div class="c-title">' + esc(t.title) + '</div>';
5781
+ html += '<div class="c-id">#' + esc(t.taskId) + '</div>';
5782
+ html += '<div class="c-row">' + ownerTag(t) + verificationTag(t);
5783
+ if (t.status === 'cancelled') html += '<span class="tag t-cancelled">cancelled</span>';
5784
+ html += '</div>';
5785
+ if (t.lastVerifyError) {
5786
+ html += '<div class="c-err">verify failed: ' + esc(t.lastVerifyError) + '</div>';
5787
+ }
5788
+ var actions = actionsFor(t);
5789
+ if (actions.length > 0) {
5790
+ html += '<div class="c-actions">';
5791
+ for (var i = 0; i < actions.length; i++) {
5792
+ var a = actions[i];
5793
+ html += '<button class="abtn ' + a.cls + '" data-taskid="' + esc(t.taskId) + '" data-action="' + a.action + '">' + a.label + '</button>';
5794
+ }
5795
+ html += '</div>';
5796
+ }
5797
+ html += '</div>';
5798
+ return html;
5799
+ }
5800
+
5801
+ function render() {
5802
+ document.getElementById('board-id').textContent = boardId || '\u2014';
5803
+ if (!document.getElementById('board-input').value) {
5804
+ document.getElementById('board-input').value = boardId || '';
5805
+ }
5806
+ var el = document.getElementById('columns');
5807
+ var html = '';
5808
+ for (var c = 0; c < COLUMNS.length; c++) {
5809
+ var col = COLUMNS[c];
5810
+ var rows = tasks.filter(function (t) { return columnOf(t.status) === col.key; });
5811
+ html += '<div class="col"><div class="col-hdr"><span>' + col.label + '</span><span>' + rows.length + '</span></div><div class="col-body">';
5812
+ if (rows.length === 0) {
5813
+ html += '<div class="empty">No tasks</div>';
5814
+ } else {
5815
+ for (var i = 0; i < rows.length; i++) html += renderCard(rows[i]);
5816
+ }
5817
+ html += '</div></div>';
5818
+ }
5819
+ el.innerHTML = html;
5820
+ }
5821
+
5822
+ // ============================================================
5823
+ // Data
5824
+ // ============================================================
5825
+
5826
+ function loadBoard() {
5827
+ var args = {includeClosed: true, full: true};
5828
+ if (boardId) args.boardId = boardId;
5829
+ return callTool('task_list', args).then(function (data) {
5830
+ boardId = data.boardId || boardId;
5831
+ tasks = data.tasks || [];
5832
+ render();
5833
+ setStatus(tasks.length + ' task' + (tasks.length === 1 ? '' : 's') + ' \xB7 ' + new Date().toLocaleTimeString());
5834
+ }).catch(function (e) {
5835
+ setStatus('Error: ' + e.message);
5836
+ });
5837
+ }
5838
+
5839
+ function doPoll() {
5840
+ if (pollActive) return;
5841
+ pollActive = true;
5842
+ loadBoard().then(function () {
5843
+ pollActive = false;
5844
+ pollTimer = setTimeout(doPoll, 4000);
5845
+ }).catch(function () {
5846
+ pollActive = false;
5847
+ pollTimer = setTimeout(doPoll, 4000);
5848
+ });
5849
+ }
5850
+
5851
+ // ============================================================
5852
+ // Toolbar wiring
5853
+ // ============================================================
5854
+
5855
+ document.getElementById('columns').addEventListener('click', function (evt) {
5856
+ var btn = evt.target.closest ? evt.target.closest('button[data-action]') : null;
5857
+ if (!btn) return;
5858
+ applyAction(btn.getAttribute('data-taskid'), btn.getAttribute('data-action'));
5859
+ });
5860
+
5861
+ document.getElementById('refresh-btn').addEventListener('click', function () {
5862
+ loadBoard();
5863
+ });
5864
+
5865
+ document.getElementById('go-btn').addEventListener('click', function () {
5866
+ var v = document.getElementById('board-input').value.trim();
5867
+ if (!v) return;
5868
+ boardId = v;
5869
+ loadBoard();
5870
+ });
5871
+
5872
+ document.getElementById('add-btn').addEventListener('click', function () {
5873
+ var input = document.getElementById('new-title');
5874
+ var title = input.value.trim();
5875
+ if (!title) return;
5876
+ var args = {title: title};
5877
+ if (boardId) args.boardId = boardId;
5878
+ callTool('task_create', args).then(function (result) {
5879
+ if (result && result.error) {
5880
+ setStatus('Create failed: ' + result.error);
5881
+ return;
5882
+ }
5883
+ input.value = '';
5884
+ setStatus('Created "' + title + '".');
5885
+ return loadBoard();
5886
+ }).catch(function (e) {
5887
+ setStatus('Create failed: ' + e.message);
5888
+ });
5889
+ });
5890
+
5891
+ // ============================================================
5892
+ // Boot
5893
+ // ============================================================
5894
+
5895
+ initBridge().then(function () {
5896
+ return loadBoard();
5897
+ }).then(function () {
5898
+ pollTimer = setTimeout(doPoll, 4000);
5899
+ }).catch(function (e) {
5900
+ setStatus('Bridge error: ' + e.message);
5901
+ });
5902
+ </script>
5903
+ </body>
5904
+ </html>`;
5905
+
5906
+ // src/work-board/index.ts
5907
+ var workBoardInputSchema = z.object({
5908
+ boardId: z.string().optional().describe(
5909
+ "Board to open \u2014 `tree:<rootSessionId>` (a supervisor and its executors) or `ws:<slug>` (an operator workspace). Omit \u2192 the caller's default board."
5910
+ )
5911
+ });
5912
+ function makeWorkBoardApp(ops) {
5913
+ return {
5914
+ id: "agentproto_work_board",
5915
+ title: "Work Board",
5916
+ description: "Open the agentproto work board \u2014 a kanban over the daemon's Task ledger (columns: pending/in_progress/done/failed, cancelled folded into failed). Swimlane is the ledger's own board id (`tree:<root>` or `ws:<slug>`). Each card shows its owner (or \"Unclaimed\") and the verification tell \u2014 a gate-passed done reads visually distinct from a self-reported one. Pass `boardId` to open a specific board.",
5917
+ inputSchema: workBoardInputSchema,
5918
+ execute: async (input) => ops.listTasks(input.boardId),
5919
+ html: WORK_BOARD_HTML
5920
+ };
5921
+ }
5922
+ var workBoardApp = defineApp({
5923
+ id: "@agentproto/work-board",
5924
+ name: "Work Board",
5925
+ description: "Open the agentproto work board \u2014 a kanban over the daemon's Task ledger, scoped by board id (`tree:<rootSessionId>` or `ws:<slug>`), with an explicit status action per card.",
5926
+ agents: [],
5927
+ ui: {
5928
+ html: WORK_BOARD_HTML,
5929
+ title: "Work Board",
5930
+ tools: ["task_list", "task_claim", "task_update", "task_create"]
5931
+ }
5932
+ });
5933
+
5934
+ export { SESSION_CHAT_APP_ID, SESSION_CHAT_FALLBACK_HTML, agentsOverviewApp, bureauSessionsApp, codeTeam, contentTeam, liveSessionApp, mailTriage, makeAgentsOverviewApp, makeBureauSessionsApp, makeLiveSessionApp, makeSessionChatApp, makeSessionStoryPanelApp, makeSessionsPanelApp, makeWorkBoardApp, mediaViewer, opsPanel, panelBridgeScript, sessionChatApp, sessionChatAppUrl, sessionChatEmbedHtml, sessionStoryApp, sessionViewer, sessionsPanelApp, workBoardApp };
5494
5935
  //# sourceMappingURL=index.mjs.map
5495
5936
  //# sourceMappingURL=index.mjs.map