@tangle-network/agent-app 0.60.180 → 0.60.182

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.
Files changed (55) hide show
  1. package/dist/assistant/index.js +12 -12
  2. package/dist/chat-routes/index.js +23 -23
  3. package/dist/chat-store/index.js +4 -4
  4. package/dist/{chunk-6ZUVYAKB.js → chunk-6O2NQ7WD.js} +9 -9
  5. package/dist/{chunk-IIE3K2Y5.js → chunk-EOPFHXEA.js} +1 -1
  6. package/dist/{chunk-PYPWEXTD.js → chunk-J26IXWFK.js} +12 -12
  7. package/dist/chunk-LTWJYNEC.js +100 -0
  8. package/dist/chunk-LTWJYNEC.js.map +1 -0
  9. package/dist/{chunk-YR6TZ777.js → chunk-TNWDYAFX.js} +6 -6
  10. package/dist/{chunk-T5PPQPOD.js → chunk-TXUAGSFR.js} +1 -1
  11. package/dist/{chunk-T5PPQPOD.js.map → chunk-TXUAGSFR.js.map} +1 -1
  12. package/dist/{chunk-N3CYCSKK.js → chunk-ZBB5KQ6B.js} +1 -1
  13. package/dist/chunk-ZBB5KQ6B.js.map +1 -0
  14. package/dist/{chunk-XNKLQG26.js → chunk-ZGUXI5SI.js} +5 -5
  15. package/dist/design-canvas-react/index.js +4 -4
  16. package/dist/design-canvas-react/lazy.js +1 -1
  17. package/dist/model-resolution/allow-list.d.ts +64 -0
  18. package/dist/model-resolution/index.d.ts +1 -0
  19. package/dist/model-resolution/index.js +28 -0
  20. package/dist/model-resolution/index.js.map +1 -1
  21. package/dist/profile/index.js +2 -1
  22. package/dist/profile/index.js.map +1 -1
  23. package/dist/public-consultation/index.d.ts +1 -1
  24. package/dist/public-consultation/index.js +8 -8
  25. package/dist/skills/index.d.ts +1 -0
  26. package/dist/skills/index.js +26 -2
  27. package/dist/skills/marketplace-drizzle.d.ts +121 -0
  28. package/dist/skills/marketplace-drizzle.js +34 -0
  29. package/dist/skills/marketplace-drizzle.js.map +1 -0
  30. package/dist/skills/marketplace.d.ts +104 -0
  31. package/dist/skills-placement/index.js +2 -1
  32. package/dist/skills-placement/index.js.map +1 -1
  33. package/dist/spend/delegate-budget.d.ts +59 -0
  34. package/dist/spend/index.d.ts +1 -0
  35. package/dist/spend/index.js +43 -0
  36. package/dist/spend/index.js.map +1 -1
  37. package/dist/stream/index.js +2 -2
  38. package/dist/teams/drizzle/access.d.ts +4 -0
  39. package/dist/teams/drizzle.js.map +1 -1
  40. package/dist/teams/invitations-api.d.ts +6 -3
  41. package/dist/teams/invitations-api.js +72 -39
  42. package/dist/teams/invitations-api.js.map +1 -1
  43. package/dist/teams/members-api.d.ts +2 -2
  44. package/dist/teams/members-api.js +1 -1
  45. package/dist/toolbelt/index.d.ts +80 -0
  46. package/dist/toolbelt/index.js +178 -0
  47. package/dist/toolbelt/index.js.map +1 -0
  48. package/dist/web-react/index.js +25 -25
  49. package/package.json +11 -1
  50. package/dist/chunk-N3CYCSKK.js.map +0 -1
  51. /package/dist/{chunk-6ZUVYAKB.js.map → chunk-6O2NQ7WD.js.map} +0 -0
  52. /package/dist/{chunk-IIE3K2Y5.js.map → chunk-EOPFHXEA.js.map} +0 -0
  53. /package/dist/{chunk-PYPWEXTD.js.map → chunk-J26IXWFK.js.map} +0 -0
  54. /package/dist/{chunk-YR6TZ777.js.map → chunk-TNWDYAFX.js.map} +0 -0
  55. /package/dist/{chunk-XNKLQG26.js.map → chunk-ZGUXI5SI.js.map} +0 -0
@@ -0,0 +1,80 @@
1
+ /** One authored tool in the product's manifest — the ONE source of truth the
2
+ * generated program and every derived surface (allowlists, prompt tool
3
+ * tables, dashboards) must agree with. */
4
+ export interface ToolbeltManifestTool {
5
+ readonly name: string;
6
+ /** AAA-standard description (what / example / when NOT). Parity requires the
7
+ * program to serve it byte-identical — truncation at a bundle boundary is
8
+ * drift, not formatting. */
9
+ readonly description: string;
10
+ /** JSON Schema for the tool's input. Compared structurally (key order
11
+ * insensitive) when either side declares one. */
12
+ readonly inputSchema?: unknown;
13
+ /** MCP tool annotations (readOnlyHint, …). Compared structurally when the
14
+ * manifest declares them. */
15
+ readonly annotations?: unknown;
16
+ /** Product-defined transport tag (`pure` | `http` | …). Not part of the
17
+ * wire surface; carried so derived surfaces can key off the manifest. */
18
+ readonly transport?: string;
19
+ }
20
+ /** A tool as the spawned program actually listed it. */
21
+ export interface ProbedTool {
22
+ readonly name: string;
23
+ readonly description?: string;
24
+ readonly inputSchema?: unknown;
25
+ readonly annotations?: unknown;
26
+ }
27
+ /** What `probeStdioToolProgram` saw. `serverInfo`/`raw` are included so a
28
+ * failed probe can name the layer (the diagnosability rule: never swallow). */
29
+ export interface ToolProgramProbe {
30
+ readonly tools: readonly ProbedTool[];
31
+ readonly initializeReply: Record<string, unknown> | null;
32
+ }
33
+ export interface ProbeStdioToolProgramOptions {
34
+ /** Path to the program to spawn. Spawned with the current Node executable. */
35
+ readonly program: string;
36
+ /** Extra argv after the program path. */
37
+ readonly args?: readonly string[];
38
+ /** Environment for the child. Defaults to `process.env`. */
39
+ readonly env?: NodeJS.ProcessEnv;
40
+ /** Working directory for the child. */
41
+ readonly cwd?: string;
42
+ /** Wall-clock ceiling for the whole probe. Default 15s. */
43
+ readonly timeoutMs?: number;
44
+ }
45
+ /** Spawn the embedded tool program and read its REAL tool surface. */
46
+ export declare function probeStdioToolProgram(options: ProbeStdioToolProgramOptions): Promise<ToolProgramProbe>;
47
+ /** Field-level drift between the manifest and the program's real surface. */
48
+ export interface ToolbeltFieldDrift {
49
+ readonly name: string;
50
+ readonly manifest: unknown;
51
+ readonly program: unknown;
52
+ }
53
+ /** The named diff. Every array is sorted; empty arrays mean agreement. */
54
+ export interface ToolbeltParityDiff {
55
+ readonly ok: boolean;
56
+ /** Manifest tools the program did not list (the #10155 class: the verb
57
+ * exists in the manifest, absent from the running surface). */
58
+ readonly missingFromProgram: readonly string[];
59
+ /** Tools the program listed that no manifest entry owns. */
60
+ readonly unknownToManifest: readonly string[];
61
+ /** Tools whose served description is not byte-identical to the manifest. */
62
+ readonly descriptionDrift: readonly ToolbeltFieldDrift[];
63
+ /** Tools whose served input schema differs structurally from the manifest. */
64
+ readonly schemaDrift: readonly ToolbeltFieldDrift[];
65
+ /** Tools whose served annotations differ structurally from the manifest. */
66
+ readonly annotationDrift: readonly ToolbeltFieldDrift[];
67
+ }
68
+ /** Diff a spawned program's real surface against the authored manifest. */
69
+ export declare function toolbeltParityDiff(manifest: readonly ToolbeltManifestTool[], listed: readonly ProbedTool[]): ToolbeltParityDiff;
70
+ /** Render a diff as one actionable report — every drift named, never a bare count. */
71
+ export declare function formatToolbeltParityDiff(diff: ToolbeltParityDiff): string;
72
+ /** Thrown by {@link assertToolbeltParity} with the full formatted diff. */
73
+ export declare class ToolbeltParityError extends Error {
74
+ readonly diff: ToolbeltParityDiff;
75
+ constructor(diff: ToolbeltParityDiff);
76
+ }
77
+ /** Assert parity: same names, byte-identical descriptions, structurally equal
78
+ * schemas and annotations. Throws {@link ToolbeltParityError} with every
79
+ * disagreement named — a red build, not a production silence. */
80
+ export declare function assertToolbeltParity(manifest: readonly ToolbeltManifestTool[], listed: readonly ProbedTool[]): void;
@@ -0,0 +1,178 @@
1
+ // src/toolbelt/index.ts
2
+ import { spawn } from "child_process";
3
+ function probeStdioToolProgram(options) {
4
+ const timeoutMs = options.timeoutMs ?? 15e3;
5
+ return new Promise((resolve, reject) => {
6
+ const child = spawn(process.execPath, [options.program, ...options.args ?? []], {
7
+ env: options.env ?? process.env,
8
+ cwd: options.cwd,
9
+ stdio: ["pipe", "pipe", "pipe"]
10
+ });
11
+ let stdout = "";
12
+ let stderr = "";
13
+ let settled = false;
14
+ let initializeReply = null;
15
+ const lines = [];
16
+ const finish = (run) => {
17
+ if (settled) return;
18
+ settled = true;
19
+ clearTimeout(timer);
20
+ try {
21
+ child.kill();
22
+ } catch {
23
+ }
24
+ run();
25
+ };
26
+ const timer = setTimeout(
27
+ () => finish(() => reject(new Error(
28
+ `tool program probe timed out after ${timeoutMs}ms waiting for tools/list. stderr so far: ${stderr.trim().slice(0, 2e3) || "(empty)"}; stdout so far: ${stdout.trim().slice(0, 2e3) || "(empty)"}`
29
+ ))),
30
+ timeoutMs
31
+ );
32
+ child.stdout.setEncoding("utf8");
33
+ child.stdout.on("data", (chunk) => {
34
+ stdout += chunk;
35
+ let index;
36
+ while ((index = stdout.indexOf("\n")) >= 0) {
37
+ const line = stdout.slice(0, index).trim();
38
+ stdout = stdout.slice(index + 1);
39
+ if (!line) continue;
40
+ lines.push(line);
41
+ let message;
42
+ try {
43
+ message = JSON.parse(line);
44
+ } catch {
45
+ continue;
46
+ }
47
+ if (message.method !== void 0) continue;
48
+ if (message.id === 1) initializeReply = message.result ?? null;
49
+ if (message.id === 2 && message.result !== void 0 && message.error === void 0) {
50
+ const rawTools = message.result.tools;
51
+ const tools = Array.isArray(rawTools) ? rawTools.filter((t) => !!t && typeof t === "object" && typeof t.name === "string").map((t) => {
52
+ const tool = t;
53
+ return {
54
+ name: tool.name,
55
+ ...tool.description !== void 0 ? { description: tool.description } : {},
56
+ ...tool.inputSchema !== void 0 ? { inputSchema: tool.inputSchema } : {},
57
+ ...tool.annotations !== void 0 ? { annotations: tool.annotations } : {}
58
+ };
59
+ }) : [];
60
+ finish(() => resolve({ tools, initializeReply }));
61
+ } else if (message.id === 2 && message.error !== void 0) {
62
+ finish(() => reject(new Error(
63
+ `tool program refused tools/list: ${JSON.stringify(message.error)}`
64
+ )));
65
+ }
66
+ }
67
+ });
68
+ child.stderr.setEncoding("utf8");
69
+ child.stderr.on("data", (chunk) => {
70
+ stderr += chunk;
71
+ });
72
+ child.on("error", (error) => finish(() => reject(new Error(
73
+ `tool program probe failed to spawn ${options.program}: ${error.message}`
74
+ ))));
75
+ child.on("exit", (code, signal) => finish(() => reject(new Error(
76
+ `tool program exited before answering tools/list (code ${code}${signal ? `, signal ${signal}` : ""}). stderr: ${stderr.trim().slice(0, 2e3) || "(empty)"}`
77
+ ))));
78
+ const send = (payload) => {
79
+ try {
80
+ child.stdin.write(JSON.stringify(payload) + "\n");
81
+ } catch {
82
+ }
83
+ };
84
+ send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "toolbelt-parity", version: "0.0.0" } } });
85
+ send({ jsonrpc: "2.0", method: "notifications/initialized" });
86
+ send({ jsonrpc: "2.0", id: 2, method: "tools/list" });
87
+ });
88
+ }
89
+ function stableStringify(value) {
90
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
91
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
92
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
93
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
94
+ }
95
+ function toolbeltParityDiff(manifest, listed) {
96
+ const byName = new Map(manifest.map((tool) => [tool.name, tool]));
97
+ const listedByName = new Map(listed.map((tool) => [tool.name, tool]));
98
+ const missingFromProgram = manifest.filter((tool) => !listedByName.has(tool.name)).map((tool) => tool.name).sort();
99
+ const unknownToManifest = listed.filter((tool) => !byName.has(tool.name)).map((tool) => tool.name).sort();
100
+ const descriptionDrift = [];
101
+ const schemaDrift = [];
102
+ const annotationDrift = [];
103
+ for (const tool of manifest) {
104
+ const served = listedByName.get(tool.name);
105
+ if (!served) continue;
106
+ if (served.description !== tool.description) {
107
+ descriptionDrift.push({ name: tool.name, manifest: tool.description, program: served.description ?? null });
108
+ }
109
+ const manifestSchema = tool.inputSchema;
110
+ if (manifestSchema !== void 0 || served.inputSchema !== void 0) {
111
+ if (stableStringify(manifestSchema) !== stableStringify(served.inputSchema)) {
112
+ schemaDrift.push({ name: tool.name, manifest: manifestSchema ?? null, program: served.inputSchema ?? null });
113
+ }
114
+ }
115
+ const manifestAnnotations = tool.annotations;
116
+ if (manifestAnnotations !== void 0 || served.annotations !== void 0) {
117
+ if (stableStringify(manifestAnnotations) !== stableStringify(served.annotations)) {
118
+ annotationDrift.push({ name: tool.name, manifest: manifestAnnotations ?? null, program: served.annotations ?? null });
119
+ }
120
+ }
121
+ }
122
+ const ok = missingFromProgram.length === 0 && unknownToManifest.length === 0 && descriptionDrift.length === 0 && schemaDrift.length === 0 && annotationDrift.length === 0;
123
+ return {
124
+ ok,
125
+ missingFromProgram,
126
+ unknownToManifest,
127
+ descriptionDrift,
128
+ schemaDrift,
129
+ annotationDrift
130
+ };
131
+ }
132
+ function formatToolbeltParityDiff(diff) {
133
+ if (diff.ok) return "toolbelt parity: the program is the manifest";
134
+ const lines = ["toolbelt parity FAILED \u2014 the program and the manifest disagree:"];
135
+ if (diff.missingFromProgram.length > 0) {
136
+ lines.push(` missing from the program (in the manifest, NOT served): ${diff.missingFromProgram.join(", ")}`);
137
+ }
138
+ if (diff.unknownToManifest.length > 0) {
139
+ lines.push(` unknown to the manifest (served, NOT authored): ${diff.unknownToManifest.join(", ")}`);
140
+ }
141
+ for (const drift of diff.descriptionDrift) {
142
+ lines.push(` description drift on "${drift.name}":`);
143
+ lines.push(` manifest: ${JSON.stringify(drift.manifest)}`);
144
+ lines.push(` program: ${JSON.stringify(drift.program)}`);
145
+ }
146
+ for (const drift of diff.schemaDrift) {
147
+ lines.push(` input-schema drift on "${drift.name}":`);
148
+ lines.push(` manifest: ${stableStringify(drift.manifest)}`);
149
+ lines.push(` program: ${stableStringify(drift.program)}`);
150
+ }
151
+ for (const drift of diff.annotationDrift) {
152
+ lines.push(` annotation drift on "${drift.name}":`);
153
+ lines.push(` manifest: ${stableStringify(drift.manifest)}`);
154
+ lines.push(` program: ${stableStringify(drift.program)}`);
155
+ }
156
+ lines.push(" Fix the ONE manifest (or the generator that derives the program from it) \u2014 never patch a second list.");
157
+ return lines.join("\n");
158
+ }
159
+ var ToolbeltParityError = class extends Error {
160
+ diff;
161
+ constructor(diff) {
162
+ super(formatToolbeltParityDiff(diff));
163
+ this.name = "ToolbeltParityError";
164
+ this.diff = diff;
165
+ }
166
+ };
167
+ function assertToolbeltParity(manifest, listed) {
168
+ const diff = toolbeltParityDiff(manifest, listed);
169
+ if (!diff.ok) throw new ToolbeltParityError(diff);
170
+ }
171
+ export {
172
+ ToolbeltParityError,
173
+ assertToolbeltParity,
174
+ formatToolbeltParityDiff,
175
+ probeStdioToolProgram,
176
+ toolbeltParityDiff
177
+ };
178
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/toolbelt/index.ts"],"sourcesContent":["/**\n * The toolbelt parity gate — one manifest, every target, enforced at build time.\n *\n * A product with an embedded tool program (a stdio MCP the sandbox spawns)\n * has two representations of its tool surface: the manifest it authors and\n * the program that actually answers `tools/list`. Every hour of pain in the\n * fleet's toolbelt history was those two lists disagreeing — a verb present\n * in one target and absent from the other shipped green and failed in\n * production (hardware-agent #10155 class). This module turns that drift\n * class into a red test: spawn the program, read its real surface, diff it\n * against the manifest, and name every disagreement.\n *\n * Substrate-free by design: Node builtins only, no test-framework\n * dependency, no MCP SDK. `probeStdioToolProgram` speaks just enough\n * JSON-RPC (initialize → initialized → tools/list, replies matched by id,\n * notifications ignored) for a zero-dependency embedded program; the diff\n * and the assert are pure functions any runner (vitest, node:test, a tsx\n * script) can call.\n *\n * Canonical consumer shape:\n *\n * ```ts\n * import { assertToolbeltParity, probeStdioToolProgram } from '@tangle-network/agent-app/toolbelt'\n *\n * const probed = await probeStdioToolProgram({ program: programPath, env })\n * assertToolbeltParity(TOOLBELT, probed.tools) // throws with the named diff\n * ```\n */\nimport { spawn } from 'node:child_process'\n\n/** One authored tool in the product's manifest — the ONE source of truth the\n * generated program and every derived surface (allowlists, prompt tool\n * tables, dashboards) must agree with. */\nexport interface ToolbeltManifestTool {\n readonly name: string\n /** AAA-standard description (what / example / when NOT). Parity requires the\n * program to serve it byte-identical — truncation at a bundle boundary is\n * drift, not formatting. */\n readonly description: string\n /** JSON Schema for the tool's input. Compared structurally (key order\n * insensitive) when either side declares one. */\n readonly inputSchema?: unknown\n /** MCP tool annotations (readOnlyHint, …). Compared structurally when the\n * manifest declares them. */\n readonly annotations?: unknown\n /** Product-defined transport tag (`pure` | `http` | …). Not part of the\n * wire surface; carried so derived surfaces can key off the manifest. */\n readonly transport?: string\n}\n\n/** A tool as the spawned program actually listed it. */\nexport interface ProbedTool {\n readonly name: string\n readonly description?: string\n readonly inputSchema?: unknown\n readonly annotations?: unknown\n}\n\n/** What `probeStdioToolProgram` saw. `serverInfo`/`raw` are included so a\n * failed probe can name the layer (the diagnosability rule: never swallow). */\nexport interface ToolProgramProbe {\n readonly tools: readonly ProbedTool[]\n readonly initializeReply: Record<string, unknown> | null\n}\n\nexport interface ProbeStdioToolProgramOptions {\n /** Path to the program to spawn. Spawned with the current Node executable. */\n readonly program: string\n /** Extra argv after the program path. */\n readonly args?: readonly string[]\n /** Environment for the child. Defaults to `process.env`. */\n readonly env?: NodeJS.ProcessEnv\n /** Working directory for the child. */\n readonly cwd?: string\n /** Wall-clock ceiling for the whole probe. Default 15s. */\n readonly timeoutMs?: number\n}\n\n/** Spawn the embedded tool program and read its REAL tool surface. */\nexport function probeStdioToolProgram(options: ProbeStdioToolProgramOptions): Promise<ToolProgramProbe> {\n const timeoutMs = options.timeoutMs ?? 15_000\n return new Promise<ToolProgramProbe>((resolve, reject) => {\n const child = spawn(process.execPath, [options.program, ...(options.args ?? [])], {\n env: options.env ?? process.env,\n cwd: options.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n let stdout = ''\n let stderr = ''\n let settled = false\n let initializeReply: Record<string, unknown> | null = null\n const lines: string[] = []\n\n const finish = (run: () => void) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n try { child.kill() } catch { /* already gone */ }\n run()\n }\n\n const timer = setTimeout(\n () => finish(() => reject(new Error(\n `tool program probe timed out after ${timeoutMs}ms waiting for tools/list. ` +\n `stderr so far: ${stderr.trim().slice(0, 2000) || '(empty)'}; ` +\n `stdout so far: ${stdout.trim().slice(0, 2000) || '(empty)'}`,\n ))),\n timeoutMs,\n )\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => {\n stdout += chunk\n let index: number\n while ((index = stdout.indexOf('\\n')) >= 0) {\n const line = stdout.slice(0, index).trim()\n stdout = stdout.slice(index + 1)\n if (!line) continue\n lines.push(line)\n let message: Record<string, unknown>\n try {\n message = JSON.parse(line) as Record<string, unknown>\n } catch {\n continue // a banner line, not JSON-RPC\n }\n if (message.method !== undefined) continue // notification from server\n if (message.id === 1) initializeReply = message.result as Record<string, unknown> ?? null\n if (message.id === 2 && message.result !== undefined && message.error === undefined) {\n const rawTools = (message.result as { tools?: unknown }).tools\n const tools: ProbedTool[] = Array.isArray(rawTools)\n ? rawTools.filter((t): t is Record<string, unknown> => !!t && typeof t === 'object' && typeof (t as { name?: unknown }).name === 'string')\n .map((t) => {\n const tool = t as unknown as { name: string; description?: string; inputSchema?: unknown; annotations?: unknown }\n return {\n name: tool.name,\n ...(tool.description !== undefined ? { description: tool.description } : {}),\n ...(tool.inputSchema !== undefined ? { inputSchema: tool.inputSchema } : {}),\n ...(tool.annotations !== undefined ? { annotations: tool.annotations } : {}),\n }\n })\n : []\n finish(() => resolve({ tools, initializeReply }))\n } else if (message.id === 2 && message.error !== undefined) {\n finish(() => reject(new Error(\n `tool program refused tools/list: ${JSON.stringify(message.error)}`,\n )))\n }\n }\n })\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => { stderr += chunk })\n child.on('error', (error) => finish(() => reject(new Error(\n `tool program probe failed to spawn ${options.program}: ${error.message}`,\n ))))\n child.on('exit', (code, signal) => finish(() => reject(new Error(\n `tool program exited before answering tools/list (code ${code}${signal ? `, signal ${signal}` : ''}). ` +\n `stderr: ${stderr.trim().slice(0, 2000) || '(empty)'}`,\n ))))\n\n // Minimal MCP handshake: initialize → initialized → tools/list. Replies\n // are matched by id; a program that never replies to initialize still\n // resolves the probe when its tools/list reply arrives.\n const send = (payload: unknown) => { try { child.stdin.write(JSON.stringify(payload) + '\\n') } catch { /* closed; exit handler reports */ } }\n send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'toolbelt-parity', version: '0.0.0' } } })\n send({ jsonrpc: '2.0', method: 'notifications/initialized' })\n send({ jsonrpc: '2.0', id: 2, method: 'tools/list' })\n })\n}\n\n/** Structural equality with sorted keys — two JSON schemas are the same\n * contract regardless of key order. */\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null'\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(',')}}`\n}\n\n/** Field-level drift between the manifest and the program's real surface. */\nexport interface ToolbeltFieldDrift {\n readonly name: string\n readonly manifest: unknown\n readonly program: unknown\n}\n\n/** The named diff. Every array is sorted; empty arrays mean agreement. */\nexport interface ToolbeltParityDiff {\n readonly ok: boolean\n /** Manifest tools the program did not list (the #10155 class: the verb\n * exists in the manifest, absent from the running surface). */\n readonly missingFromProgram: readonly string[]\n /** Tools the program listed that no manifest entry owns. */\n readonly unknownToManifest: readonly string[]\n /** Tools whose served description is not byte-identical to the manifest. */\n readonly descriptionDrift: readonly ToolbeltFieldDrift[]\n /** Tools whose served input schema differs structurally from the manifest. */\n readonly schemaDrift: readonly ToolbeltFieldDrift[]\n /** Tools whose served annotations differ structurally from the manifest. */\n readonly annotationDrift: readonly ToolbeltFieldDrift[]\n}\n\n/** Diff a spawned program's real surface against the authored manifest. */\nexport function toolbeltParityDiff(\n manifest: readonly ToolbeltManifestTool[],\n listed: readonly ProbedTool[],\n): ToolbeltParityDiff {\n const byName = new Map(manifest.map((tool) => [tool.name, tool]))\n const listedByName = new Map(listed.map((tool) => [tool.name, tool]))\n const missingFromProgram = manifest\n .filter((tool) => !listedByName.has(tool.name))\n .map((tool) => tool.name)\n .sort()\n const unknownToManifest = listed\n .filter((tool) => !byName.has(tool.name))\n .map((tool) => tool.name)\n .sort()\n const descriptionDrift: ToolbeltFieldDrift[] = []\n const schemaDrift: ToolbeltFieldDrift[] = []\n const annotationDrift: ToolbeltFieldDrift[] = []\n for (const tool of manifest) {\n const served = listedByName.get(tool.name)\n if (!served) continue\n if (served.description !== tool.description) {\n descriptionDrift.push({ name: tool.name, manifest: tool.description, program: served.description ?? null })\n }\n const manifestSchema = tool.inputSchema\n if (manifestSchema !== undefined || served.inputSchema !== undefined) {\n if (stableStringify(manifestSchema) !== stableStringify(served.inputSchema)) {\n schemaDrift.push({ name: tool.name, manifest: manifestSchema ?? null, program: served.inputSchema ?? null })\n }\n }\n const manifestAnnotations = tool.annotations\n if (manifestAnnotations !== undefined || served.annotations !== undefined) {\n if (stableStringify(manifestAnnotations) !== stableStringify(served.annotations)) {\n annotationDrift.push({ name: tool.name, manifest: manifestAnnotations ?? null, program: served.annotations ?? null })\n }\n }\n }\n const ok = missingFromProgram.length === 0\n && unknownToManifest.length === 0\n && descriptionDrift.length === 0\n && schemaDrift.length === 0\n && annotationDrift.length === 0\n return {\n ok,\n missingFromProgram,\n unknownToManifest,\n descriptionDrift,\n schemaDrift,\n annotationDrift,\n }\n}\n\n/** Render a diff as one actionable report — every drift named, never a bare count. */\nexport function formatToolbeltParityDiff(diff: ToolbeltParityDiff): string {\n if (diff.ok) return 'toolbelt parity: the program is the manifest'\n const lines = ['toolbelt parity FAILED — the program and the manifest disagree:']\n if (diff.missingFromProgram.length > 0) {\n lines.push(` missing from the program (in the manifest, NOT served): ${diff.missingFromProgram.join(', ')}`)\n }\n if (diff.unknownToManifest.length > 0) {\n lines.push(` unknown to the manifest (served, NOT authored): ${diff.unknownToManifest.join(', ')}`)\n }\n for (const drift of diff.descriptionDrift) {\n lines.push(` description drift on \"${drift.name}\":`)\n lines.push(` manifest: ${JSON.stringify(drift.manifest)}`)\n lines.push(` program: ${JSON.stringify(drift.program)}`)\n }\n for (const drift of diff.schemaDrift) {\n lines.push(` input-schema drift on \"${drift.name}\":`)\n lines.push(` manifest: ${stableStringify(drift.manifest)}`)\n lines.push(` program: ${stableStringify(drift.program)}`)\n }\n for (const drift of diff.annotationDrift) {\n lines.push(` annotation drift on \"${drift.name}\":`)\n lines.push(` manifest: ${stableStringify(drift.manifest)}`)\n lines.push(` program: ${stableStringify(drift.program)}`)\n }\n lines.push(' Fix the ONE manifest (or the generator that derives the program from it) — never patch a second list.')\n return lines.join('\\n')\n}\n\n/** Thrown by {@link assertToolbeltParity} with the full formatted diff. */\nexport class ToolbeltParityError extends Error {\n readonly diff: ToolbeltParityDiff\n constructor(diff: ToolbeltParityDiff) {\n super(formatToolbeltParityDiff(diff))\n this.name = 'ToolbeltParityError'\n this.diff = diff\n }\n}\n\n/** Assert parity: same names, byte-identical descriptions, structurally equal\n * schemas and annotations. Throws {@link ToolbeltParityError} with every\n * disagreement named — a red build, not a production silence. */\nexport function assertToolbeltParity(\n manifest: readonly ToolbeltManifestTool[],\n listed: readonly ProbedTool[],\n): void {\n const diff = toolbeltParityDiff(manifest, listed)\n if (!diff.ok) throw new ToolbeltParityError(diff)\n}\n"],"mappings":";AA4BA,SAAS,aAAa;AAmDf,SAAS,sBAAsB,SAAkE;AACtG,QAAM,YAAY,QAAQ,aAAa;AACvC,SAAO,IAAI,QAA0B,CAAC,SAAS,WAAW;AACxD,UAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,QAAQ,SAAS,GAAI,QAAQ,QAAQ,CAAC,CAAE,GAAG;AAAA,MAChF,KAAK,QAAQ,OAAO,QAAQ;AAAA,MAC5B,KAAK,QAAQ;AAAA,MACb,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AACD,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI,UAAU;AACd,QAAI,kBAAkD;AACtD,UAAM,QAAkB,CAAC;AAEzB,UAAM,SAAS,CAAC,QAAoB;AAClC,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,KAAK;AAClB,UAAI;AAAE,cAAM,KAAK;AAAA,MAAE,QAAQ;AAAA,MAAqB;AAChD,UAAI;AAAA,IACN;AAEA,UAAM,QAAQ;AAAA,MACZ,MAAM,OAAO,MAAM,OAAO,IAAI;AAAA,QAC5B,sCAAsC,SAAS,6CAC7B,OAAO,KAAK,EAAE,MAAM,GAAG,GAAI,KAAK,SAAS,oBACzC,OAAO,KAAK,EAAE,MAAM,GAAG,GAAI,KAAK,SAAS;AAAA,MAC7D,CAAC,CAAC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,YAAY,MAAM;AAC/B,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACzC,gBAAU;AACV,UAAI;AACJ,cAAQ,QAAQ,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC1C,cAAM,OAAO,OAAO,MAAM,GAAG,KAAK,EAAE,KAAK;AACzC,iBAAS,OAAO,MAAM,QAAQ,CAAC;AAC/B,YAAI,CAAC,KAAM;AACX,cAAM,KAAK,IAAI;AACf,YAAI;AACJ,YAAI;AACF,oBAAU,KAAK,MAAM,IAAI;AAAA,QAC3B,QAAQ;AACN;AAAA,QACF;AACA,YAAI,QAAQ,WAAW,OAAW;AAClC,YAAI,QAAQ,OAAO,EAAG,mBAAkB,QAAQ,UAAqC;AACrF,YAAI,QAAQ,OAAO,KAAK,QAAQ,WAAW,UAAa,QAAQ,UAAU,QAAW;AACnF,gBAAM,WAAY,QAAQ,OAA+B;AACzD,gBAAM,QAAsB,MAAM,QAAQ,QAAQ,IAC9C,SAAS,OAAO,CAAC,MAAoC,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,OAAQ,EAAyB,SAAS,QAAQ,EACtI,IAAI,CAAC,MAAM;AACV,kBAAM,OAAO;AACb,mBAAO;AAAA,cACL,MAAM,KAAK;AAAA,cACX,GAAI,KAAK,gBAAgB,SAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,cAC1E,GAAI,KAAK,gBAAgB,SAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,cAC1E,GAAI,KAAK,gBAAgB,SAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,YAC5E;AAAA,UACF,CAAC,IACD,CAAC;AACL,iBAAO,MAAM,QAAQ,EAAE,OAAO,gBAAgB,CAAC,CAAC;AAAA,QAClD,WAAW,QAAQ,OAAO,KAAK,QAAQ,UAAU,QAAW;AAC1D,iBAAO,MAAM,OAAO,IAAI;AAAA,YACtB,oCAAoC,KAAK,UAAU,QAAQ,KAAK,CAAC;AAAA,UACnE,CAAC,CAAC;AAAA,QACJ;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,OAAO,YAAY,MAAM;AAC/B,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AAAE,gBAAU;AAAA,IAAM,CAAC;AAC9D,UAAM,GAAG,SAAS,CAAC,UAAU,OAAO,MAAM,OAAO,IAAI;AAAA,MACnD,sCAAsC,QAAQ,OAAO,KAAK,MAAM,OAAO;AAAA,IACzE,CAAC,CAAC,CAAC;AACH,UAAM,GAAG,QAAQ,CAAC,MAAM,WAAW,OAAO,MAAM,OAAO,IAAI;AAAA,MACzD,yDAAyD,IAAI,GAAG,SAAS,YAAY,MAAM,KAAK,EAAE,cACvF,OAAO,KAAK,EAAE,MAAM,GAAG,GAAI,KAAK,SAAS;AAAA,IACtD,CAAC,CAAC,CAAC;AAKH,UAAM,OAAO,CAAC,YAAqB;AAAE,UAAI;AAAE,cAAM,MAAM,MAAM,KAAK,UAAU,OAAO,IAAI,IAAI;AAAA,MAAE,QAAQ;AAAA,MAAqC;AAAA,IAAE;AAC5I,SAAK,EAAE,SAAS,OAAO,IAAI,GAAG,QAAQ,cAAc,QAAQ,EAAE,iBAAiB,cAAc,cAAc,CAAC,GAAG,YAAY,EAAE,MAAM,mBAAmB,SAAS,QAAQ,EAAE,EAAE,CAAC;AAC5K,SAAK,EAAE,SAAS,OAAO,QAAQ,4BAA4B,CAAC;AAC5D,SAAK,EAAE,SAAS,OAAO,IAAI,GAAG,QAAQ,aAAa,CAAC;AAAA,EACtD,CAAC;AACH;AAIA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK,KAAK;AACjF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,eAAe,EAAE,KAAK,GAAG,CAAC;AACzE,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EACjC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AAClD,SAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC5F;AA0BO,SAAS,mBACd,UACA,QACoB;AACpB,QAAM,SAAS,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAChE,QAAM,eAAe,IAAI,IAAI,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AACpE,QAAM,qBAAqB,SACxB,OAAO,CAAC,SAAS,CAAC,aAAa,IAAI,KAAK,IAAI,CAAC,EAC7C,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK;AACR,QAAM,oBAAoB,OACvB,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,KAAK,IAAI,CAAC,EACvC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK;AACR,QAAM,mBAAyC,CAAC;AAChD,QAAM,cAAoC,CAAC;AAC3C,QAAM,kBAAwC,CAAC;AAC/C,aAAW,QAAQ,UAAU;AAC3B,UAAM,SAAS,aAAa,IAAI,KAAK,IAAI;AACzC,QAAI,CAAC,OAAQ;AACb,QAAI,OAAO,gBAAgB,KAAK,aAAa;AAC3C,uBAAiB,KAAK,EAAE,MAAM,KAAK,MAAM,UAAU,KAAK,aAAa,SAAS,OAAO,eAAe,KAAK,CAAC;AAAA,IAC5G;AACA,UAAM,iBAAiB,KAAK;AAC5B,QAAI,mBAAmB,UAAa,OAAO,gBAAgB,QAAW;AACpE,UAAI,gBAAgB,cAAc,MAAM,gBAAgB,OAAO,WAAW,GAAG;AAC3E,oBAAY,KAAK,EAAE,MAAM,KAAK,MAAM,UAAU,kBAAkB,MAAM,SAAS,OAAO,eAAe,KAAK,CAAC;AAAA,MAC7G;AAAA,IACF;AACA,UAAM,sBAAsB,KAAK;AACjC,QAAI,wBAAwB,UAAa,OAAO,gBAAgB,QAAW;AACzE,UAAI,gBAAgB,mBAAmB,MAAM,gBAAgB,OAAO,WAAW,GAAG;AAChF,wBAAgB,KAAK,EAAE,MAAM,KAAK,MAAM,UAAU,uBAAuB,MAAM,SAAS,OAAO,eAAe,KAAK,CAAC;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,mBAAmB,WAAW,KACpC,kBAAkB,WAAW,KAC7B,iBAAiB,WAAW,KAC5B,YAAY,WAAW,KACvB,gBAAgB,WAAW;AAChC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAGO,SAAS,yBAAyB,MAAkC;AACzE,MAAI,KAAK,GAAI,QAAO;AACpB,QAAM,QAAQ,CAAC,sEAAiE;AAChF,MAAI,KAAK,mBAAmB,SAAS,GAAG;AACtC,UAAM,KAAK,6DAA6D,KAAK,mBAAmB,KAAK,IAAI,CAAC,EAAE;AAAA,EAC9G;AACA,MAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,UAAM,KAAK,qDAAqD,KAAK,kBAAkB,KAAK,IAAI,CAAC,EAAE;AAAA,EACrG;AACA,aAAW,SAAS,KAAK,kBAAkB;AACzC,UAAM,KAAK,2BAA2B,MAAM,IAAI,IAAI;AACpD,UAAM,KAAK,iBAAiB,KAAK,UAAU,MAAM,QAAQ,CAAC,EAAE;AAC5D,UAAM,KAAK,iBAAiB,KAAK,UAAU,MAAM,OAAO,CAAC,EAAE;AAAA,EAC7D;AACA,aAAW,SAAS,KAAK,aAAa;AACpC,UAAM,KAAK,4BAA4B,MAAM,IAAI,IAAI;AACrD,UAAM,KAAK,iBAAiB,gBAAgB,MAAM,QAAQ,CAAC,EAAE;AAC7D,UAAM,KAAK,iBAAiB,gBAAgB,MAAM,OAAO,CAAC,EAAE;AAAA,EAC9D;AACA,aAAW,SAAS,KAAK,iBAAiB;AACxC,UAAM,KAAK,0BAA0B,MAAM,IAAI,IAAI;AACnD,UAAM,KAAK,iBAAiB,gBAAgB,MAAM,QAAQ,CAAC,EAAE;AAC7D,UAAM,KAAK,iBAAiB,gBAAgB,MAAM,OAAO,CAAC,EAAE;AAAA,EAC9D;AACA,QAAM,KAAK,8GAAyG;AACpH,SAAO,MAAM,KAAK,IAAI;AACxB;AAGO,IAAM,sBAAN,cAAkC,MAAM;AAAA,EACpC;AAAA,EACT,YAAY,MAA0B;AACpC,UAAM,yBAAyB,IAAI,CAAC;AACpC,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAKO,SAAS,qBACd,UACA,QACM;AACN,QAAM,OAAO,mBAAmB,UAAU,MAAM;AAChD,MAAI,CAAC,KAAK,GAAI,OAAM,IAAI,oBAAoB,IAAI;AAClD;","names":[]}
@@ -143,7 +143,7 @@ import {
143
143
  withoutRecordGridCreated,
144
144
  withoutRecordGridRemoved,
145
145
  withoutRecordGridUpdate
146
- } from "../chunk-6ZUVYAKB.js";
146
+ } from "../chunk-6O2NQ7WD.js";
147
147
  import {
148
148
  SessionHistoryPanel,
149
149
  formatSessionTimestamp,
@@ -155,20 +155,6 @@ import {
155
155
  MENTION_PILL_CLASS
156
156
  } from "../chunk-3HUFJ5LO.js";
157
157
  import "../chunk-FBVLEGEG.js";
158
- import {
159
- WorkspaceInitial,
160
- WorkspaceSwitcher
161
- } from "../chunk-UDLA3NGY.js";
162
- import "../chunk-A2GG4D4A.js";
163
- import {
164
- tabTerminalConnectionId,
165
- useSandboxTerminalConnection
166
- } from "../chunk-E4AY62T2.js";
167
- import {
168
- AGENT_PROFILE_EDITOR_SECTIONS,
169
- AgentProfileEditor,
170
- AgentProfileRegistryError
171
- } from "../chunk-3RHAF2P5.js";
172
158
  import {
173
159
  EvidenceLineageTable,
174
160
  ExceptionList,
@@ -182,9 +168,6 @@ import {
182
168
  workProductStatusLabel,
183
169
  workProductStatusTone
184
170
  } from "../chunk-Y6PRDUFJ.js";
185
- import {
186
- parseReviewQueueItem
187
- } from "../chunk-GEYACSFW.js";
188
171
  import {
189
172
  ChatComposer,
190
173
  ComposerModeControls,
@@ -199,7 +182,21 @@ import {
199
182
  useDictation
200
183
  } from "../chunk-BBHVV37T.js";
201
184
  import "../chunk-L7MB2LLM.js";
185
+ import {
186
+ WorkspaceInitial,
187
+ WorkspaceSwitcher
188
+ } from "../chunk-UDLA3NGY.js";
189
+ import "../chunk-A2GG4D4A.js";
190
+ import {
191
+ tabTerminalConnectionId,
192
+ useSandboxTerminalConnection
193
+ } from "../chunk-E4AY62T2.js";
202
194
  import "../chunk-SJWIZT7B.js";
195
+ import {
196
+ AGENT_PROFILE_EDITOR_SECTIONS,
197
+ AgentProfileEditor,
198
+ AgentProfileRegistryError
199
+ } from "../chunk-3RHAF2P5.js";
203
200
  import {
204
201
  AgentSessionControls,
205
202
  AgentSettingsPopover,
@@ -230,13 +227,16 @@ import {
230
227
  usePopover
231
228
  } from "../chunk-TJ4DYKF2.js";
232
229
  import {
233
- ProviderLogo
234
- } from "../chunk-RASGKEAL.js";
235
- import "../chunk-LN5RBVGP.js";
230
+ parseReviewQueueItem
231
+ } from "../chunk-GEYACSFW.js";
236
232
  import {
237
233
  ReviewFeedbackForm
238
234
  } from "../chunk-ATQQCG4I.js";
239
235
  import "../chunk-WSEXFTN4.js";
236
+ import {
237
+ ProviderLogo
238
+ } from "../chunk-RASGKEAL.js";
239
+ import "../chunk-LN5RBVGP.js";
240
240
  import "../chunk-FQYAJYPW.js";
241
241
  import {
242
242
  ATTACHMENT_ACCEPT
@@ -252,8 +252,7 @@ import {
252
252
  isChatAttachmentPart,
253
253
  mentionInputToPart,
254
254
  mentionPartsFromMessageParts
255
- } from "../chunk-YR6TZ777.js";
256
- import "../chunk-ZVEEWGDK.js";
255
+ } from "../chunk-TNWDYAFX.js";
257
256
  import {
258
257
  DISPATCH_MAX_MEDIA_PARTS,
259
258
  DISPATCH_MAX_PARTS,
@@ -277,11 +276,11 @@ import {
277
276
  mentionKindForPath,
278
277
  settleTurnResponse
279
278
  } from "../chunk-YHRWZZJN.js";
279
+ import "../chunk-ZVEEWGDK.js";
280
280
  import "../chunk-TXD5HXLE.js";
281
281
  import {
282
282
  attachmentPartKey
283
- } from "../chunk-XNKLQG26.js";
284
- import "../chunk-LQYIBL3G.js";
283
+ } from "../chunk-ZGUXI5SI.js";
285
284
  import {
286
285
  INTERACTION_CANCEL_EVENT,
287
286
  INTERACTION_EVENT,
@@ -307,6 +306,7 @@ import {
307
306
  questionInteractionContentSignature,
308
307
  stampInteractionAnswers
309
308
  } from "../chunk-6VQCFJWP.js";
309
+ import "../chunk-LQYIBL3G.js";
310
310
  export {
311
311
  AGENT_PROFILE_EDITOR_SECTIONS,
312
312
  ATTACHMENT_ACCEPT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.60.180",
3
+ "version": "0.60.182",
4
4
  "packageManager": "pnpm@11.24.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -124,11 +124,21 @@
124
124
  "import": "./dist/skills/index.js",
125
125
  "default": "./dist/skills/index.js"
126
126
  },
127
+ "./skills/marketplace-drizzle": {
128
+ "types": "./dist/skills/marketplace-drizzle.d.ts",
129
+ "import": "./dist/skills/marketplace-drizzle.js",
130
+ "default": "./dist/skills/marketplace-drizzle.js"
131
+ },
127
132
  "./skills-placement": {
128
133
  "types": "./dist/skills-placement/index.d.ts",
129
134
  "import": "./dist/skills-placement/index.js",
130
135
  "default": "./dist/skills-placement/index.js"
131
136
  },
137
+ "./toolbelt": {
138
+ "types": "./dist/toolbelt/index.d.ts",
139
+ "import": "./dist/toolbelt/index.js",
140
+ "default": "./dist/toolbelt/index.js"
141
+ },
132
142
  "./profile": {
133
143
  "types": "./dist/profile/index.d.ts",
134
144
  "import": "./dist/profile/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/teams/members-api.ts"],"sourcesContent":["/**\n * Framework-neutral members API for the teams module: the invite / list /\n * update-role / remove / accept-invite logic, lifted out of any one app's route\n * file. Each app mounts these in its own route with its own auth — the handlers\n * take an already-authenticated `actor`, the parsed inputs, the `db` + `tables`\n * from `createTeamTables`, the product's user + workspace tables, and the\n * workspace-access API from `createWorkspaceAccess`. They return web-standard\n * `Response`s (available in Workers, Node 18+, Deno, browsers), so\n * \"framework-neutral\" is literal: no Remix/React-Router/Express import anywhere.\n *\n * Two OPTIONAL seams an app wires only if it needs them:\n * - `enforceSeat` — billing/seat-limit gate, called at invite time only when\n * the invite would consume a NEW billable seat. An app without seat billing\n * passes nothing and seats are never checked.\n * - `memberSyncSeam` — fire-and-forget propagation of membership changes to a\n * sandbox/external system (add on accept, role on update, remove on\n * delete). An app without sandbox sync passes nothing. Fail-soft by\n * contract: a thrown sync is caught and never blocks the DB mutation.\n *\n * Imports `drizzle-orm`, so this is a subpath, never re-exported from root.\n */\n\nimport { and, eq, isNull } from 'drizzle-orm'\nimport { INVITATION_EMAIL_HINT, isInvitationEmail } from './invitations'\nimport {\n type AssignableWorkspaceRole,\n type WorkspaceRole,\n canManageWorkspaceMemberRole,\n hasWorkspaceRole,\n isAssignableWorkspaceRole,\n organizationRoleGrantsWorkspaceOwner,\n} from './roles'\nimport { generateInviteToken } from './invite'\nimport type { TeamDatabase, WorkspaceAccessApi } from './drizzle/access'\nimport type { TeamParentTable, TeamTables } from './drizzle/schema'\n\n/** The authenticated caller — apps resolve this from their own session layer. */\nexport interface MembersApiActor {\n id: string\n email?: string | null\n}\n\n/**\n * The product's user table, narrowed to the columns the member queries read.\n * Adopters pass their real drizzle user table.\n */\nexport interface UserLookupTable {\n id: any\n name: any\n email: any\n}\n\n/**\n * The product's workspace table, narrowed to the columns the member queries\n * read. The handlers join it to resolve a workspace's organization (the same\n * table passed to createTeamTables as workspaceTable).\n */\nexport interface WorkspaceLookupTable {\n id: any\n organizationId: any\n}\n\n/**\n * Optional billing seat gate. The seam resolves the count input itself (it\n * owns the plan/seat model) and throws when over the limit; the handler turns a\n * thrown `SeatLimitError` into a 402. Called only when an invite would consume\n * a NEW seat (invitee is not already an org member and has no pending org\n * invite) — the same guard gtm uses, so the seam never fires on a no-op invite.\n */\nexport interface EnforceSeatSeam {\n (input: { actorId: string; organizationId: string }): Promise<void> | void\n}\n\n/** Thrown by an `enforceSeat` seam to deny an invite; serialized to a 402. */\nexport class SeatLimitError extends Error {\n readonly status: number\n readonly capability?: string\n readonly requiredPlan?: string\n constructor(message: string, opts: { status?: number; capability?: string; requiredPlan?: string } = {}) {\n super(message)\n this.name = 'SeatLimitError'\n this.status = opts.status ?? 402\n this.capability = opts.capability\n this.requiredPlan = opts.requiredPlan\n }\n}\n\n/**\n * Optional membership-change propagation to an external system (e.g. sandbox).\n * Every method is fire-and-forget and fail-soft: the handler awaits nothing and\n * swallows rejections, so an unavailable downstream never blocks the mutation.\n * Each fires only for members with a real `userId` (never email-only invites).\n */\nexport interface MemberSyncSeam {\n add?(input: { workspaceId: string; userId: string; role: WorkspaceRole }): Promise<void> | void\n role?(input: { workspaceId: string; userId: string; role: WorkspaceRole }): Promise<void> | void\n remove?(input: { workspaceId: string; userId: string }): Promise<void> | void\n}\n\n/** Define configuration options for managing team members and workspace access APIs */\nexport interface MembersApiOptions {\n db: TeamDatabase\n tables: TeamTables\n /** The product's user table (FK target passed to createTeamTables). */\n userTable: TeamParentTable & UserLookupTable\n /** The product's workspace table (FK target passed to createTeamTables). */\n workspaceTable: TeamParentTable & WorkspaceLookupTable\n /** Workspace-access API from createWorkspaceAccess — RBAC stays one source. */\n access: Pick<WorkspaceAccessApi, 'getWorkspaceAccess'>\n enforceSeat?: EnforceSeatSeam\n memberSyncSeam?: MemberSyncSeam\n}\n\n/** Define the structure of a workspace member entry with identification, role, and status details */\nexport interface MemberListEntry {\n id: string\n userId: string | null\n organizationMemberId: string | null\n role: WorkspaceRole\n name: string | null\n email: string | null\n invitedAt: Date | number | null\n acceptedAt: Date | number | null\n inherited: boolean\n}\n\n/**\n * Build the members API bound to one product's db/tables/access. Returns five\n * handlers; an app maps its route methods onto them (GET→list, POST→invite,\n * PATCH→updateRole, DELETE→remove; accept on its own route).\n */\nexport function createMembersApi(opts: MembersApiOptions) {\n const { db, tables, userTable, workspaceTable, access, enforceSeat, memberSyncSeam } = opts\n const { organizations, organizationMembers, workspaceMembers } = tables\n const users = userTable\n const workspaces = workspaceTable\n\n function fireSync(op: () => Promise<void> | void) {\n try {\n Promise.resolve(op()).catch(() => {})\n } catch {\n // seam threw synchronously — swallow; sync is best-effort by contract.\n }\n }\n\n async function listMembers(input: { workspaceId: string; actor: MembersApiActor }): Promise<Response> {\n const accessRow = await access.getWorkspaceAccess(input.workspaceId, input.actor.id)\n if (!accessRow) return Response.json({ error: 'Workspace not found' }, { status: 404 })\n\n const organizationId = (accessRow.workspace as { organizationId: string }).organizationId\n\n const [projectMembers, orgAdmins] = await Promise.all([\n db\n .select({\n id: workspaceMembers.id,\n organizationMemberId: workspaceMembers.organizationMemberId,\n userId: workspaceMembers.userId,\n role: workspaceMembers.role,\n invitedAt: workspaceMembers.invitedAt,\n acceptedAt: workspaceMembers.acceptedAt,\n inviteEmail: workspaceMembers.inviteEmail,\n userName: users.name,\n userEmail: users.email,\n })\n .from(workspaceMembers)\n .leftJoin(users, eq(users.id, workspaceMembers.userId))\n .where(eq(workspaceMembers.workspaceId, input.workspaceId)),\n db\n .select({\n id: organizationMembers.id,\n userId: organizationMembers.userId,\n orgRole: organizationMembers.role,\n userName: users.name,\n userEmail: users.email,\n createdAt: organizationMembers.createdAt,\n })\n .from(organizationMembers)\n .innerJoin(users, eq(users.id, organizationMembers.userId))\n .where(eq(organizationMembers.organizationId, organizationId)),\n ])\n\n const explicitOrgMemberIds = new Set(\n projectMembers.map((m: any) => m.organizationMemberId).filter(Boolean),\n )\n const members: MemberListEntry[] = [\n ...orgAdmins\n .filter((m: any) => organizationRoleGrantsWorkspaceOwner(m.orgRole) && !explicitOrgMemberIds.has(m.id))\n .map((m: any) => ({\n id: `org:${m.id}`,\n userId: m.userId,\n organizationMemberId: m.id,\n role: 'owner' as WorkspaceRole,\n name: m.userName,\n email: m.userEmail,\n invitedAt: m.createdAt,\n acceptedAt: m.createdAt,\n inherited: true,\n })),\n ...projectMembers.map((m: any) => ({\n id: m.id,\n userId: m.userId,\n organizationMemberId: m.organizationMemberId,\n role: m.role as WorkspaceRole,\n name: m.userName,\n email: m.userEmail ?? m.inviteEmail,\n invitedAt: m.invitedAt,\n acceptedAt: m.acceptedAt,\n inherited: false,\n })),\n ]\n\n return Response.json({ members, currentRole: accessRow.role, organizationId })\n }\n\n async function inviteMember(input: {\n workspaceId: string\n actor: MembersApiActor\n email?: string\n role?: string\n }): Promise<Response> {\n if (!input.email) return Response.json({ error: 'Missing email' }, { status: 400 })\n if (!isInvitationEmail(input.email)) return Response.json({ error: INVITATION_EMAIL_HINT }, { status: 400 })\n const requestedRole = input.role ?? 'editor'\n if (!isAssignableWorkspaceRole(requestedRole)) {\n return Response.json({ error: 'Invalid role. Must be viewer, editor, or admin.' }, { status: 400 })\n }\n const assignRole: AssignableWorkspaceRole = requestedRole\n const accessRow = await access.getWorkspaceAccess(input.workspaceId, input.actor.id, 'admin')\n if (!accessRow) return Response.json({ error: 'Workspace not found' }, { status: 404 })\n if (!hasWorkspaceRole(accessRow.role, assignRole)) {\n return Response.json({ error: 'Cannot assign a role higher than your own' }, { status: 403 })\n }\n\n const organizationId = (accessRow.workspace as { organizationId: string }).organizationId\n const normalizedEmail = input.email.toLowerCase().trim()\n const invitee = await getUserByEmail(normalizedEmail)\n const existingOrgMember = invitee ? await getOrganizationMember(organizationId, invitee.id) : null\n\n if (organizationRoleGrantsWorkspaceOwner(existingOrgMember?.role)) {\n return Response.json({ error: 'Organization admins already have project access' }, { status: 409 })\n }\n\n const existingInvite = await findExistingProjectInvite(input.workspaceId, normalizedEmail, invitee?.id)\n if (existingInvite) {\n return Response.json({ error: 'This collaborator is already invited to this project' }, { status: 409 })\n }\n\n if (enforceSeat && !existingOrgMember && !(await hasPendingOrgInvite(organizationId, normalizedEmail))) {\n try {\n await enforceSeat({ actorId: input.actor.id, organizationId })\n } catch (err) {\n if (err instanceof SeatLimitError) {\n return Response.json(\n { error: err.message, capability: err.capability, requiredPlan: err.requiredPlan },\n { status: err.status },\n )\n }\n throw err\n }\n }\n\n const token = generateInviteToken()\n const [member] = await db\n .insert(workspaceMembers)\n .values({\n workspaceId: input.workspaceId,\n organizationMemberId: existingOrgMember?.id ?? null,\n userId: invitee?.id ?? null,\n role: assignRole,\n invitedBy: input.actor.id,\n inviteEmail: normalizedEmail,\n inviteToken: token,\n })\n .returning()\n\n return Response.json({ member, inviteToken: token })\n }\n\n async function updateMemberRole(input: {\n workspaceId: string\n actor: MembersApiActor\n memberId?: string\n role?: string\n }): Promise<Response> {\n if (!input.memberId || !input.role) {\n return Response.json({ error: 'Missing memberId or role' }, { status: 400 })\n }\n if (input.memberId.startsWith('org:')) {\n return Response.json({ error: 'Organization owner/admin project access is managed at the organization level' }, { status: 403 })\n }\n if (!isAssignableWorkspaceRole(input.role)) {\n return Response.json({ error: 'Invalid role' }, { status: 400 })\n }\n\n const accessRow = await access.getWorkspaceAccess(input.workspaceId, input.actor.id, 'admin')\n if (!accessRow) return Response.json({ error: 'Workspace not found' }, { status: 404 })\n if (!hasWorkspaceRole(accessRow.role, input.role)) {\n return Response.json({ error: 'Cannot assign a role higher than your own' }, { status: 403 })\n }\n\n const [target] = await db\n .select({ id: workspaceMembers.id, role: workspaceMembers.role, userId: workspaceMembers.userId })\n .from(workspaceMembers)\n .where(and(eq(workspaceMembers.id, input.memberId), eq(workspaceMembers.workspaceId, input.workspaceId)))\n .limit(1)\n\n if (!target) return Response.json({ error: 'Member not found' }, { status: 404 })\n if (target.userId === input.actor.id) return Response.json({ error: 'Cannot change your own role' }, { status: 403 })\n if (!canManageWorkspaceMemberRole(accessRow.role, target.role as WorkspaceRole)) {\n return Response.json({ error: 'Cannot modify a member with equal or higher role' }, { status: 403 })\n }\n\n await db.update(workspaceMembers).set({ role: input.role }).where(eq(workspaceMembers.id, input.memberId))\n if (target.userId && memberSyncSeam?.role) {\n const userId = target.userId\n const nextRole = input.role as WorkspaceRole\n fireSync(() => memberSyncSeam.role!({ workspaceId: input.workspaceId, userId, role: nextRole }))\n }\n return Response.json({ success: true })\n }\n\n async function removeMember(input: {\n workspaceId: string\n actor: MembersApiActor\n memberId?: string\n }): Promise<Response> {\n if (!input.memberId) return Response.json({ error: 'Missing memberId' }, { status: 400 })\n if (input.memberId.startsWith('org:')) {\n return Response.json({ error: 'Organization owner/admin project access is managed at the organization level' }, { status: 403 })\n }\n\n const accessRow = await access.getWorkspaceAccess(input.workspaceId, input.actor.id, 'admin')\n if (!accessRow) return Response.json({ error: 'Workspace not found' }, { status: 404 })\n\n const [target] = await db\n .select({ id: workspaceMembers.id, role: workspaceMembers.role, userId: workspaceMembers.userId })\n .from(workspaceMembers)\n .where(and(eq(workspaceMembers.id, input.memberId), eq(workspaceMembers.workspaceId, input.workspaceId)))\n .limit(1)\n\n if (!target) return Response.json({ error: 'Member not found' }, { status: 404 })\n if (target.userId === input.actor.id) return Response.json({ error: 'Cannot remove yourself from this project' }, { status: 403 })\n if (!canManageWorkspaceMemberRole(accessRow.role, target.role as WorkspaceRole)) {\n return Response.json({ error: 'Cannot remove a member with equal or higher role' }, { status: 403 })\n }\n\n await db.delete(workspaceMembers).where(eq(workspaceMembers.id, input.memberId))\n if (target.userId && memberSyncSeam?.remove) {\n const userId = target.userId\n fireSync(() => memberSyncSeam.remove!({ workspaceId: input.workspaceId, userId }))\n }\n return Response.json({ success: true })\n }\n\n async function acceptInvite(input: { token?: string; actor: MembersApiActor }): Promise<Response> {\n if (!input.token || typeof input.token !== 'string') {\n return Response.json({ error: 'Missing invite token' }, { status: 400 })\n }\n\n const [invite] = await db\n .select()\n .from(workspaceMembers)\n .where(eq(workspaceMembers.inviteToken, input.token))\n .limit(1)\n\n if (!invite) return Response.json({ error: 'Invalid or expired invite' }, { status: 404 })\n if (invite.acceptedAt) return Response.json({ error: 'Invite already accepted' }, { status: 409 })\n\n if (invite.inviteEmail && invite.inviteEmail.toLowerCase() !== input.actor.email?.toLowerCase()) {\n return Response.json(\n { error: `This invite was sent to ${invite.inviteEmail}. Please sign in with that email.` },\n { status: 403 },\n )\n }\n\n const [workspace] = await db\n .select({ id: workspaces.id, organizationId: workspaces.organizationId })\n .from(workspaces)\n .where(eq(workspaces.id, invite.workspaceId))\n .limit(1)\n\n if (!workspace) return Response.json({ error: 'Project not found' }, { status: 404 })\n const organizationId = (workspace as { organizationId: string }).organizationId\n\n // Atomic accept: only succeeds if the token still exists and is unaccepted,\n // so two concurrent accepts can't both win.\n const updated = await db\n .update(workspaceMembers)\n .set({\n userId: input.actor.id,\n acceptedAt: new Date(),\n inviteToken: null,\n })\n .where(and(\n eq(workspaceMembers.inviteToken, input.token),\n isNull(workspaceMembers.acceptedAt),\n ))\n .returning({ id: workspaceMembers.id })\n\n if (updated.length === 0) return Response.json({ error: 'Invite already accepted' }, { status: 409 })\n\n const [orgMember] = await db\n .insert(organizationMembers)\n .values({\n organizationId,\n userId: input.actor.id,\n role: 'member',\n })\n .onConflictDoUpdate({\n target: [organizationMembers.organizationId, organizationMembers.userId],\n set: { updatedAt: new Date() },\n })\n .returning()\n\n await db\n .update(workspaceMembers)\n .set({ organizationMemberId: invite.organizationMemberId ?? orgMember!.id })\n .where(eq(workspaceMembers.id, updated[0]!.id))\n\n if (memberSyncSeam?.add) {\n const role = invite.role as WorkspaceRole\n fireSync(() => memberSyncSeam.add!({ workspaceId: invite.workspaceId, userId: input.actor.id, role }))\n }\n\n return Response.json({\n success: true,\n workspaceId: invite.workspaceId,\n role: invite.role,\n })\n }\n\n // ── internal query helpers ──\n\n async function getUserByEmail(email: string) {\n const [user] = await db\n .select({ id: users.id, email: users.email })\n .from(users)\n .where(eq(users.email, email))\n .limit(1)\n return user ?? null\n }\n\n async function getOrganizationMember(organizationId: string, userId: string) {\n const [member] = await db\n .select()\n .from(organizationMembers)\n .where(and(eq(organizationMembers.organizationId, organizationId), eq(organizationMembers.userId, userId)))\n .limit(1)\n return member ?? null\n }\n\n async function findExistingProjectInvite(workspaceId: string, email: string, userId?: string) {\n const byEmail = await db\n .select({ id: workspaceMembers.id })\n .from(workspaceMembers)\n .where(and(eq(workspaceMembers.workspaceId, workspaceId), eq(workspaceMembers.inviteEmail, email)))\n .limit(1)\n if (byEmail[0]) return byEmail[0]\n if (!userId) return null\n const byUser = await db\n .select({ id: workspaceMembers.id })\n .from(workspaceMembers)\n .where(and(eq(workspaceMembers.workspaceId, workspaceId), eq(workspaceMembers.userId, userId)))\n .limit(1)\n return byUser[0] ?? null\n }\n\n async function hasPendingOrgInvite(organizationId: string, email: string): Promise<boolean> {\n const [row] = await db\n .select({ id: workspaceMembers.id })\n .from(workspaceMembers)\n .innerJoin(workspaces, eq(workspaces.id, workspaceMembers.workspaceId))\n .where(and(\n eq(workspaces.organizationId, organizationId),\n eq(workspaceMembers.inviteEmail, email),\n isNull(workspaceMembers.acceptedAt),\n ))\n .limit(1)\n return Boolean(row)\n }\n\n return { listMembers, inviteMember, updateMemberRole, removeMember, acceptInvite }\n}\n"],"mappings":"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","names":[]}