@agentproto/apps 0.9.3 → 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 +12 -10
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +442 -1
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-app-types.d.ts +4 -0
- package/dist/mcp-app-types.d.ts.map +1 -1
- package/dist/session-chat/index.d.ts +72 -0
- package/dist/session-chat/index.d.ts.map +1 -0
- package/dist/session-chat/panel.d.ts +28 -0
- package/dist/session-chat/panel.d.ts.map +1 -0
- package/dist/session-chat/panel.mjs +65 -0
- package/dist/session-chat/panel.mjs.map +1 -0
- package/dist/session-chat.mjs +113 -0
- package/dist/session-chat.mjs.map +1 -0
- package/dist/work-board/index.d.ts +67 -0
- package/dist/work-board/index.d.ts.map +1 -0
- package/dist/work-board/panel.d.ts +39 -0
- package/dist/work-board/panel.d.ts.map +1 -0
- package/dist/work-board/panel.mjs +464 -0
- package/dist/work-board/panel.mjs.map +1 -0
- package/dist/work-board.mjs +496 -0
- package/dist/work-board.mjs.map +1 -0
- package/package.json +22 -2
package/dist/mcp-app-types.d.ts
CHANGED
|
@@ -28,6 +28,10 @@ export interface AgnoMcpApp<TInput = unknown, TOutput = unknown> {
|
|
|
28
28
|
csp?: {
|
|
29
29
|
connectDomains?: string[];
|
|
30
30
|
resourceDomains?: string[];
|
|
31
|
+
/** Origins the panel may iframe (`frame-src` under the ext-apps CSP
|
|
32
|
+
* grammar) — e.g. the session-chat widget frames the installed
|
|
33
|
+
* `@agentik/session-chat` app's standalone url on the daemon origin. */
|
|
34
|
+
frameDomains?: string[];
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
37
|
//# sourceMappingURL=mcp-app-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-types.d.ts","sourceRoot":"","sources":["../src/mcp-app-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAG5B,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAC7D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC,CAAA;IAC9C;;;;;;;;2BAQuB;IACvB,GAAG,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"mcp-app-types.d.ts","sourceRoot":"","sources":["../src/mcp-app-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAG5B,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAC7D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC,CAAA;IAC9C;;;;;;;;2BAQuB;IACvB,GAAG,CAAC,EAAE;QACJ,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;QACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;QAC1B;;iFAEyE;QACzE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KACxB,CAAA;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McpApp definition for the session-chat builtin widget — a thin launcher
|
|
3
|
+
* for the installed `@agentik/session-chat` app's UI, exposed as a BUILTIN
|
|
4
|
+
* daemon panel so MCP-Apps clients (and the VS Code appPanel surface) can
|
|
5
|
+
* open the chat from `app_catalog` without installing anything into the
|
|
6
|
+
* MCP surface itself.
|
|
7
|
+
*
|
|
8
|
+
* Uses the AgnoMcpApp contract (a local McpApp-compatible shape that does
|
|
9
|
+
* NOT depend on @agstudio/mcp-apps or Mastra), same as sessions-panel /
|
|
10
|
+
* live-session — the host (@agentproto/runtime) wires this factory's output
|
|
11
|
+
* via `registerMcpApps` from its mcp-apps-adapter.ts at boot time, with the
|
|
12
|
+
* mounted list assembled in runtime's builtin-apps.ts.
|
|
13
|
+
*
|
|
14
|
+
* Serving approach (decided; see the PR description for the tradeoffs):
|
|
15
|
+
* (a) App installed → the tool returns the app's standalone deep-link
|
|
16
|
+
* (`GET /apps/@agentik/session-chat/ui?session=<id>&embed=1`) and the
|
|
17
|
+
* panel HTML is a thin full-viewport iframe of it. No duplicate chat
|
|
18
|
+
* bundle: the UI is the studio-built app, served by the daemon's
|
|
19
|
+
* standalone app host. The daemon relaxes that route's
|
|
20
|
+
* `frame-ancestors 'none'` only when `?embed=1` is present.
|
|
21
|
+
* (b) App NOT installed → the panel HTML is a small readable notice
|
|
22
|
+
* pointing at `agentproto app install`. Never a vendored/reimplemented
|
|
23
|
+
* chat UI.
|
|
24
|
+
*
|
|
25
|
+
* This module also exports `sessionChatApp`, a real `defineApp()`
|
|
26
|
+
* `AppHandle` (`agents: []`, UI-only) — the catalog/emit/`app_install`
|
|
27
|
+
* path. Its `ui.html` is the fallback notice, since `AppUiDefinition.ui.html`
|
|
28
|
+
* is a plain static string and can't know at emit time whether the sibling
|
|
29
|
+
* app is installed; the live-mounted `makeSessionChatApp` below is the one
|
|
30
|
+
* that resolves installed-ness per boot.
|
|
31
|
+
*/
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
import { type AppHandle } from "@agentproto/app-kit";
|
|
34
|
+
import type { AgnoMcpApp } from "../mcp-app-types.js";
|
|
35
|
+
import { SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml } from "./panel.js";
|
|
36
|
+
export { SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml };
|
|
37
|
+
/** The installed studio app this builtin widget is a launcher for. */
|
|
38
|
+
export declare const SESSION_CHAT_APP_ID = "@agentik/session-chat";
|
|
39
|
+
export declare const sessionChatInputSchema: z.ZodObject<{
|
|
40
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
export type SessionChatInput = z.infer<typeof sessionChatInputSchema>;
|
|
43
|
+
export interface SessionChatOutput {
|
|
44
|
+
/** Whether the `@agentik/session-chat` app is installed (with a UI) on
|
|
45
|
+
* the daemon this widget is mounted on. */
|
|
46
|
+
installed: boolean;
|
|
47
|
+
/** The app's standalone deep-link url when installed, else null. */
|
|
48
|
+
url: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface SessionChatOps {
|
|
51
|
+
/** The daemon's own HTTP origin, e.g. "http://127.0.0.1:18790" — the
|
|
52
|
+
* standalone app host the chat UI is served from. */
|
|
53
|
+
httpBaseUrl: string;
|
|
54
|
+
/** Whether the `@agentik/session-chat` app is installed with a `ui`
|
|
55
|
+
* block. The runtime supplies this from its AppRegistry; optional so
|
|
56
|
+
* tests/consumers without a registry can omit it (treated as false). */
|
|
57
|
+
isSessionChatInstalled?: () => boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deep-link into the installed app's standalone UI — the same url shape the
|
|
61
|
+
* VS Code chat-panel webview iframes (`chatPanelUrl` in
|
|
62
|
+
* packages/vscode/src/commands/sessionView.logic.ts).
|
|
63
|
+
*/
|
|
64
|
+
export declare function sessionChatAppUrl(httpBaseUrl: string, sessionId?: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* Factory: close over the daemon origin + the installed-ness check so
|
|
67
|
+
* execute() needs nothing beyond the tool input (no registry access inside
|
|
68
|
+
* the app itself — mirrors live-session/index.ts).
|
|
69
|
+
*/
|
|
70
|
+
export declare function makeSessionChatApp(ops: SessionChatOps): AgnoMcpApp<SessionChatInput, SessionChatOutput>;
|
|
71
|
+
export declare const sessionChatApp: AppHandle;
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session-chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAE7E,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,CAAA;AAE3D,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,0BAA0B,CAAA;AAE1D,eAAO,MAAM,sBAAsB;;iBAQjC,CAAA;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE,MAAM,WAAW,iBAAiB;IAChC;gDAC4C;IAC5C,SAAS,EAAE,OAAO,CAAA;IAClB,oEAAoE;IACpE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B;0DACsD;IACtD,WAAW,EAAE,MAAM,CAAA;IACnB;;6EAEyE;IACzE,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAA;CACvC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAMjF;AAQD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,cAAc,GAClB,UAAU,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAoBjD;AAED,eAAO,MAAM,cAAc,EAAE,SAY3B,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML bundles for the session-chat builtin widget — the thin bridge page
|
|
3
|
+
* (`sessionChatEmbedHtml`) and the not-installed notice
|
|
4
|
+
* (`SESSION_CHAT_FALLBACK_HTML`) served as the
|
|
5
|
+
* `ui://agentproto_session_chat/view` resource by `registerMcpApps` (see
|
|
6
|
+
* ../mcp-app-types.ts and runtime's mcp-apps-adapter.ts). Mounted via the
|
|
7
|
+
* `agentproto_session_chat` tool defined in ./index.ts.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately NOT a chat UI reimplementation: the real chat lives in the
|
|
10
|
+
* installed `@agentik/session-chat` app, served by the daemon's standalone
|
|
11
|
+
* app host at `GET /apps/@agentik/session-chat/ui`. When the app is
|
|
12
|
+
* installed, this page is a full-viewport iframe of that URL deep-linked
|
|
13
|
+
* with `?session=<id>&embed=1` — the exact spelling the daemon's standalone
|
|
14
|
+
* route relaxes its `frame-ancestors 'none'` for (see runtime
|
|
15
|
+
* http-server.ts handleAppUiPage) and the VS Code chat-panel webview
|
|
16
|
+
* already uses. No second chat bundle exists anywhere in agentproto/ts.
|
|
17
|
+
*
|
|
18
|
+
* A persistent header with the deep link stays visible above the iframe, so
|
|
19
|
+
* if the frame is refused (older daemon without the embed relaxation, or a
|
|
20
|
+
* host whose own CSP blocks daemon frames) the user still has a one-click
|
|
21
|
+
* path to the chat in a tab. When the app is NOT installed the page is a
|
|
22
|
+
* small readable notice pointing at `agentproto app install` — the
|
|
23
|
+
* fallback branch, never a vendored UI.
|
|
24
|
+
*/
|
|
25
|
+
import type { SessionChatOutput } from "./index.js";
|
|
26
|
+
export declare function sessionChatEmbedHtml(initData: SessionChatOutput): string;
|
|
27
|
+
export declare const SESSION_CHAT_FALLBACK_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Session Chat \u2014 not installed</title>\n<style>\n*{box-sizing:border-box;margin:0;padding:0}\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}\n#wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}\nh1{font-size:18px;margin-bottom:12px}\ncode{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}\np{margin:8px 0;color:#8b949e;font-size:13px}\n</style>\n</head>\n<body>\n<div id=\"wrap\">\n <h1>Session Chat is not installed</h1>\n <p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app —\n it does not bundle the chat UI itself.</p>\n <p>To use it, install the app into this daemon:</p>\n <p><code>agentproto app install @agentik/session-chat</code></p>\n <p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a\n <code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that\n session.</p>\n</div>\n</body>\n</html>";
|
|
28
|
+
//# sourceMappingURL=panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/session-chat/panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOnD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CA6BxE;AAED,eAAO,MAAM,0BAA0B,gqCA2B/B,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentproto/apps v0.1.0
|
|
3
|
+
* Ready-made agentproto apps (teams of agents + workflows) built on app-kit.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// src/session-chat/panel.ts
|
|
7
|
+
function escapeAttr(text) {
|
|
8
|
+
return text.replace(/&/g, "&").replace(/"/g, """);
|
|
9
|
+
}
|
|
10
|
+
function sessionChatEmbedHtml(initData) {
|
|
11
|
+
const url = initData.url;
|
|
12
|
+
const link = url != null ? `<a href="${escapeAttr(url)}" target="_blank" rel="noreferrer">open in a tab</a>` : "app not installed";
|
|
13
|
+
const iframe = url != null ? `<iframe id="chat" title="Session Chat" src="${escapeAttr(url)}"></iframe>` : "";
|
|
14
|
+
return `<!DOCTYPE html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="UTF-8">
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
<title>Session Chat</title>
|
|
20
|
+
<style>
|
|
21
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
22
|
+
html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3;overflow:hidden}
|
|
23
|
+
#bar{padding:6px 12px;font-size:12px;color:#8b949e;background:#161b22;border-bottom:1px solid #30363d}
|
|
24
|
+
#bar a{color:#58a6ff}
|
|
25
|
+
#chat{border:0;display:block;width:100%;height:calc(100% - 29px)}
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div id="bar">Session Chat · ${link}</div>
|
|
30
|
+
${iframe}
|
|
31
|
+
</body>
|
|
32
|
+
</html>`;
|
|
33
|
+
}
|
|
34
|
+
var SESSION_CHAT_FALLBACK_HTML = `<!DOCTYPE html>
|
|
35
|
+
<html lang="en">
|
|
36
|
+
<head>
|
|
37
|
+
<meta charset="UTF-8">
|
|
38
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
39
|
+
<title>Session Chat \u2014 not installed</title>
|
|
40
|
+
<style>
|
|
41
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
42
|
+
html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}
|
|
43
|
+
#wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}
|
|
44
|
+
h1{font-size:18px;margin-bottom:12px}
|
|
45
|
+
code{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}
|
|
46
|
+
p{margin:8px 0;color:#8b949e;font-size:13px}
|
|
47
|
+
</style>
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div id="wrap">
|
|
51
|
+
<h1>Session Chat is not installed</h1>
|
|
52
|
+
<p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app —
|
|
53
|
+
it does not bundle the chat UI itself.</p>
|
|
54
|
+
<p>To use it, install the app into this daemon:</p>
|
|
55
|
+
<p><code>agentproto app install @agentik/session-chat</code></p>
|
|
56
|
+
<p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a
|
|
57
|
+
<code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that
|
|
58
|
+
session.</p>
|
|
59
|
+
</div>
|
|
60
|
+
</body>
|
|
61
|
+
</html>`;
|
|
62
|
+
|
|
63
|
+
export { SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml };
|
|
64
|
+
//# sourceMappingURL=panel.mjs.map
|
|
65
|
+
//# sourceMappingURL=panel.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-chat/panel.ts"],"names":[],"mappings":";;;;;;AA4BA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,OAAO,KAAK,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3D;AAEO,SAAS,qBAAqB,QAAA,EAAqC;AACxE,EAAA,MAAM,MAAM,QAAA,CAAS,GAAA;AACrB,EAAA,MAAM,OACJ,GAAA,IAAO,IAAA,GACH,YAAY,UAAA,CAAW,GAAG,CAAC,CAAA,oDAAA,CAAA,GAC3B,mBAAA;AACN,EAAA,MAAM,SACJ,GAAA,IAAO,IAAA,GACH,+CAA+C,UAAA,CAAW,GAAG,CAAC,CAAA,WAAA,CAAA,GAC9D,EAAA;AACN,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAAA,EAe2B,IAAI,CAAA;AAAA,EACtC,MAAM;AAAA;AAAA,OAAA,CAAA;AAGR;AAEO,IAAM,0BAAA,GAA6B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAAA","file":"panel.mjs","sourcesContent":["/**\n * HTML bundles for the session-chat builtin widget — the thin bridge page\n * (`sessionChatEmbedHtml`) and the not-installed notice\n * (`SESSION_CHAT_FALLBACK_HTML`) served as the\n * `ui://agentproto_session_chat/view` resource by `registerMcpApps` (see\n * ../mcp-app-types.ts and runtime's mcp-apps-adapter.ts). Mounted via the\n * `agentproto_session_chat` tool defined in ./index.ts.\n *\n * Deliberately NOT a chat UI reimplementation: the real chat lives in the\n * installed `@agentik/session-chat` app, served by the daemon's standalone\n * app host at `GET /apps/@agentik/session-chat/ui`. When the app is\n * installed, this page is a full-viewport iframe of that URL deep-linked\n * with `?session=<id>&embed=1` — the exact spelling the daemon's standalone\n * route relaxes its `frame-ancestors 'none'` for (see runtime\n * http-server.ts handleAppUiPage) and the VS Code chat-panel webview\n * already uses. No second chat bundle exists anywhere in agentproto/ts.\n *\n * A persistent header with the deep link stays visible above the iframe, so\n * if the frame is refused (older daemon without the embed relaxation, or a\n * host whose own CSP blocks daemon frames) the user still has a one-click\n * path to the chat in a tab. When the app is NOT installed the page is a\n * small readable notice pointing at `agentproto app install` — the\n * fallback branch, never a vendored UI.\n */\n\nimport type { SessionChatOutput } from \"./index.js\"\n\n/** Only `&` and `\"` are significant inside a double-quoted attribute value. */\nfunction escapeAttr(text: string): string {\n return text.replace(/&/g, \"&\").replace(/\"/g, \""\")\n}\n\nexport function sessionChatEmbedHtml(initData: SessionChatOutput): string {\n const url = initData.url\n const link =\n url != null\n ? `<a href=\"${escapeAttr(url)}\" target=\"_blank\" rel=\"noreferrer\">open in a tab</a>`\n : \"app not installed\"\n const iframe =\n url != null\n ? `<iframe id=\"chat\" title=\"Session Chat\" src=\"${escapeAttr(url)}\"></iframe>`\n : \"\"\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Session Chat</title>\n<style>\n*{box-sizing:border-box;margin:0;padding:0}\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3;overflow:hidden}\n#bar{padding:6px 12px;font-size:12px;color:#8b949e;background:#161b22;border-bottom:1px solid #30363d}\n#bar a{color:#58a6ff}\n#chat{border:0;display:block;width:100%;height:calc(100% - 29px)}\n</style>\n</head>\n<body>\n<div id=\"bar\">Session Chat · ${link}</div>\n${iframe}\n</body>\n</html>`\n}\n\nexport const SESSION_CHAT_FALLBACK_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Session Chat — not installed</title>\n<style>\n*{box-sizing:border-box;margin:0;padding:0}\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}\n#wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}\nh1{font-size:18px;margin-bottom:12px}\ncode{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}\np{margin:8px 0;color:#8b949e;font-size:13px}\n</style>\n</head>\n<body>\n<div id=\"wrap\">\n <h1>Session Chat is not installed</h1>\n <p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app —\n it does not bundle the chat UI itself.</p>\n <p>To use it, install the app into this daemon:</p>\n <p><code>agentproto app install @agentik/session-chat</code></p>\n <p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a\n <code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that\n session.</p>\n</div>\n</body>\n</html>`\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineApp } from '@agentproto/app-kit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @agentproto/apps v0.1.0
|
|
6
|
+
* Ready-made agentproto apps (teams of agents + workflows) built on app-kit.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// src/session-chat/panel.ts
|
|
11
|
+
function escapeAttr(text) {
|
|
12
|
+
return text.replace(/&/g, "&").replace(/"/g, """);
|
|
13
|
+
}
|
|
14
|
+
function sessionChatEmbedHtml(initData) {
|
|
15
|
+
const url = initData.url;
|
|
16
|
+
const link = url != null ? `<a href="${escapeAttr(url)}" target="_blank" rel="noreferrer">open in a tab</a>` : "app not installed";
|
|
17
|
+
const iframe = url != null ? `<iframe id="chat" title="Session Chat" src="${escapeAttr(url)}"></iframe>` : "";
|
|
18
|
+
return `<!DOCTYPE html>
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="UTF-8">
|
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
23
|
+
<title>Session Chat</title>
|
|
24
|
+
<style>
|
|
25
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
26
|
+
html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3;overflow:hidden}
|
|
27
|
+
#bar{padding:6px 12px;font-size:12px;color:#8b949e;background:#161b22;border-bottom:1px solid #30363d}
|
|
28
|
+
#bar a{color:#58a6ff}
|
|
29
|
+
#chat{border:0;display:block;width:100%;height:calc(100% - 29px)}
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<div id="bar">Session Chat · ${link}</div>
|
|
34
|
+
${iframe}
|
|
35
|
+
</body>
|
|
36
|
+
</html>`;
|
|
37
|
+
}
|
|
38
|
+
var SESSION_CHAT_FALLBACK_HTML = `<!DOCTYPE html>
|
|
39
|
+
<html lang="en">
|
|
40
|
+
<head>
|
|
41
|
+
<meta charset="UTF-8">
|
|
42
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
43
|
+
<title>Session Chat \u2014 not installed</title>
|
|
44
|
+
<style>
|
|
45
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
46
|
+
html,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}
|
|
47
|
+
#wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}
|
|
48
|
+
h1{font-size:18px;margin-bottom:12px}
|
|
49
|
+
code{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}
|
|
50
|
+
p{margin:8px 0;color:#8b949e;font-size:13px}
|
|
51
|
+
</style>
|
|
52
|
+
</head>
|
|
53
|
+
<body>
|
|
54
|
+
<div id="wrap">
|
|
55
|
+
<h1>Session Chat is not installed</h1>
|
|
56
|
+
<p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app —
|
|
57
|
+
it does not bundle the chat UI itself.</p>
|
|
58
|
+
<p>To use it, install the app into this daemon:</p>
|
|
59
|
+
<p><code>agentproto app install @agentik/session-chat</code></p>
|
|
60
|
+
<p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a
|
|
61
|
+
<code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that
|
|
62
|
+
session.</p>
|
|
63
|
+
</div>
|
|
64
|
+
</body>
|
|
65
|
+
</html>`;
|
|
66
|
+
|
|
67
|
+
// src/session-chat/index.ts
|
|
68
|
+
var SESSION_CHAT_APP_ID = "@agentik/session-chat";
|
|
69
|
+
var sessionChatInputSchema = z.object({
|
|
70
|
+
sessionId: z.string().optional().describe(
|
|
71
|
+
"Deep-link the chat to an existing session by id (e.g. `sess_xxx`). Omit to open the app with its session picker."
|
|
72
|
+
)
|
|
73
|
+
});
|
|
74
|
+
function sessionChatAppUrl(httpBaseUrl, sessionId) {
|
|
75
|
+
const base = `${httpBaseUrl.replace(/\/+$/, "")}/apps/${SESSION_CHAT_APP_ID}/ui`;
|
|
76
|
+
const params = new URLSearchParams();
|
|
77
|
+
if (sessionId) params.set("session", sessionId);
|
|
78
|
+
params.set("embed", "1");
|
|
79
|
+
return `${base}?${params.toString()}`;
|
|
80
|
+
}
|
|
81
|
+
function frameOrigin(httpBaseUrl) {
|
|
82
|
+
return new URL(httpBaseUrl).origin;
|
|
83
|
+
}
|
|
84
|
+
function makeSessionChatApp(ops) {
|
|
85
|
+
const installed = ops.isSessionChatInstalled?.() ?? false;
|
|
86
|
+
return {
|
|
87
|
+
id: "agentproto_session_chat",
|
|
88
|
+
title: "Session Chat",
|
|
89
|
+
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.",
|
|
90
|
+
inputSchema: sessionChatInputSchema,
|
|
91
|
+
execute: async (input) => ({
|
|
92
|
+
installed,
|
|
93
|
+
url: installed ? sessionChatAppUrl(ops.httpBaseUrl, input.sessionId) : null
|
|
94
|
+
}),
|
|
95
|
+
html: (initData) => sessionChatEmbedHtml(initData),
|
|
96
|
+
csp: { frameDomains: [frameOrigin(ops.httpBaseUrl)] }
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
var sessionChatApp = defineApp({
|
|
100
|
+
id: "@agentproto/session-chat-widget",
|
|
101
|
+
name: "Session Chat",
|
|
102
|
+
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.",
|
|
103
|
+
agents: [],
|
|
104
|
+
ui: {
|
|
105
|
+
html: SESSION_CHAT_FALLBACK_HTML,
|
|
106
|
+
title: "Session Chat",
|
|
107
|
+
tools: ["session_list", "agent_start", "adapter_list", "conversation_read"]
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
export { SESSION_CHAT_APP_ID, SESSION_CHAT_FALLBACK_HTML, makeSessionChatApp, sessionChatApp, sessionChatAppUrl, sessionChatEmbedHtml, sessionChatInputSchema };
|
|
112
|
+
//# sourceMappingURL=session-chat.mjs.map
|
|
113
|
+
//# sourceMappingURL=session-chat.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session-chat/panel.ts","../src/session-chat/index.ts"],"names":[],"mappings":"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","file":"session-chat.mjs","sourcesContent":["/**\n * HTML bundles for the session-chat builtin widget — the thin bridge page\n * (`sessionChatEmbedHtml`) and the not-installed notice\n * (`SESSION_CHAT_FALLBACK_HTML`) served as the\n * `ui://agentproto_session_chat/view` resource by `registerMcpApps` (see\n * ../mcp-app-types.ts and runtime's mcp-apps-adapter.ts). Mounted via the\n * `agentproto_session_chat` tool defined in ./index.ts.\n *\n * Deliberately NOT a chat UI reimplementation: the real chat lives in the\n * installed `@agentik/session-chat` app, served by the daemon's standalone\n * app host at `GET /apps/@agentik/session-chat/ui`. When the app is\n * installed, this page is a full-viewport iframe of that URL deep-linked\n * with `?session=<id>&embed=1` — the exact spelling the daemon's standalone\n * route relaxes its `frame-ancestors 'none'` for (see runtime\n * http-server.ts handleAppUiPage) and the VS Code chat-panel webview\n * already uses. No second chat bundle exists anywhere in agentproto/ts.\n *\n * A persistent header with the deep link stays visible above the iframe, so\n * if the frame is refused (older daemon without the embed relaxation, or a\n * host whose own CSP blocks daemon frames) the user still has a one-click\n * path to the chat in a tab. When the app is NOT installed the page is a\n * small readable notice pointing at `agentproto app install` — the\n * fallback branch, never a vendored UI.\n */\n\nimport type { SessionChatOutput } from \"./index.js\"\n\n/** Only `&` and `\"` are significant inside a double-quoted attribute value. */\nfunction escapeAttr(text: string): string {\n return text.replace(/&/g, \"&\").replace(/\"/g, \""\")\n}\n\nexport function sessionChatEmbedHtml(initData: SessionChatOutput): string {\n const url = initData.url\n const link =\n url != null\n ? `<a href=\"${escapeAttr(url)}\" target=\"_blank\" rel=\"noreferrer\">open in a tab</a>`\n : \"app not installed\"\n const iframe =\n url != null\n ? `<iframe id=\"chat\" title=\"Session Chat\" src=\"${escapeAttr(url)}\"></iframe>`\n : \"\"\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Session Chat</title>\n<style>\n*{box-sizing:border-box;margin:0;padding:0}\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3;overflow:hidden}\n#bar{padding:6px 12px;font-size:12px;color:#8b949e;background:#161b22;border-bottom:1px solid #30363d}\n#bar a{color:#58a6ff}\n#chat{border:0;display:block;width:100%;height:calc(100% - 29px)}\n</style>\n</head>\n<body>\n<div id=\"bar\">Session Chat · ${link}</div>\n${iframe}\n</body>\n</html>`\n}\n\nexport const SESSION_CHAT_FALLBACK_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Session Chat — not installed</title>\n<style>\n*{box-sizing:border-box;margin:0;padding:0}\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:#0d1117;color:#e6edf3}\n#wrap{max-width:560px;margin:0 auto;padding:48px 24px;line-height:1.6}\nh1{font-size:18px;margin-bottom:12px}\ncode{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:2px 6px;font-size:13px}\np{margin:8px 0;color:#8b949e;font-size:13px}\n</style>\n</head>\n<body>\n<div id=\"wrap\">\n <h1>Session Chat is not installed</h1>\n <p>This panel is a thin launcher for the <code>@agentik/session-chat</code> app —\n it does not bundle the chat UI itself.</p>\n <p>To use it, install the app into this daemon:</p>\n <p><code>agentproto app install @agentik/session-chat</code></p>\n <p>Once installed, call <code>agentproto_session_chat</code> again (optionally with a\n <code>sessionId</code>) and the panel will embed the app's chat UI deep-linked to that\n session.</p>\n</div>\n</body>\n</html>`\n","/**\n * McpApp definition for the session-chat builtin widget — a thin launcher\n * for the installed `@agentik/session-chat` app's UI, exposed as a BUILTIN\n * daemon panel so MCP-Apps clients (and the VS Code appPanel surface) can\n * open the chat from `app_catalog` without installing anything into the\n * MCP surface itself.\n *\n * Uses the AgnoMcpApp contract (a local McpApp-compatible shape that does\n * NOT depend on @agstudio/mcp-apps or Mastra), same as sessions-panel /\n * live-session — the host (@agentproto/runtime) wires this factory's output\n * via `registerMcpApps` from its mcp-apps-adapter.ts at boot time, with the\n * mounted list assembled in runtime's builtin-apps.ts.\n *\n * Serving approach (decided; see the PR description for the tradeoffs):\n * (a) App installed → the tool returns the app's standalone deep-link\n * (`GET /apps/@agentik/session-chat/ui?session=<id>&embed=1`) and the\n * panel HTML is a thin full-viewport iframe of it. No duplicate chat\n * bundle: the UI is the studio-built app, served by the daemon's\n * standalone app host. The daemon relaxes that route's\n * `frame-ancestors 'none'` only when `?embed=1` is present.\n * (b) App NOT installed → the panel HTML is a small readable notice\n * pointing at `agentproto app install`. Never a vendored/reimplemented\n * chat UI.\n *\n * This module also exports `sessionChatApp`, a real `defineApp()`\n * `AppHandle` (`agents: []`, UI-only) — the catalog/emit/`app_install`\n * path. Its `ui.html` is the fallback notice, since `AppUiDefinition.ui.html`\n * is a plain static string and can't know at emit time whether the sibling\n * app is installed; the live-mounted `makeSessionChatApp` below is the one\n * that resolves installed-ness per boot.\n */\n\nimport { z } from \"zod\"\nimport { defineApp, type AppHandle } from \"@agentproto/app-kit\"\nimport type { AgnoMcpApp } from \"../mcp-app-types.js\"\nimport { SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml } from \"./panel.js\"\n\nexport { SESSION_CHAT_FALLBACK_HTML, sessionChatEmbedHtml }\n\n/** The installed studio app this builtin widget is a launcher for. */\nexport const SESSION_CHAT_APP_ID = \"@agentik/session-chat\"\n\nexport const sessionChatInputSchema = z.object({\n sessionId: z\n .string()\n .optional()\n .describe(\n \"Deep-link the chat to an existing session by id (e.g. `sess_xxx`). \" +\n \"Omit to open the app with its session picker.\",\n ),\n})\n\nexport type SessionChatInput = z.infer<typeof sessionChatInputSchema>\n\nexport interface SessionChatOutput {\n /** Whether the `@agentik/session-chat` app is installed (with a UI) on\n * the daemon this widget is mounted on. */\n installed: boolean\n /** The app's standalone deep-link url when installed, else null. */\n url: string | null\n}\n\nexport interface SessionChatOps {\n /** The daemon's own HTTP origin, e.g. \"http://127.0.0.1:18790\" — the\n * standalone app host the chat UI is served from. */\n httpBaseUrl: string\n /** Whether the `@agentik/session-chat` app is installed with a `ui`\n * block. The runtime supplies this from its AppRegistry; optional so\n * tests/consumers without a registry can omit it (treated as false). */\n isSessionChatInstalled?: () => boolean\n}\n\n/**\n * Deep-link into the installed app's standalone UI — the same url shape the\n * VS Code chat-panel webview iframes (`chatPanelUrl` in\n * packages/vscode/src/commands/sessionView.logic.ts).\n */\nexport function sessionChatAppUrl(httpBaseUrl: string, sessionId?: string): string {\n const base = `${httpBaseUrl.replace(/\\/+$/, \"\")}/apps/${SESSION_CHAT_APP_ID}/ui`\n const params = new URLSearchParams()\n if (sessionId) params.set(\"session\", sessionId)\n params.set(\"embed\", \"1\")\n return `${base}?${params.toString()}`\n}\n\n/** The daemon origin the widget's host-iframe CSP must allow as a frame\n * target (same derivation as live-session's connectDomains entry). */\nfunction frameOrigin(httpBaseUrl: string): string {\n return new URL(httpBaseUrl).origin\n}\n\n/**\n * Factory: close over the daemon origin + the installed-ness check so\n * execute() needs nothing beyond the tool input (no registry access inside\n * the app itself — mirrors live-session/index.ts).\n */\nexport function makeSessionChatApp(\n ops: SessionChatOps,\n): AgnoMcpApp<SessionChatInput, SessionChatOutput> {\n const installed = ops.isSessionChatInstalled?.() ?? false\n return {\n id: \"agentproto_session_chat\",\n title: \"Session Chat\",\n description:\n \"Open the Session Chat app — a chat-thread view of any agentproto \" +\n \"daemon session: full transcript replay, live follow-over SSE, and a \" +\n \"composer that sends prompts into the same session. Requires the \" +\n \"`@agentik/session-chat` app to be installed; without it the panel \" +\n \"shows install instructions. Pass `sessionId` to deep-link straight \" +\n \"into a known session.\",\n inputSchema: sessionChatInputSchema,\n execute: async input => ({\n installed,\n url: installed ? sessionChatAppUrl(ops.httpBaseUrl, input.sessionId) : null,\n }),\n html: (initData: SessionChatOutput) => sessionChatEmbedHtml(initData),\n csp: { frameDomains: [frameOrigin(ops.httpBaseUrl)] },\n }\n}\n\nexport const sessionChatApp: AppHandle = defineApp({\n id: \"@agentproto/session-chat-widget\",\n name: \"Session Chat\",\n description:\n \"Open the Session Chat app — a chat-thread view of any agentproto daemon session, deep-linked \" +\n \"by sessionId. A thin builtin launcher for the installed @agentik/session-chat app.\",\n agents: [],\n ui: {\n html: SESSION_CHAT_FALLBACK_HTML,\n title: \"Session Chat\",\n tools: [\"session_list\", \"agent_start\", \"adapter_list\", \"conversation_read\"],\n },\n})\n"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McpApp definition for the agentproto work-board panel — a kanban over the
|
|
3
|
+
* daemon's Task ledger (`packages/runtime/src/task-ledger.ts`), the ONLY
|
|
4
|
+
* writable multi-party entity the daemon exposes (Activity is a read-only
|
|
5
|
+
* projection recomputed on every `list()`; a session has a lifecycle, not an
|
|
6
|
+
* intention).
|
|
7
|
+
*
|
|
8
|
+
* Uses the AgnoMcpApp contract (a local McpApp-compatible shape that does
|
|
9
|
+
* NOT depend on @agstudio/mcp-apps or Mastra), same as sessions-panel /
|
|
10
|
+
* session-chat — the host (@agentproto/runtime) wires this factory's output
|
|
11
|
+
* via `registerMcpApps` from its mcp-apps-adapter.ts at boot time, with the
|
|
12
|
+
* mounted list assembled in runtime's builtin-apps.ts.
|
|
13
|
+
*
|
|
14
|
+
* Protocol flow:
|
|
15
|
+
* 1. Tool `agentproto_work_board` is called by the host with an optional
|
|
16
|
+
* `boardId`.
|
|
17
|
+
* 2. execute() answers an initial `{boardId, tasks}` snapshot off the
|
|
18
|
+
* ledger — resolved to the caller's default board when `boardId` is
|
|
19
|
+
* omitted (a session's `tree:<root>`, the operator's `ws:<slug>`).
|
|
20
|
+
* 3. The HTML panel opens a JSON-RPC bridge (postMessage) and polls
|
|
21
|
+
* `task_list` (`full: true` — the compact projection drops
|
|
22
|
+
* `verification`) every ~4 s; writes go through `task_claim` /
|
|
23
|
+
* `task_update` / `task_create`, the same verbs any other caller uses —
|
|
24
|
+
* no second write path.
|
|
25
|
+
*
|
|
26
|
+
* This module also exports `workBoardApp`, a real `defineApp()` `AppHandle`
|
|
27
|
+
* (`agents: []`, UI-only) — the catalog/emit/`app_install` path. It's
|
|
28
|
+
* separate from `makeWorkBoardApp` above, which the daemon mounts directly
|
|
29
|
+
* at boot: that factory closes over the LIVE ledger read, something a
|
|
30
|
+
* static emitted `ui.html` snapshot can't carry.
|
|
31
|
+
*/
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
import { type AppHandle } from "@agentproto/app-kit";
|
|
34
|
+
import type { AgnoMcpApp } from "../mcp-app-types.js";
|
|
35
|
+
export declare const workBoardInputSchema: z.ZodObject<{
|
|
36
|
+
boardId: z.ZodOptional<z.ZodString>;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
export type WorkBoardInput = z.infer<typeof workBoardInputSchema>;
|
|
39
|
+
export interface WorkBoardOutput<TTask = unknown> {
|
|
40
|
+
/** Always echoed back — the ledger's board ids are the swimlane
|
|
41
|
+
* selector, and must be visible rather than hidden behind a friendly
|
|
42
|
+
* name (it's how the operator knows which mission they're looking at). */
|
|
43
|
+
boardId: string;
|
|
44
|
+
tasks: TTask[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generic over the host's own task-record shape — this package doesn't own
|
|
48
|
+
* that type (it lives in @agentproto/runtime's task ledger), so the factory
|
|
49
|
+
* stays agnostic to it and the host supplies the concrete type as a type
|
|
50
|
+
* argument when it wires the app up (mirrors SessionsPanelOps<TSession>).
|
|
51
|
+
*/
|
|
52
|
+
export interface WorkBoardOps<TTask = unknown> {
|
|
53
|
+
/** Full (unprojected) records for a board — NOT `task_list`'s default
|
|
54
|
+
* compact projection, since the verification tell needs `verification`
|
|
55
|
+
* (self-report vs gate vs human), which compact mode omits. Omit
|
|
56
|
+
* `boardId` to resolve the caller's default board. */
|
|
57
|
+
listTasks(boardId?: string): WorkBoardOutput<TTask>;
|
|
58
|
+
}
|
|
59
|
+
export type { AgnoMcpApp };
|
|
60
|
+
/**
|
|
61
|
+
* Factory: close over the ledger read so execute() doesn't need an
|
|
62
|
+
* AppContext (agentproto has no userId/guildId concept) — mirrors
|
|
63
|
+
* makeSessionsPanelApp.
|
|
64
|
+
*/
|
|
65
|
+
export declare function makeWorkBoardApp<TTask = unknown>(ops: WorkBoardOps<TTask>): AgnoMcpApp<WorkBoardInput, WorkBoardOutput<TTask>>;
|
|
66
|
+
export declare const workBoardApp: AppHandle;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/work-board/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAErD,eAAO,MAAM,oBAAoB;;iBAS/B,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEjE,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO;IAC9C;;+EAE2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,KAAK,EAAE,CAAA;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK,GAAG,OAAO;IAC3C;;;2DAGuD;IACvD,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;CACpD;AAED,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAC9C,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,GACvB,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAepD;AAED,eAAO,MAAM,YAAY,EAAE,SAYzB,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML bundle for the agentproto work-board panel — the `WORK_BOARD_HTML`
|
|
3
|
+
* served as the `ui://agentproto_work_board/view` resource by
|
|
4
|
+
* `registerMcpApps` (see ../mcp-app-types.ts and runtime's
|
|
5
|
+
* mcp-apps-adapter.ts). Mounted via the `agentproto_work_board` tool defined
|
|
6
|
+
* in ./index.ts.
|
|
7
|
+
*
|
|
8
|
+
* A kanban over the daemon's Task ledger (`packages/runtime/src/
|
|
9
|
+
* task-ledger.ts`) — the one writable multi-party entity the daemon exposes
|
|
10
|
+
* (Activity is a read-only projection; a session has a lifecycle, not an
|
|
11
|
+
* intention). Columns are the ledger's own status enum, folding `cancelled`
|
|
12
|
+
* into the `failed` column (tagged distinctly — see `columnOf` below)
|
|
13
|
+
* rather than adding a fifth column for a status v1 treats as terminal
|
|
14
|
+
* scrap. The board/swimlane selector is the ledger's own board id
|
|
15
|
+
* (`tree:<rootSessionId>` or `ws:<slug>`) — always shown verbatim, never
|
|
16
|
+
* hidden behind a friendly name, per the ledger's scoping model.
|
|
17
|
+
*
|
|
18
|
+
* Protocol: MCP Apps ext spec 2026-01-26
|
|
19
|
+
* – Bridge: JSON-RPC 2.0 over window.parent.postMessage
|
|
20
|
+
* – Handshake: ui/initialize → host result → ui/notifications/initialized
|
|
21
|
+
* – Data: tools/call → task_list (`full: true` — the compact projection
|
|
22
|
+
* drops `verification`, which the verification tell needs) on a ~4 s poll
|
|
23
|
+
* – Actions: tools/call → task_claim / task_update / task_create
|
|
24
|
+
*
|
|
25
|
+
* Read-only-safe first: no drag-and-drop. Each card gets the explicit status
|
|
26
|
+
* actions valid from its current state (Claim/Start/Done/Fail/Release/
|
|
27
|
+
* Cancel/Reopen) — a correct read-only-plus-explicit-actions board beats a
|
|
28
|
+
* half-wired drag, per the brief.
|
|
29
|
+
*
|
|
30
|
+
* The verification tell (never render an unverified done as gate-passed):
|
|
31
|
+
* - `verification.kind === "gate"` → solid green "✓ gate"
|
|
32
|
+
* - `verification.kind === "self-report"` → amber outline "self-report"
|
|
33
|
+
* - `verification.kind === "human"` → blue "human"
|
|
34
|
+
* - a declared `verify` with no verification yet → grey "gated" tag
|
|
35
|
+
* An owner-less task always reads "Unclaimed", never "pending" (that word is
|
|
36
|
+
* reserved for the Activity vocabulary's "blocked" meaning elsewhere).
|
|
37
|
+
*/
|
|
38
|
+
export declare const WORK_BOARD_HTML: string;
|
|
39
|
+
//# sourceMappingURL=panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/work-board/panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAIH,eAAO,MAAM,eAAe,QAqTpB,CAAA"}
|