theokit 0.25.0 → 0.27.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.
Files changed (32) hide show
  1. package/dist/{agent-GXJNFW6N.js → agent-I5QEOMCN.js} +2 -2
  2. package/dist/{agents-typed-client-RIJVHSX4.js → agents-typed-client-5DCGDWFZ.js} +8 -2
  3. package/dist/agents-typed-client-5DCGDWFZ.js.map +1 -0
  4. package/dist/{agents-typed-client-DCPSXUU5.js → agents-typed-client-MAAILRI6.js} +8 -2
  5. package/dist/agents-typed-client-MAAILRI6.js.map +1 -0
  6. package/dist/{build-WD2PT5TA.js → build-V2QEBE7I.js} +2 -2
  7. package/dist/{chunk-2JNG3P4Y.js → chunk-R4VVXLKZ.js} +2 -2
  8. package/dist/{chunk-GG6H76GC.js → chunk-VRVNM3QL.js} +2 -2
  9. package/dist/{chunk-LVGDYTU2.js → chunk-Y4TOVMNC.js} +2 -2
  10. package/dist/cli/index.js +4 -4
  11. package/dist/client/index.d.ts +177 -19
  12. package/dist/client/index.js +314 -62
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/{dev-63UNEUF6.js → dev-5ZQMWVFC.js} +2 -2
  15. package/dist/index.js +1 -1
  16. package/dist/{mcp-MIZFVNCL.js → mcp-VMKWB2BY.js} +2 -2
  17. package/dist/server/index.d.ts +10 -5
  18. package/dist/server/index.js +31 -7
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/vite-plugin/index.js +1 -1
  21. package/dist/{vite-plugin-ST4JZQRJ.js → vite-plugin-BNI7YLCD.js} +2 -2
  22. package/package.json +1 -1
  23. package/dist/agents-typed-client-DCPSXUU5.js.map +0 -1
  24. package/dist/agents-typed-client-RIJVHSX4.js.map +0 -1
  25. /package/dist/{agent-GXJNFW6N.js.map → agent-I5QEOMCN.js.map} +0 -0
  26. /package/dist/{build-WD2PT5TA.js.map → build-V2QEBE7I.js.map} +0 -0
  27. /package/dist/{chunk-2JNG3P4Y.js.map → chunk-R4VVXLKZ.js.map} +0 -0
  28. /package/dist/{chunk-GG6H76GC.js.map → chunk-VRVNM3QL.js.map} +0 -0
  29. /package/dist/{chunk-LVGDYTU2.js.map → chunk-Y4TOVMNC.js.map} +0 -0
  30. /package/dist/{dev-63UNEUF6.js.map → dev-5ZQMWVFC.js.map} +0 -0
  31. /package/dist/{mcp-MIZFVNCL.js.map → mcp-VMKWB2BY.js.map} +0 -0
  32. /package/dist/{vite-plugin-ST4JZQRJ.js.map → vite-plugin-BNI7YLCD.js.map} +0 -0
@@ -3,7 +3,7 @@ import "tsx/esm";
3
3
  import {
4
4
  agentCommand,
5
5
  createAgentSsrLoader
6
- } from "./chunk-LVGDYTU2.js";
6
+ } from "./chunk-Y4TOVMNC.js";
7
7
  import "./chunk-M6NMS5LR.js";
8
8
  import "./chunk-GDN3PXFH.js";
9
9
  import "./chunk-TERFLG67.js";
@@ -12,4 +12,4 @@ export {
12
12
  agentCommand,
13
13
  createAgentSsrLoader
14
14
  };
15
- //# sourceMappingURL=agent-GXJNFW6N.js.map
15
+ //# sourceMappingURL=agent-I5QEOMCN.js.map
@@ -48,13 +48,19 @@ ${entries.join("\n")}
48
48
  return `${FILE_HEADER}
49
49
  declare module '@theo/agents' {
50
50
  import type { InferAgentInput, InferAgentToolNames } from '@theokit/agents'
51
- import type { UseAgentReturn } from 'theokit/client'
51
+ import type { UseAgentReturn, AgentTransport } from 'theokit/client'
52
52
  ${importBlock}
53
53
  export interface AppAgents ${body}
54
54
 
55
+ // Web (and any HTTP surface): bind by agent name \u2014 \`send\` is typed to the agent's \`input\` schema.
55
56
  export function useAgent<K extends keyof AppAgents>(
56
57
  name: K,
57
58
  ): UseAgentReturn<AppAgents[K]['input'], AppAgents[K]['tools']>
59
+ // M41 (ADR-0050) \u2014 terminal/desktop (and advanced): bind by an explicit AgentTransport
60
+ // (e.g. InProcessTransport). The SAME hook, one consumption shape across every surface.
61
+ export function useAgent<TInput = unknown>(
62
+ transport: AgentTransport,
63
+ ): UseAgentReturn<TInput>
58
64
  }
59
65
  `;
60
66
  }
@@ -145,4 +151,4 @@ export {
145
151
  agentsTypedClientPlugin,
146
152
  generateAgentsDts
147
153
  };
148
- //# sourceMappingURL=agents-typed-client-RIJVHSX4.js.map
154
+ //# sourceMappingURL=agents-typed-client-5DCGDWFZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite-plugin/agents-typed-client.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Codegen-time fs ops: all paths derive from `opts.projectRoot` / `opts.distDir`\n * (vite plugin opts — trusted, set by the framework's CLI). Never serves HTTP input.\n */\n/**\n * M2 (theokit-ai-first) — end-to-end typed binding for the `agents/*.ts` convention.\n *\n * Sibling of `app-typed-client.ts` (kept separate so the `@theo/client` output stays\n * byte-unchanged). Two parts:\n *\n * 1. `generateAgentsDts({ manifest, dtsOutPath, projectRoot })` — pure function emitting\n * `.theokit/agents.d.ts` (the virtual `@theo/agents` module) with `AppAgents` mapping\n * each scanned agent to `InferAgentInput` of its `defineAgent({ input })` schema, plus a\n * typed `useAgent` signature — so the client binds to `/api/agents/<name>` with the right\n * request type and ZERO manual wiring (DoD line 2).\n * 2. `agentsTypedClientPlugin(opts)` — Vite plugin that emits (1), rewrites on `agents/*`\n * changes, and serves the virtual `@theo/agents` runtime (`useAgent` from `theokit/client`).\n */\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, posix } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nimport type { TheoManifest } from '../server/internal-api.js'\n\nconst FILE_HEADER = `// AUTO-GENERATED by theokit — do not edit.\n// Source: theokit/packages/theo/src/vite-plugin/agents-typed-client.ts (M2).\n// To refresh: \\`pnpm dev\\` or \\`pnpm build\\` regenerates this on every agents/ change.\n\n/* eslint-disable */\n`\n\n/** A safe TS identifier alias for an agent (name may contain path separators). */\nfunction aliasFor(name: string): string {\n return `_agent_${name.replace(/[^\\w$]/g, '_')}`\n}\n\n/** Relative `import type` path from the .d.ts dir to the agent source (extension stripped). */\nfunction importPath(dtsOutPath: string, projectRoot: string, filePath: string): string {\n const fromDir = dirname(dtsOutPath).replace(/\\\\/g, '/')\n const abs = posix.join(projectRoot.replace(/\\\\/g, '/'), filePath.replace(/\\\\/g, '/'))\n const noExt = abs.replace(/\\.[jt]sx?$/, '')\n let rel = posix.relative(fromDir, noExt)\n if (!rel.startsWith('.')) rel = `./${rel}`\n return rel\n}\n\nexport interface GenerateAgentsDtsOptions {\n manifest: TheoManifest\n /** Absolute path to the .d.ts that will be emitted (drives the import paths). */\n dtsOutPath: string\n /** Absolute project root — agents live at `<projectRoot>/agents`. */\n projectRoot: string\n}\n\nexport function generateAgentsDts({\n manifest,\n dtsOutPath,\n projectRoot,\n}: GenerateAgentsDtsOptions): string {\n const agents = manifest.agents ?? []\n const imports: string[] = []\n const entries: string[] = []\n for (const agent of agents) {\n const alias = aliasFor(agent.name)\n imports.push(\n ` import type ${alias} from '${importPath(dtsOutPath, projectRoot, agent.filePath)}'`,\n )\n entries.push(\n ` '${agent.name}': { input: InferAgentInput<${alias}>; tools: InferAgentToolNames<${alias}> }`,\n )\n }\n\n const body =\n entries.length > 0\n ? `{\\n${entries.join('\\n')}\\n }`\n : `{\\n // No agents detected — add \\`agents/*.ts\\` to populate this binding.\\n }`\n\n const importBlock = imports.length > 0 ? `${imports.join('\\n')}\\n` : ''\n\n return `${FILE_HEADER}\ndeclare module '@theo/agents' {\n import type { InferAgentInput, InferAgentToolNames } from '@theokit/agents'\n import type { UseAgentReturn, AgentTransport } from 'theokit/client'\n${importBlock}\n export interface AppAgents ${body}\n\n // Web (and any HTTP surface): bind by agent name — \\`send\\` is typed to the agent's \\`input\\` schema.\n export function useAgent<K extends keyof AppAgents>(\n name: K,\n ): UseAgentReturn<AppAgents[K]['input'], AppAgents[K]['tools']>\n // M41 (ADR-0050) — terminal/desktop (and advanced): bind by an explicit AgentTransport\n // (e.g. InProcessTransport). The SAME hook, one consumption shape across every surface.\n export function useAgent<TInput = unknown>(\n transport: AgentTransport,\n ): UseAgentReturn<TInput>\n}\n`\n}\n\n// ─── Vite plugin ─────────────────────────────────────────────────────────────\n\nconst VIRTUAL_AGENTS_ID = '@theo/agents'\nconst RESOLVED_AGENTS_ID = '\\0@theo/agents'\n\nexport interface AgentsTypedClientPluginOptions {\n /** Absolute project root (agents live at `<projectRoot>/<agentsDir>`). */\n projectRoot: string\n /** Agents dir name (config `agentsDir`, default \"agents\"), relative to projectRoot — the watch glob. */\n agentsDir?: string\n /** Absolute `.theokit/` output dir (where `agents.d.ts` lands). */\n distDir: string\n /** Injects the scanned agents; returns the current manifest-shaped agent list. */\n scanManifest: (projectRoot: string) => TheoManifest\n}\n\n/** Atomic write via tmp + rename; skips when content is unchanged. */\nfunction writeIfChanged(filePath: string, content: string): void {\n if (existsSync(filePath)) {\n try {\n if (readFileSync(filePath, 'utf-8') === content) return\n } catch {\n /* fall through to write */\n }\n }\n mkdirSync(dirname(filePath), { recursive: true })\n const tmp = `${filePath}.${process.pid}.tmp`\n writeFileSync(tmp, content)\n renameSync(tmp, filePath)\n}\n\nfunction emitAgentsDts(opts: AgentsTypedClientPluginOptions): string {\n const dtsOutPath = posix.join(opts.distDir.replace(/\\\\/g, '/'), 'agents.d.ts')\n const content = generateAgentsDts({\n manifest: opts.scanManifest(opts.projectRoot),\n dtsOutPath,\n projectRoot: opts.projectRoot,\n })\n writeIfChanged(dtsOutPath, content)\n return dtsOutPath\n}\n\nexport function agentsTypedClientPlugin(opts: AgentsTypedClientPluginOptions): Plugin {\n let debounce: NodeJS.Timeout | undefined\n let viteServer: ViteDevServer | undefined\n\n const scheduleEmit = (): void => {\n if (debounce) clearTimeout(debounce)\n debounce = setTimeout(() => {\n try {\n emitAgentsDts(opts)\n if (viteServer) {\n const mod = viteServer.moduleGraph.getModuleById(RESOLVED_AGENTS_ID)\n if (mod) viteServer.moduleGraph.invalidateModule(mod)\n }\n } catch (err) {\n console.error('[theokit:agents-typed-client] codegen error:', err)\n }\n }, 100)\n }\n\n return {\n name: 'theokit:agents-typed-client',\n enforce: 'post',\n configResolved() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] initial codegen error:', err)\n }\n },\n buildEnd() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] buildEnd codegen error:', err)\n }\n },\n configureServer(server) {\n viteServer = server\n const agentsGlob = posix.join(\n opts.projectRoot.replace(/\\\\/g, '/'),\n opts.agentsDir ?? 'agents',\n )\n const onFile = (file: string): void => {\n if (file.replace(/\\\\/g, '/').startsWith(agentsGlob)) scheduleEmit()\n }\n server.watcher.on('add', onFile)\n server.watcher.on('change', onFile)\n server.watcher.on('unlink', onFile)\n },\n resolveId(id) {\n return id === VIRTUAL_AGENTS_ID ? RESOLVED_AGENTS_ID : null\n },\n load(id) {\n if (id === RESOLVED_AGENTS_ID) {\n return `export { useAgent } from 'theokit/client'\\n`\n }\n return null\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -47,13 +47,19 @@ ${entries.join("\n")}
47
47
  return `${FILE_HEADER}
48
48
  declare module '@theo/agents' {
49
49
  import type { InferAgentInput, InferAgentToolNames } from '@theokit/agents'
50
- import type { UseAgentReturn } from 'theokit/client'
50
+ import type { UseAgentReturn, AgentTransport } from 'theokit/client'
51
51
  ${importBlock}
52
52
  export interface AppAgents ${body}
53
53
 
54
+ // Web (and any HTTP surface): bind by agent name \u2014 \`send\` is typed to the agent's \`input\` schema.
54
55
  export function useAgent<K extends keyof AppAgents>(
55
56
  name: K,
56
57
  ): UseAgentReturn<AppAgents[K]['input'], AppAgents[K]['tools']>
58
+ // M41 (ADR-0050) \u2014 terminal/desktop (and advanced): bind by an explicit AgentTransport
59
+ // (e.g. InProcessTransport). The SAME hook, one consumption shape across every surface.
60
+ export function useAgent<TInput = unknown>(
61
+ transport: AgentTransport,
62
+ ): UseAgentReturn<TInput>
57
63
  }
58
64
  `;
59
65
  }
@@ -144,4 +150,4 @@ export {
144
150
  agentsTypedClientPlugin,
145
151
  generateAgentsDts
146
152
  };
147
- //# sourceMappingURL=agents-typed-client-DCPSXUU5.js.map
153
+ //# sourceMappingURL=agents-typed-client-MAAILRI6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite-plugin/agents-typed-client.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Codegen-time fs ops: all paths derive from `opts.projectRoot` / `opts.distDir`\n * (vite plugin opts — trusted, set by the framework's CLI). Never serves HTTP input.\n */\n/**\n * M2 (theokit-ai-first) — end-to-end typed binding for the `agents/*.ts` convention.\n *\n * Sibling of `app-typed-client.ts` (kept separate so the `@theo/client` output stays\n * byte-unchanged). Two parts:\n *\n * 1. `generateAgentsDts({ manifest, dtsOutPath, projectRoot })` — pure function emitting\n * `.theokit/agents.d.ts` (the virtual `@theo/agents` module) with `AppAgents` mapping\n * each scanned agent to `InferAgentInput` of its `defineAgent({ input })` schema, plus a\n * typed `useAgent` signature — so the client binds to `/api/agents/<name>` with the right\n * request type and ZERO manual wiring (DoD line 2).\n * 2. `agentsTypedClientPlugin(opts)` — Vite plugin that emits (1), rewrites on `agents/*`\n * changes, and serves the virtual `@theo/agents` runtime (`useAgent` from `theokit/client`).\n */\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, posix } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nimport type { TheoManifest } from '../server/internal-api.js'\n\nconst FILE_HEADER = `// AUTO-GENERATED by theokit — do not edit.\n// Source: theokit/packages/theo/src/vite-plugin/agents-typed-client.ts (M2).\n// To refresh: \\`pnpm dev\\` or \\`pnpm build\\` regenerates this on every agents/ change.\n\n/* eslint-disable */\n`\n\n/** A safe TS identifier alias for an agent (name may contain path separators). */\nfunction aliasFor(name: string): string {\n return `_agent_${name.replace(/[^\\w$]/g, '_')}`\n}\n\n/** Relative `import type` path from the .d.ts dir to the agent source (extension stripped). */\nfunction importPath(dtsOutPath: string, projectRoot: string, filePath: string): string {\n const fromDir = dirname(dtsOutPath).replace(/\\\\/g, '/')\n const abs = posix.join(projectRoot.replace(/\\\\/g, '/'), filePath.replace(/\\\\/g, '/'))\n const noExt = abs.replace(/\\.[jt]sx?$/, '')\n let rel = posix.relative(fromDir, noExt)\n if (!rel.startsWith('.')) rel = `./${rel}`\n return rel\n}\n\nexport interface GenerateAgentsDtsOptions {\n manifest: TheoManifest\n /** Absolute path to the .d.ts that will be emitted (drives the import paths). */\n dtsOutPath: string\n /** Absolute project root — agents live at `<projectRoot>/agents`. */\n projectRoot: string\n}\n\nexport function generateAgentsDts({\n manifest,\n dtsOutPath,\n projectRoot,\n}: GenerateAgentsDtsOptions): string {\n const agents = manifest.agents ?? []\n const imports: string[] = []\n const entries: string[] = []\n for (const agent of agents) {\n const alias = aliasFor(agent.name)\n imports.push(\n ` import type ${alias} from '${importPath(dtsOutPath, projectRoot, agent.filePath)}'`,\n )\n entries.push(\n ` '${agent.name}': { input: InferAgentInput<${alias}>; tools: InferAgentToolNames<${alias}> }`,\n )\n }\n\n const body =\n entries.length > 0\n ? `{\\n${entries.join('\\n')}\\n }`\n : `{\\n // No agents detected — add \\`agents/*.ts\\` to populate this binding.\\n }`\n\n const importBlock = imports.length > 0 ? `${imports.join('\\n')}\\n` : ''\n\n return `${FILE_HEADER}\ndeclare module '@theo/agents' {\n import type { InferAgentInput, InferAgentToolNames } from '@theokit/agents'\n import type { UseAgentReturn, AgentTransport } from 'theokit/client'\n${importBlock}\n export interface AppAgents ${body}\n\n // Web (and any HTTP surface): bind by agent name — \\`send\\` is typed to the agent's \\`input\\` schema.\n export function useAgent<K extends keyof AppAgents>(\n name: K,\n ): UseAgentReturn<AppAgents[K]['input'], AppAgents[K]['tools']>\n // M41 (ADR-0050) — terminal/desktop (and advanced): bind by an explicit AgentTransport\n // (e.g. InProcessTransport). The SAME hook, one consumption shape across every surface.\n export function useAgent<TInput = unknown>(\n transport: AgentTransport,\n ): UseAgentReturn<TInput>\n}\n`\n}\n\n// ─── Vite plugin ─────────────────────────────────────────────────────────────\n\nconst VIRTUAL_AGENTS_ID = '@theo/agents'\nconst RESOLVED_AGENTS_ID = '\\0@theo/agents'\n\nexport interface AgentsTypedClientPluginOptions {\n /** Absolute project root (agents live at `<projectRoot>/<agentsDir>`). */\n projectRoot: string\n /** Agents dir name (config `agentsDir`, default \"agents\"), relative to projectRoot — the watch glob. */\n agentsDir?: string\n /** Absolute `.theokit/` output dir (where `agents.d.ts` lands). */\n distDir: string\n /** Injects the scanned agents; returns the current manifest-shaped agent list. */\n scanManifest: (projectRoot: string) => TheoManifest\n}\n\n/** Atomic write via tmp + rename; skips when content is unchanged. */\nfunction writeIfChanged(filePath: string, content: string): void {\n if (existsSync(filePath)) {\n try {\n if (readFileSync(filePath, 'utf-8') === content) return\n } catch {\n /* fall through to write */\n }\n }\n mkdirSync(dirname(filePath), { recursive: true })\n const tmp = `${filePath}.${process.pid}.tmp`\n writeFileSync(tmp, content)\n renameSync(tmp, filePath)\n}\n\nfunction emitAgentsDts(opts: AgentsTypedClientPluginOptions): string {\n const dtsOutPath = posix.join(opts.distDir.replace(/\\\\/g, '/'), 'agents.d.ts')\n const content = generateAgentsDts({\n manifest: opts.scanManifest(opts.projectRoot),\n dtsOutPath,\n projectRoot: opts.projectRoot,\n })\n writeIfChanged(dtsOutPath, content)\n return dtsOutPath\n}\n\nexport function agentsTypedClientPlugin(opts: AgentsTypedClientPluginOptions): Plugin {\n let debounce: NodeJS.Timeout | undefined\n let viteServer: ViteDevServer | undefined\n\n const scheduleEmit = (): void => {\n if (debounce) clearTimeout(debounce)\n debounce = setTimeout(() => {\n try {\n emitAgentsDts(opts)\n if (viteServer) {\n const mod = viteServer.moduleGraph.getModuleById(RESOLVED_AGENTS_ID)\n if (mod) viteServer.moduleGraph.invalidateModule(mod)\n }\n } catch (err) {\n console.error('[theokit:agents-typed-client] codegen error:', err)\n }\n }, 100)\n }\n\n return {\n name: 'theokit:agents-typed-client',\n enforce: 'post',\n configResolved() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] initial codegen error:', err)\n }\n },\n buildEnd() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] buildEnd codegen error:', err)\n }\n },\n configureServer(server) {\n viteServer = server\n const agentsGlob = posix.join(\n opts.projectRoot.replace(/\\\\/g, '/'),\n opts.agentsDir ?? 'agents',\n )\n const onFile = (file: string): void => {\n if (file.replace(/\\\\/g, '/').startsWith(agentsGlob)) scheduleEmit()\n }\n server.watcher.on('add', onFile)\n server.watcher.on('change', onFile)\n server.watcher.on('unlink', onFile)\n },\n resolveId(id) {\n return id === VIRTUAL_AGENTS_ID ? RESOLVED_AGENTS_ID : null\n },\n load(id) {\n if (id === RESOLVED_AGENTS_ID) {\n return `export { useAgent } from 'theokit/client'\\n`\n }\n return null\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -531,7 +531,7 @@ async function buildCommand(options) {
531
531
  `);
532
532
  }
533
533
  async function runAdapterBuild(target, config, cwd) {
534
- const { theoPluginAsync } = await import("./vite-plugin-ST4JZQRJ.js");
534
+ const { theoPluginAsync } = await import("./vite-plugin-BNI7YLCD.js");
535
535
  const { default: react } = await import("@vitejs/plugin-react");
536
536
  const ctx = {
537
537
  // `react()` may return Plugin or Plugin[] depending on version; spread the
@@ -616,4 +616,4 @@ function relativize3(absPath, root) {
616
616
  export {
617
617
  buildCommand
618
618
  };
619
- //# sourceMappingURL=build-WD2PT5TA.js.map
619
+ //# sourceMappingURL=build-V2QEBE7I.js.map
@@ -3353,7 +3353,7 @@ async function theoPluginAsync(rootOrOptions) {
3353
3353
  serverDir: serverDirAbs,
3354
3354
  distDir: resolve9(projectRoot, ".theokit")
3355
3355
  });
3356
- const { agentsTypedClientPlugin } = await import("./agents-typed-client-DCPSXUU5.js");
3356
+ const { agentsTypedClientPlugin } = await import("./agents-typed-client-MAAILRI6.js");
3357
3357
  const { generateManifest } = await import("./internal-api-KPULK7ZK.js");
3358
3358
  const agentsClientPlugin = agentsTypedClientPlugin({
3359
3359
  projectRoot,
@@ -3537,4 +3537,4 @@ export {
3537
3537
  theoPluginAsync,
3538
3538
  theoPlugin
3539
3539
  };
3540
- //# sourceMappingURL=chunk-2JNG3P4Y.js.map
3540
+ //# sourceMappingURL=chunk-R4VVXLKZ.js.map
@@ -1928,7 +1928,7 @@ async function theoPluginAsync(rootOrOptions) {
1928
1928
  serverDir: serverDirAbs,
1929
1929
  distDir: resolve7(projectRoot, ".theokit")
1930
1930
  });
1931
- const { agentsTypedClientPlugin } = await import("./agents-typed-client-RIJVHSX4.js");
1931
+ const { agentsTypedClientPlugin } = await import("./agents-typed-client-5DCGDWFZ.js");
1932
1932
  const { generateManifest } = await import("./internal-api-Y5REPVUS.js");
1933
1933
  const agentsClientPlugin = agentsTypedClientPlugin({
1934
1934
  projectRoot,
@@ -2104,4 +2104,4 @@ export {
2104
2104
  theoPluginAsync,
2105
2105
  theoPlugin
2106
2106
  };
2107
- //# sourceMappingURL=chunk-GG6H76GC.js.map
2107
+ //# sourceMappingURL=chunk-VRVNM3QL.js.map
@@ -178,7 +178,7 @@ async function agentCommand(name, message, deps = {}) {
178
178
  async function createAgentSsrLoader(projectRoot) {
179
179
  const { createServer } = await import("vite");
180
180
  const react = (await import("@vitejs/plugin-react")).default;
181
- const { theoPluginAsync } = await import("./vite-plugin-ST4JZQRJ.js");
181
+ const { theoPluginAsync } = await import("./vite-plugin-BNI7YLCD.js");
182
182
  const { loadConfig } = await import("./load-config-3EAQTXPH.js");
183
183
  const config = await loadConfig(projectRoot);
184
184
  const theoPlugins = await theoPluginAsync({
@@ -212,4 +212,4 @@ export {
212
212
  agentCommand,
213
213
  createAgentSsrLoader
214
214
  };
215
- //# sourceMappingURL=chunk-LVGDYTU2.js.map
215
+ //# sourceMappingURL=chunk-Y4TOVMNC.js.map
package/dist/cli/index.js CHANGED
@@ -5,12 +5,12 @@ import "tsx/esm";
5
5
  import cac from "cac";
6
6
  var cli = cac("theokit");
7
7
  cli.command("dev", "Start development server").option("--port <port>", "Port number").action(async (options) => {
8
- const { devCommand } = await import("../dev-63UNEUF6.js");
8
+ const { devCommand } = await import("../dev-5ZQMWVFC.js");
9
9
  await devCommand({ port: options.port ? Number(options.port) : void 0 });
10
10
  });
11
11
  cli.command("build", "Build for production").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
12
12
  try {
13
- const { buildCommand } = await import("../build-WD2PT5TA.js");
13
+ const { buildCommand } = await import("../build-V2QEBE7I.js");
14
14
  await buildCommand({ target: options.target });
15
15
  } catch (err) {
16
16
  const msg = err instanceof Error ? err.message : String(err);
@@ -52,7 +52,7 @@ cli.command(
52
52
  "Run an agent in the terminal (stream + tool calls + approval)"
53
53
  ).action(async (name, message) => {
54
54
  try {
55
- const { agentCommand } = await import("../agent-GXJNFW6N.js");
55
+ const { agentCommand } = await import("../agent-I5QEOMCN.js");
56
56
  const { sawError } = await agentCommand(name, message);
57
57
  if (sawError) process.exit(1);
58
58
  } catch (err) {
@@ -65,7 +65,7 @@ cli.command(
65
65
  });
66
66
  cli.command("mcp <agent>", "Serve an agent as an MCP server over stdio (for desktop MCP clients)").action(async (agent) => {
67
67
  try {
68
- const { mcpCommand } = await import("../mcp-MIZFVNCL.js");
68
+ const { mcpCommand } = await import("../mcp-VMKWB2BY.js");
69
69
  await mcpCommand(agent);
70
70
  } catch (err) {
71
71
  const msg = err instanceof Error ? err.message : String(err);
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { T as TheoErrorEnvelope } from '../error-envelope-BsNzzAV5.js';
3
3
  export { FetchOptionsLike, Fetcher, QueryKey, UseTheoQueryConfig, buildUseTheoQueryConfig, stableQueryKey } from '../react-query/index.js';
4
- import { UIMessage } from 'ai';
4
+ import { UIMessageChunk, UIMessage, ChatTransport } from 'ai';
5
5
  import * as react from 'react';
6
6
  import { LinkProps as LinkProps$1 } from 'react-router';
7
7
 
@@ -130,20 +130,85 @@ declare function createBatcher(options: BatcherOptions): Batcher;
130
130
  * assistant message, so a caller (the `useAgent` hook) can render streaming updates.
131
131
  */
132
132
  declare function consumeUIMessageStream(response: Response, onMessage: (message: UIMessage) => void): Promise<void>;
133
+ /**
134
+ * M41 (ADR-0050 D3) — the reusable middle piece: a UIMessageStream SSE `Response` →
135
+ * `ReadableStream<UIMessageChunk>`, reusing `ai`'s own `parseJsonEventStream` (the exact primitive
136
+ * `useChat` runs). This is precisely what a `ChatTransport.sendMessages` returns, so `HttpTransport`
137
+ * builds on it directly (no reinvented wire parser — Rule 9). A body-less response yields an empty stream.
138
+ */
139
+ declare function responseToChunkStream(response: Response): Promise<ReadableStream<UIMessageChunk>>;
140
+ /**
141
+ * M41 (ADR-0050 D6) — read a `ReadableStream<UIMessageChunk>` into reconstructed assistant
142
+ * `UIMessage`s via `ai`'s `readUIMessageStream`. Shared by `consumeUIMessageStream` (Response path)
143
+ * and the framework-agnostic `AgentClient` store (transport path). `onMessage` fires on every
144
+ * reconstruction step so a caller can render streaming updates.
145
+ */
146
+ declare function consumeChunkStream(stream: ReadableStream<UIMessageChunk>, onMessage: (message: UIMessage) => void): Promise<void>;
133
147
 
134
148
  /**
135
- * M2 (theokit-ai-first) — `useAgent`, the typed client hook for the `agents/*.ts` convention.
149
+ * M41 (ADR-0050 D2) — a HITL approval decision sent to settle a paused gated-tool call. Mirrors the
150
+ * `POST /api/agents/<name>/approve/<id>` wire body (`approve-agent.ts` `parseApprovalBody`). Defined
151
+ * on the client side (not imported from `server/`) as the client's view of the boundary contract.
152
+ */
153
+ interface ApprovalDecision {
154
+ /** Whether the paused gated tool may proceed. */
155
+ approved: boolean;
156
+ /** Optional reason surfaced to the model on denial. */
157
+ reason?: string;
158
+ /** Optional small structured note (edited args, a reviewer comment) — capped server-side at 16 KiB. */
159
+ payload?: unknown;
160
+ }
161
+ /**
162
+ * M41 (ADR-0050 D1/D2) — the client transport seam.
136
163
  *
137
- * A thin React hook over `consumeUIMessageStream` (which reuses `ai`'s own UIMessageStream
138
- * reader). `useAgent('support')` binds to `POST /api/agents/support`; the generated
139
- * `@theo/agents` module (`.theokit/agents.d.ts`) types `send` to the agent's `input` schema,
140
- * so the request shape is inferred end-to-end from the server `defineAgent({ input })` with
141
- * ZERO manual wiring (DoD line 2).
164
+ * It IS `ai`'s `ChatTransport<UIMessage>` (the adopted SOTA interface — we do NOT invent a parallel
165
+ * one) plus ONE optional method, `approve`, for TheoKit's OUT-OF-BAND HITL (the server pauses the run;
166
+ * the client settles it via a separate call). `ai`'s `ChatTransport` has no `approve` because its HITL
167
+ * is in-band (a re-sent message part); ours is out-of-band, and the settle route differs per transport
168
+ * (HTTP `POST /approve/<id>` vs an inline callback), so it belongs on the transport. `approve` is
169
+ * optional — agents without gated tools never settle an approval.
142
170
  *
143
- * Transport: fetch + ReadableStream (POST needs a body; EventSource is GET-only). `ai` is
144
- * loaded lazily by `consumeUIMessageStream` so non-agent apps never pay for it.
171
+ * `HttpTransport` (web) and `InProcessTransport` (TUI/desktop) implement this; `useAgent` drives it.
145
172
  */
173
+ type AgentTransport = ChatTransport<UIMessage> & {
174
+ approve?(approvalId: string, decision: ApprovalDecision): Promise<void>;
175
+ };
176
+
146
177
  type UseAgentStatus = 'idle' | 'streaming' | 'done' | 'error';
178
+ /** The observable state the store exposes (stable reference between emits — `useSyncExternalStore` contract). */
179
+ interface AgentClientState {
180
+ messages: UIMessage[];
181
+ status: UseAgentStatus;
182
+ error: Error | undefined;
183
+ }
184
+ /**
185
+ * M41 (ADR-0050 D6) — the framework-agnostic agent client store.
186
+ *
187
+ * Holds `messages`/`status`/`error`, drives an {@link AgentTransport}, and notifies subscribers on
188
+ * change. It is the SINGLE consolidation point: web (`HttpTransport`) and terminal/desktop
189
+ * (`InProcessTransport`) run the SAME store. `useAgent` is a thin React binding over it via
190
+ * `useSyncExternalStore`; a standalone (no-React) client (M44) can subscribe directly. Being
191
+ * framework-agnostic, it is unit-tested without a DOM.
192
+ */
193
+ declare class AgentClient<TInput = unknown> {
194
+ #private;
195
+ constructor(transport: AgentTransport);
196
+ /** Subscribe to state changes; returns an unsubscribe fn. */
197
+ subscribe: (listener: () => void) => (() => void);
198
+ /** The current immutable snapshot (stable reference until the next emit). */
199
+ getSnapshot: () => AgentClientState;
200
+ /** Send a typed input; opens a fresh stream (replaces prior messages). */
201
+ send: (input: TInput) => void;
202
+ /** Resume an interrupted stream via the transport's `reconnectToStream` (no-op when unavailable). */
203
+ reconnect: () => void;
204
+ /** Abort an in-flight stream (not an error — leaves messages as-is). */
205
+ abort: () => void;
206
+ /** Clear messages + error, back to idle. */
207
+ reset: () => void;
208
+ /** Settle a paused HITL approval via the transport's HITL path (HTTP POST or inline callback). */
209
+ approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>;
210
+ }
211
+
147
212
  interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {
148
213
  /** Reconstructed assistant messages so far (ai `UIMessage[]`). */
149
214
  messages: UIMessage[];
@@ -156,25 +221,118 @@ interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {
156
221
  abort: () => void;
157
222
  /** Clear messages + error, back to idle. */
158
223
  reset: () => void;
224
+ /** Settle a paused HITL approval (HTTP `POST /approve/<id>` for web; the inline callback in-process). */
225
+ approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>;
226
+ /** Resume an interrupted stream (M37 durable transport for web; a no-op in-process). */
227
+ reconnect: () => void;
159
228
  /**
160
- * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()`
161
- * builder's accumulated tool-name type through the generated `@theo/agents` client. Type-only
162
- * witness (never populated at runtime) narrow a streamed `tool-<name>` part against it. Resolves
163
- * to the literal union for builder agents (`'read_file' | 'count_lines'`), `string` otherwise.
229
+ * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()` builder's
230
+ * accumulated tool-name type through the generated `@theo/agents` client. Type-only witness (never
231
+ * populated at runtime). Resolves to the literal union for builder agents, `string` otherwise.
164
232
  */
165
233
  readonly __toolNames?: TToolNames;
166
234
  }
167
235
  interface UseAgentOptions {
168
- /** Extra request headers (e.g., auth). */
236
+ /**
237
+ * Extra request headers (e.g., auth) — applied when a string path builds an `HttpTransport`. Read on
238
+ * EVERY request, so a value that changes across renders (a rotating JWT) is never sent stale.
239
+ */
169
240
  headers?: Record<string, string>;
170
- /** Override fetch (primarily for tests). */
241
+ /** Override fetch (primarily for tests) — captured when a string path builds an `HttpTransport`. */
171
242
  fetch?: typeof fetch;
172
243
  }
173
244
  /**
174
- * Bind to the agent endpoint at `path` (`/api/agents/<name>`). Prefer the generated
175
- * `useAgent` from `@theo/agents` (typed by agent name); this base accepts an explicit path.
245
+ * Bind to an agent by endpoint path (`/api/agents/<name>`) or by an explicit {@link AgentTransport}.
246
+ * Prefer the generated `useAgent` from `@theo/agents` (typed by agent name); this base accepts a path
247
+ * or a transport. The store is created once per binding identity — memoize a transport before passing it.
248
+ */
249
+ declare function useAgent<TInput = unknown>(pathOrTransport: string | AgentTransport, options?: UseAgentOptions): UseAgentReturn<TInput>;
250
+
251
+ /** Extra request headers — a static record OR a resolver called per request (for dynamic auth). */
252
+ type HeadersResolver = Record<string, string> | (() => Record<string, string> | undefined);
253
+ interface HttpTransportOptions {
254
+ /** Agent endpoint path or URL, e.g. `/api/agents/support`. */
255
+ api: string;
256
+ /**
257
+ * Extra request headers (e.g. auth). Static record OR a resolver evaluated on EVERY request — pass a
258
+ * resolver when the value is dynamic (a rotating JWT), so a stale header is never sent. Merged UNDER
259
+ * per-request headers.
260
+ */
261
+ headers?: HeadersResolver;
262
+ /** Override fetch (primarily for tests / non-browser hosts) — static; resolved once at construction. */
263
+ fetch?: typeof fetch;
264
+ }
265
+ /**
266
+ * M41 (ADR-0050 D3) — `ChatTransport` over the web agent path.
267
+ *
268
+ * - `sendMessages`: `POST <api>` with the UIMessageStream `accept` + the `X-Theo-Action` CSRF header
269
+ * (HTTP method + headers are identical to the pre-M41 `useAgent` fetch; the body shape is a superset —
270
+ * `{ ...input, messages: [UIMessage] }` — which the server's dual-path parser accepts, so no
271
+ * regression), captures the server-minted `x-theokit-run-id`, and returns `ReadableStream<UIMessageChunk>`
272
+ * via `ai`'s own SSE parser (`responseToChunkStream`).
273
+ * - `reconnectToStream`: `GET <api>/runs/<runId>/stream` (M37 durable transport); 404 → `null` (the run
274
+ * completed / was evicted). A caller may pass a `Last-Event-ID` header to resume only the tail; by
275
+ * default the server replays the run from the start and the client upserts by message id (idempotent).
276
+ * - `approve`: `POST <api>/approve/<id>` (out-of-band HITL settle).
277
+ *
278
+ * Implemented directly (not by subclassing `DefaultChatTransport`) because reconnect keys on our
279
+ * server-minted `runId` captured from a response header, which the base class does not expose — see
280
+ * ADR-0050 D3.
281
+ */
282
+ declare class HttpTransport implements AgentTransport {
283
+ #private;
284
+ constructor(options: HttpTransportOptions);
285
+ sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
286
+ reconnectToStream(options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0]): Promise<ReadableStream<UIMessageChunk> | null>;
287
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
288
+ }
289
+
290
+ /** An inline approval request handed to the transport's resolver (structural — no server import). */
291
+ interface InProcessApprovalRequestLike {
292
+ approvalId: string;
293
+ toolName: string;
294
+ opts: unknown;
295
+ }
296
+ /** Resolve one gated-tool approval inline (mirrors the SDK's `boolean | HitlDecision` return). */
297
+ type InProcessAwaitApproval = (req: InProcessApprovalRequestLike) => Promise<boolean | ApprovalDecision>;
298
+ /** The input the injected runner receives (structurally compatible with `StreamAgentTurnInProcessInput`). */
299
+ interface InProcessRunInput {
300
+ message: string;
301
+ sessionId?: string;
302
+ signal?: AbortSignal;
303
+ awaitApproval?: InProcessAwaitApproval;
304
+ }
305
+ /**
306
+ * The in-process turn runner. The consumer binds `streamAgentTurnInProcess(mod, apiKey, …)`:
307
+ * `new InProcessTransport({ run: (input) => streamAgentTurnInProcess(mod, apiKey, input) })`.
308
+ * Injecting it keeps this client module decoupled from `server/` and makes the transport testable.
176
309
  */
177
- declare function useAgent<TInput = unknown>(path: string, options?: UseAgentOptions): UseAgentReturn<TInput>;
310
+ type InProcessRunner = (input: InProcessRunInput) => AsyncGenerator<UIMessageChunk>;
311
+ interface InProcessTransportOptions {
312
+ run: InProcessRunner;
313
+ }
314
+ /**
315
+ * M41 (ADR-0050 D4) — `ChatTransport` over the in-process seam (`streamAgentTurnInProcess`), for the
316
+ * terminal/desktop surfaces that run client + server in ONE process (no HTTP loopback).
317
+ *
318
+ * - `sendMessages`: bridge the injected runner's `AsyncGenerator<UIMessageChunk>` into a
319
+ * `ReadableStream<UIMessageChunk>` (honoring `abortSignal`, which the runner forwards to the SDK).
320
+ * - `reconnectToStream`: always `null` — a single process has no dropped server-side stream to resume
321
+ * (mirrors `ai`'s `DirectChatTransport`).
322
+ * - `approve`: resolve the pending inline approval by id (the run parks on `awaitApproval`). An unknown
323
+ * id rejects (fail-fast, Rule 8 — never a silent resolve).
324
+ *
325
+ * Error asymmetry vs `HttpTransport` (by design, matching the `ChatTransport` contract): a runner that
326
+ * throws SYNCHRONOUSLY surfaces the error when the stream is READ (via `controller.error`), not from the
327
+ * `sendMessages` promise — whereas `HttpTransport` throws from `sendMessages` on a non-2xx response.
328
+ */
329
+ declare class InProcessTransport implements AgentTransport {
330
+ #private;
331
+ constructor(options: InProcessTransportOptions);
332
+ sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
333
+ reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
334
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
335
+ }
178
336
 
179
337
  type PrefetchBehavior = 'none' | 'intent' | 'viewport';
180
338
  interface LinkProps extends LinkProps$1 {
@@ -323,4 +481,4 @@ declare function mountMcpApp(container: HTMLElement, resource: {
323
481
  html: string;
324
482
  }, opts: McpAppHostOptions): McpAppHandle;
325
483
 
326
- export { type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type CreateAppClientOptions, type GuestMessage, Image, type ImageProps, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, type UseAgentStatus, consumeUIMessageStream, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, theoFetch, useAgent };
484
+ export { AgentClient, type AgentClientState, type AgentTransport, type ApprovalDecision, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type CreateAppClientOptions, type GuestMessage, HttpTransport, type HttpTransportOptions, Image, type ImageProps, type InProcessApprovalRequestLike, type InProcessAwaitApproval, type InProcessRunInput, type InProcessRunner, InProcessTransport, type InProcessTransportOptions, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, type UseAgentStatus, consumeChunkStream, consumeUIMessageStream, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, responseToChunkStream, theoFetch, useAgent };