@agent-native/core 0.7.51 → 0.7.53

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 (90) hide show
  1. package/dist/a2a/artifact-response.d.ts.map +1 -1
  2. package/dist/a2a/artifact-response.js +109 -5
  3. package/dist/a2a/artifact-response.js.map +1 -1
  4. package/dist/a2a/server.d.ts.map +1 -1
  5. package/dist/a2a/server.js +11 -0
  6. package/dist/a2a/server.js.map +1 -1
  7. package/dist/cli/templates-meta.d.ts.map +1 -1
  8. package/dist/cli/templates-meta.js +1 -0
  9. package/dist/cli/templates-meta.js.map +1 -1
  10. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  11. package/dist/client/settings/VoiceTranscriptionSection.js +54 -13
  12. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  13. package/dist/deploy/workspace-deploy.js +32 -3
  14. package/dist/deploy/workspace-deploy.js.map +1 -1
  15. package/dist/integrations/plugin.d.ts.map +1 -1
  16. package/dist/integrations/plugin.js +2 -1
  17. package/dist/integrations/plugin.js.map +1 -1
  18. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  19. package/dist/integrations/webhook-handler.js +10 -0
  20. package/dist/integrations/webhook-handler.js.map +1 -1
  21. package/dist/onboarding/plugin.d.ts.map +1 -1
  22. package/dist/onboarding/plugin.js +2 -1
  23. package/dist/onboarding/plugin.js.map +1 -1
  24. package/dist/org/plugin.d.ts.map +1 -1
  25. package/dist/org/plugin.js +2 -1
  26. package/dist/org/plugin.js.map +1 -1
  27. package/dist/scripts/call-agent.js +2 -2
  28. package/dist/scripts/call-agent.js.map +1 -1
  29. package/dist/server/action-routes.d.ts.map +1 -1
  30. package/dist/server/action-routes.js +5 -11
  31. package/dist/server/action-routes.js.map +1 -1
  32. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  33. package/dist/server/agent-chat-plugin.js +2 -1
  34. package/dist/server/agent-chat-plugin.js.map +1 -1
  35. package/dist/server/auth-plugin.d.ts.map +1 -1
  36. package/dist/server/auth-plugin.js +2 -1
  37. package/dist/server/auth-plugin.js.map +1 -1
  38. package/dist/server/auth.d.ts.map +1 -1
  39. package/dist/server/auth.js +7 -12
  40. package/dist/server/auth.js.map +1 -1
  41. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  42. package/dist/server/core-routes-plugin.js +9 -29
  43. package/dist/server/core-routes-plugin.js.map +1 -1
  44. package/dist/server/cors-origins.d.ts +10 -0
  45. package/dist/server/cors-origins.d.ts.map +1 -0
  46. package/dist/server/cors-origins.js +34 -0
  47. package/dist/server/cors-origins.js.map +1 -0
  48. package/dist/server/create-server.d.ts.map +1 -1
  49. package/dist/server/create-server.js +10 -29
  50. package/dist/server/create-server.js.map +1 -1
  51. package/dist/server/framework-request-handler.d.ts +11 -0
  52. package/dist/server/framework-request-handler.d.ts.map +1 -1
  53. package/dist/server/framework-request-handler.js +24 -1
  54. package/dist/server/framework-request-handler.js.map +1 -1
  55. package/dist/server/resources-plugin.d.ts.map +1 -1
  56. package/dist/server/resources-plugin.js +2 -1
  57. package/dist/server/resources-plugin.js.map +1 -1
  58. package/dist/terminal/terminal-plugin.d.ts.map +1 -1
  59. package/dist/terminal/terminal-plugin.js +2 -1
  60. package/dist/terminal/terminal-plugin.js.map +1 -1
  61. package/docs/content/a2a-protocol.md +93 -14
  62. package/docs/content/agent-mentions.md +2 -2
  63. package/docs/content/agent-teams.md +2 -2
  64. package/docs/content/client.md +1 -1
  65. package/docs/content/cloneable-saas.md +13 -13
  66. package/docs/content/creating-templates.md +253 -211
  67. package/docs/content/dispatch.md +94 -0
  68. package/docs/content/faq.md +2 -2
  69. package/docs/content/frames.md +1 -1
  70. package/docs/content/getting-started.md +9 -1
  71. package/docs/content/key-concepts.md +17 -1
  72. package/docs/content/messaging.md +56 -19
  73. package/docs/content/multi-app-workspace.md +10 -2
  74. package/docs/content/notifications.md +1 -1
  75. package/docs/content/observability.md +184 -0
  76. package/docs/content/onboarding.md +7 -2
  77. package/docs/content/server.md +117 -133
  78. package/docs/content/skills-guide.md +3 -3
  79. package/docs/content/template-analytics.md +8 -6
  80. package/docs/content/template-design.md +25 -27
  81. package/docs/content/template-dispatch.md +3 -1
  82. package/docs/content/template-forms.md +26 -21
  83. package/docs/content/template-mail.md +4 -0
  84. package/docs/content/template-video.md +4 -4
  85. package/docs/content/tools.md +95 -1
  86. package/docs/content/tracking.md +1 -1
  87. package/docs/content/what-is-agent-native.md +4 -2
  88. package/docs/content/workspace-management.md +5 -5
  89. package/docs/content/workspace.md +39 -30
  90. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-plugin.js","sourceRoot":"","sources":["../../src/terminal/terminal-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { getH3App } from \"../server/framework-request-handler.js\";\nimport { isNodeRuntime } from \"../shared/runtime.js\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\n/**\n * Nitro Plugin — Agent Terminal\n *\n * Starts a PTY WebSocket server alongside the app so the <AgentTerminal />\n * component can connect to a real CLI. Mounts a discovery endpoint at\n * /_agent-native/agent-terminal-info for the client component.\n *\n * Skips activation when running inside a frame (FRAME_PORT is set).\n */\n\nimport { defineEventHandler } from \"h3\";\n\n// ─── module-load self-heal: chmod node-pty's spawn-helper ─────────────────\n// pnpm can extract node-pty's prebuilds tarball without running the\n// post-install that chmods spawn-helper, leaving it as `-rw-r--r--` instead\n// of `-rwxr-xr-x`. Every PTY spawn then fails with `posix_spawnp failed`.\n// Run the fix synchronously at module load (static imports, sync fs calls)\n// so by the time ANY plugin worker starts spawning PTYs, the helper is\n// already executable.\n(function fixSpawnHelperPermissions() {\n if (!isNodeRuntime()) return;\n try {\n const req = createRequire(import.meta.url);\n const ptyPkg = req.resolve(\"node-pty/package.json\");\n const ptyDir = path.dirname(ptyPkg);\n const helper = path.join(\n ptyDir,\n \"prebuilds\",\n `${process.platform}-${process.arch}`,\n \"spawn-helper\",\n );\n if (fs.existsSync(helper)) {\n const mode = fs.statSync(helper).mode;\n if (!(mode & 0o100)) {\n fs.chmodSync(helper, 0o755);\n console.log(\n `[terminal] Fixed non-executable node-pty spawn-helper at ${helper}`,\n );\n }\n }\n } catch (err) {\n // node-pty not installed → stay silent here; createTerminalPlugin emits\n // the \"install node-pty\" message when the PTY server actually fails to\n // start. Logging twice for the same root cause just adds noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"MODULE_NOT_FOUND\" || code === \"ERR_MODULE_NOT_FOUND\") return;\n console.warn(\n \"[terminal] Could not verify node-pty spawn-helper permissions:\",\n (err as Error).message,\n );\n }\n})();\n\nexport interface TerminalPluginOptions {\n /** CLI command to run. Defaults to AGENT_CLI_COMMAND env or 'builder' */\n command?: string;\n /** Port for the WebSocket server. Defaults to AGENT_TERMINAL_PORT env or auto-assigned */\n port?: number;\n /** Enable in production. Defaults to AGENT_TERMINAL_ENABLED env or false in prod */\n enabledInProduction?: boolean;\n /** Auth check for WebSocket connections in production */\n authCheck?: (req: any) => boolean | Promise<boolean>;\n}\n\n// Vite's dev server can initialize Nitro plugins more than once during boot.\n// Module-scope flags ensure the \"node-pty not installed\" / \"Disabled in\n// production\" / \"Frame detected\" notices each fire at most once per process.\nlet _ptyMissingLogged = false;\nlet _disabledLogged = false;\nlet _frameDetectedLogged = false;\n\nexport function createTerminalPlugin(options: TerminalPluginOptions = {}) {\n return async (nitroApp: any) => {\n // Terminal requires Node.js (PTY, child_process) — skip on edge runtimes\n if (!isNodeRuntime()) return;\n\n // Always mount /_agent-native/available-clis so the client doesn't get 404s\n getH3App(nitroApp).use(\n \"/_agent-native/available-clis\",\n defineEventHandler(async () => {\n try {\n const { CLI_REGISTRY, commandExists } =\n await import(\"./cli-registry.js\");\n const results = [];\n for (const [cmd, entry] of Object.entries(CLI_REGISTRY)) {\n results.push({\n command: cmd,\n label: entry.label,\n available: await commandExists(cmd),\n });\n }\n return results;\n } catch {\n return [];\n }\n }),\n );\n\n // Skip if running inside a frame\n if (process.env.FRAME_PORT) {\n if (!_frameDetectedLogged) {\n console.log(\"[terminal] Frame detected, skipping embedded terminal\");\n _frameDetectedLogged = true;\n }\n return;\n }\n\n const isProd = process.env.NODE_ENV === \"production\";\n const enabled =\n options.enabledInProduction ??\n (process.env.AGENT_TERMINAL_ENABLED === \"true\" || !isProd);\n\n if (!enabled) {\n if (!_disabledLogged) {\n console.log(\n \"[terminal] Disabled in production (set AGENT_TERMINAL_ENABLED=true to enable)\",\n );\n _disabledLogged = true;\n }\n // Mount a disabled info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({ available: false })),\n );\n return;\n }\n\n // Require authCheck in production to prevent unauthenticated shell access\n if (isProd && !options.authCheck) {\n console.error(\n \"[terminal] FATAL: authCheck is required when enabling the terminal in production. \" +\n \"Pass an authCheck function to createTerminalPlugin().\",\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: \"Terminal requires authCheck in production\",\n })),\n );\n return;\n }\n\n // Skip if a PTY server is already running (prevents leak on HMR rebuild)\n if (process.env.__AGENT_TERMINAL_RUNNING === \"true\") {\n const existingPort = process.env.AGENT_TERMINAL_PORT;\n console.log(\n `[terminal] PTY server already running on port ${existingPort}, skipping`,\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: existingPort ? parseInt(existingPort, 10) : 0,\n command:\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\",\n })),\n );\n return;\n }\n\n const command =\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\";\n const port =\n options.port ??\n (process.env.AGENT_TERMINAL_PORT\n ? parseInt(process.env.AGENT_TERMINAL_PORT, 10)\n : 0);\n\n // Mark as running BEFORE the async server start. The previous code only\n // set this AFTER `await createPtyWebSocketServer(...)`, which left a\n // TOCTOU window where two concurrent plugin invocations would both pass\n // the running-check, both spawn a server, and end up fighting for the\n // CLI's PTY pool — leading to `posix_spawnp failed` floods.\n process.env.__AGENT_TERMINAL_RUNNING = \"true\"; // guard:allow-env-mutation — process-wide running flag set once at boot, before any HTTP request handling, to coordinate concurrent plugin invocations\n\n try {\n const { createPtyWebSocketServer } = await import(\"./pty-server.js\");\n\n const result = await createPtyWebSocketServer({\n appDir: process.cwd(),\n command,\n port,\n authCheck: isProd ? options.authCheck : undefined,\n logPrefix: \"[terminal]\",\n });\n\n // Store port for other consumers\n process.env.AGENT_TERMINAL_PORT = String(result.port); // guard:allow-env-mutation — terminal subprocess port published once at boot, not per-request\n\n // Mount discovery endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: result.port,\n command,\n })),\n );\n\n // Cleanup on shutdown (use once to avoid listener leak on hot-reload)\n const cleanup = () => result.close();\n process.once(\"SIGTERM\", cleanup);\n process.once(\"SIGINT\", cleanup);\n process.once(\"exit\", cleanup);\n\n if (process.env.DEBUG)\n console.log(\n `[terminal] Agent terminal ready (command: ${command}, port: ${result.port})`,\n );\n } catch (err) {\n // Clear the running flag so a retry can spawn a fresh server\n delete process.env.__AGENT_TERMINAL_RUNNING; // guard:allow-env-mutation — terminal subprocess boot failed, clearing boot-time sentinel so a later plugin retry can start cleanly\n\n // Distinguish \"node-pty not installed\" (expected when the user opts\n // out of the terminal feature) from real failures (port conflict,\n // native binding mismatch). Native deps are optional — log as info\n // so the dev console isn't filled with red noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n const missingPty =\n code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n if (missingPty) {\n if (!_ptyMissingLogged) {\n console.log(\n \"[terminal] node-pty not installed — embedded terminal disabled. \" +\n \"Install with `pnpm add node-pty` to enable.\",\n );\n _ptyMissingLogged = true;\n }\n } else {\n console.error(\"[terminal] Failed to start PTY server:\", err);\n console.error(\n \"[terminal] If node-pty is installed but PTY fails to spawn, \" +\n \"try `pnpm rebuild node-pty` (common after switching Node \" +\n \"versions via fnm/nvm).\",\n );\n }\n\n // Mount a fallback info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: missingPty ? \"node-pty not installed\" : \"PTY server failed\",\n })),\n );\n }\n };\n}\n\n/** Pre-configured terminal plugin with defaults */\nexport const defaultTerminalPlugin = createTerminalPlugin();\n"]}
1
+ {"version":3,"file":"terminal-plugin.js","sourceRoot":"","sources":["../../src/terminal/terminal-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getH3App,\n markDefaultPluginProvided,\n} from \"../server/framework-request-handler.js\";\nimport { isNodeRuntime } from \"../shared/runtime.js\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\n/**\n * Nitro Plugin — Agent Terminal\n *\n * Starts a PTY WebSocket server alongside the app so the <AgentTerminal />\n * component can connect to a real CLI. Mounts a discovery endpoint at\n * /_agent-native/agent-terminal-info for the client component.\n *\n * Skips activation when running inside a frame (FRAME_PORT is set).\n */\n\nimport { defineEventHandler } from \"h3\";\n\n// ─── module-load self-heal: chmod node-pty's spawn-helper ─────────────────\n// pnpm can extract node-pty's prebuilds tarball without running the\n// post-install that chmods spawn-helper, leaving it as `-rw-r--r--` instead\n// of `-rwxr-xr-x`. Every PTY spawn then fails with `posix_spawnp failed`.\n// Run the fix synchronously at module load (static imports, sync fs calls)\n// so by the time ANY plugin worker starts spawning PTYs, the helper is\n// already executable.\n(function fixSpawnHelperPermissions() {\n if (!isNodeRuntime()) return;\n try {\n const req = createRequire(import.meta.url);\n const ptyPkg = req.resolve(\"node-pty/package.json\");\n const ptyDir = path.dirname(ptyPkg);\n const helper = path.join(\n ptyDir,\n \"prebuilds\",\n `${process.platform}-${process.arch}`,\n \"spawn-helper\",\n );\n if (fs.existsSync(helper)) {\n const mode = fs.statSync(helper).mode;\n if (!(mode & 0o100)) {\n fs.chmodSync(helper, 0o755);\n console.log(\n `[terminal] Fixed non-executable node-pty spawn-helper at ${helper}`,\n );\n }\n }\n } catch (err) {\n // node-pty not installed → stay silent here; createTerminalPlugin emits\n // the \"install node-pty\" message when the PTY server actually fails to\n // start. Logging twice for the same root cause just adds noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"MODULE_NOT_FOUND\" || code === \"ERR_MODULE_NOT_FOUND\") return;\n console.warn(\n \"[terminal] Could not verify node-pty spawn-helper permissions:\",\n (err as Error).message,\n );\n }\n})();\n\nexport interface TerminalPluginOptions {\n /** CLI command to run. Defaults to AGENT_CLI_COMMAND env or 'builder' */\n command?: string;\n /** Port for the WebSocket server. Defaults to AGENT_TERMINAL_PORT env or auto-assigned */\n port?: number;\n /** Enable in production. Defaults to AGENT_TERMINAL_ENABLED env or false in prod */\n enabledInProduction?: boolean;\n /** Auth check for WebSocket connections in production */\n authCheck?: (req: any) => boolean | Promise<boolean>;\n}\n\n// Vite's dev server can initialize Nitro plugins more than once during boot.\n// Module-scope flags ensure the \"node-pty not installed\" / \"Disabled in\n// production\" / \"Frame detected\" notices each fire at most once per process.\nlet _ptyMissingLogged = false;\nlet _disabledLogged = false;\nlet _frameDetectedLogged = false;\n\nexport function createTerminalPlugin(options: TerminalPluginOptions = {}) {\n return async (nitroApp: any) => {\n markDefaultPluginProvided(nitroApp, \"terminal\");\n // Terminal requires Node.js (PTY, child_process) — skip on edge runtimes\n if (!isNodeRuntime()) return;\n\n // Always mount /_agent-native/available-clis so the client doesn't get 404s\n getH3App(nitroApp).use(\n \"/_agent-native/available-clis\",\n defineEventHandler(async () => {\n try {\n const { CLI_REGISTRY, commandExists } =\n await import(\"./cli-registry.js\");\n const results = [];\n for (const [cmd, entry] of Object.entries(CLI_REGISTRY)) {\n results.push({\n command: cmd,\n label: entry.label,\n available: await commandExists(cmd),\n });\n }\n return results;\n } catch {\n return [];\n }\n }),\n );\n\n // Skip if running inside a frame\n if (process.env.FRAME_PORT) {\n if (!_frameDetectedLogged) {\n console.log(\"[terminal] Frame detected, skipping embedded terminal\");\n _frameDetectedLogged = true;\n }\n return;\n }\n\n const isProd = process.env.NODE_ENV === \"production\";\n const enabled =\n options.enabledInProduction ??\n (process.env.AGENT_TERMINAL_ENABLED === \"true\" || !isProd);\n\n if (!enabled) {\n if (!_disabledLogged) {\n console.log(\n \"[terminal] Disabled in production (set AGENT_TERMINAL_ENABLED=true to enable)\",\n );\n _disabledLogged = true;\n }\n // Mount a disabled info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({ available: false })),\n );\n return;\n }\n\n // Require authCheck in production to prevent unauthenticated shell access\n if (isProd && !options.authCheck) {\n console.error(\n \"[terminal] FATAL: authCheck is required when enabling the terminal in production. \" +\n \"Pass an authCheck function to createTerminalPlugin().\",\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: \"Terminal requires authCheck in production\",\n })),\n );\n return;\n }\n\n // Skip if a PTY server is already running (prevents leak on HMR rebuild)\n if (process.env.__AGENT_TERMINAL_RUNNING === \"true\") {\n const existingPort = process.env.AGENT_TERMINAL_PORT;\n console.log(\n `[terminal] PTY server already running on port ${existingPort}, skipping`,\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: existingPort ? parseInt(existingPort, 10) : 0,\n command:\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\",\n })),\n );\n return;\n }\n\n const command =\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\";\n const port =\n options.port ??\n (process.env.AGENT_TERMINAL_PORT\n ? parseInt(process.env.AGENT_TERMINAL_PORT, 10)\n : 0);\n\n // Mark as running BEFORE the async server start. The previous code only\n // set this AFTER `await createPtyWebSocketServer(...)`, which left a\n // TOCTOU window where two concurrent plugin invocations would both pass\n // the running-check, both spawn a server, and end up fighting for the\n // CLI's PTY pool — leading to `posix_spawnp failed` floods.\n process.env.__AGENT_TERMINAL_RUNNING = \"true\"; // guard:allow-env-mutation — process-wide running flag set once at boot, before any HTTP request handling, to coordinate concurrent plugin invocations\n\n try {\n const { createPtyWebSocketServer } = await import(\"./pty-server.js\");\n\n const result = await createPtyWebSocketServer({\n appDir: process.cwd(),\n command,\n port,\n authCheck: isProd ? options.authCheck : undefined,\n logPrefix: \"[terminal]\",\n });\n\n // Store port for other consumers\n process.env.AGENT_TERMINAL_PORT = String(result.port); // guard:allow-env-mutation — terminal subprocess port published once at boot, not per-request\n\n // Mount discovery endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: result.port,\n command,\n })),\n );\n\n // Cleanup on shutdown (use once to avoid listener leak on hot-reload)\n const cleanup = () => result.close();\n process.once(\"SIGTERM\", cleanup);\n process.once(\"SIGINT\", cleanup);\n process.once(\"exit\", cleanup);\n\n if (process.env.DEBUG)\n console.log(\n `[terminal] Agent terminal ready (command: ${command}, port: ${result.port})`,\n );\n } catch (err) {\n // Clear the running flag so a retry can spawn a fresh server\n delete process.env.__AGENT_TERMINAL_RUNNING; // guard:allow-env-mutation — terminal subprocess boot failed, clearing boot-time sentinel so a later plugin retry can start cleanly\n\n // Distinguish \"node-pty not installed\" (expected when the user opts\n // out of the terminal feature) from real failures (port conflict,\n // native binding mismatch). Native deps are optional — log as info\n // so the dev console isn't filled with red noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n const missingPty =\n code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n if (missingPty) {\n if (!_ptyMissingLogged) {\n console.log(\n \"[terminal] node-pty not installed — embedded terminal disabled. \" +\n \"Install with `pnpm add node-pty` to enable.\",\n );\n _ptyMissingLogged = true;\n }\n } else {\n console.error(\"[terminal] Failed to start PTY server:\", err);\n console.error(\n \"[terminal] If node-pty is installed but PTY fails to spawn, \" +\n \"try `pnpm rebuild node-pty` (common after switching Node \" +\n \"versions via fnm/nvm).\",\n );\n }\n\n // Mount a fallback info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: missingPty ? \"node-pty not installed\" : \"PTY server failed\",\n })),\n );\n }\n };\n}\n\n/** Pre-configured terminal plugin with defaults */\nexport const defaultTerminalPlugin = createTerminalPlugin();\n"]}
@@ -11,16 +11,18 @@ Agent-to-agent communication over HTTP. Agents discover each other, send message
11
11
 
12
12
  A2A (agent-to-agent) is a JSON-RPC protocol for inter-agent communication. A mail agent can ask an analytics agent to run a query. A calendar agent can search issues in a project management agent. Each agent exposes its capabilities via an agent card and accepts work via a standard JSON-RPC endpoint.
13
13
 
14
+ A2A is the substrate for cross-app delegation in this framework — most prominently for [Dispatch](/docs/dispatch), which routes a single inbound message (Slack, email, etc.) to whichever app in the workspace is best suited to handle it.
15
+
14
16
  Key concepts:
15
17
 
16
18
  - **Agent card** — public metadata at `/.well-known/agent-card.json` describing skills and capabilities
17
- - **JSON-RPC** — all communication goes through `POST /a2a` with standard JSON-RPC 2.0
19
+ - **JSON-RPC** — agent-native apps use `POST /_agent-native/a2a`; external/legacy peers may use `POST /a2a`
18
20
  - **Tasks** — each message creates a task with a lifecycle (submitted, working, completed, failed, canceled)
19
- - **Bearer auth** — optional API key authentication via environment variable
21
+ - **JWT bearer auth** — production A2A requires `A2A_SECRET` or an explicit legacy `apiKeyEnv`
20
22
 
21
23
  ## Server setup {#server-setup}
22
24
 
23
- Call `mountA2A()` in a server plugin to expose the A2A endpoints:
25
+ Most templates get A2A through the framework agent chat plugin. If you are mounting it yourself, call `mountA2A()` in a server plugin:
24
26
 
25
27
  ```ts
26
28
  // server/plugins/a2a.ts
@@ -39,18 +41,30 @@ export default defineNitroPlugin((nitro) => {
39
41
  examples: ["Show me signups by source this month"],
40
42
  },
41
43
  ],
42
- apiKeyEnv: "A2A_API_KEY", // env var name for bearer token
44
+ // Optional legacy external-peer bearer key. Prefer A2A_SECRET for
45
+ // agent-native workspace calls and production deployments.
46
+ apiKeyEnv: "A2A_API_KEY",
43
47
  streaming: true, // enable message/stream
44
48
  });
45
49
  });
46
50
  ```
47
51
 
48
- This mounts two endpoints: `GET /.well-known/agent-card.json` (public, no auth) and `POST /a2a` (authenticated JSON-RPC).
52
+ This mounts:
53
+
54
+ - `GET /.well-known/agent-card.json` — public discovery metadata.
55
+ - `POST /_agent-native/a2a` — primary agent-native JSON-RPC endpoint.
56
+ - `POST /_agent-native/a2a/_process-task` — internal async processor route, signed with `A2A_SECRET`.
57
+
58
+ The client also falls back to `/a2a` for external agents that expose the legacy/simple path. Production agent-native deployments should set `A2A_SECRET`; without it, hosted runtimes fail closed instead of accepting unauthenticated remote work.
49
59
 
50
60
  ## Agent card {#agent-card}
51
61
 
52
62
  The agent card is auto-generated from your config and served at `/.well-known/agent-card.json`. Other agents fetch it to discover your agent's skills.
53
63
 
64
+ ### Per-tenant skill filtering {#agent-card-filtering}
65
+
66
+ The card endpoint is public, so the framework redacts skills whose IDs reveal per-user or per-org integrations before serving it. Any skill whose id starts with `mcp__user_<emailhash>_…` or `mcp__org_<orgid>_…` is dropped from the published card. Operator-controlled stdio MCP tools (loaded from `mcp.config.json`) and template-defined skills stay visible. This prevents an unauthenticated caller from fingerprinting which tenants exist or which integrations they have connected. See `packages/core/src/a2a/server.ts`.
67
+
54
68
  ```json
55
69
  {
56
70
  "name": "Analytics Agent",
@@ -81,14 +95,16 @@ The agent card is auto-generated from your config and served at `/.well-known/ag
81
95
 
82
96
  ## JSON-RPC methods {#json-rpc-methods}
83
97
 
84
- All methods are called via `POST /a2a` with JSON-RPC 2.0 format:
98
+ All methods are called via `POST /_agent-native/a2a` with JSON-RPC 2.0 format:
99
+
100
+ | Method | Description | Key params |
101
+ | ---------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
102
+ | `message/send` | Send a message and wait for the completed task. Pass `async: true` to return immediately in `working` state and poll. | `message, contextId?, async?` |
103
+ | `message/stream` | Send a message, receive SSE task updates | `message, contextId?` |
104
+ | `tasks/get` | Fetch a task by ID — used to poll an async task to completion | `id` |
105
+ | `tasks/cancel` | Cancel a running task | `id` |
85
106
 
86
- | Method | Description | Key params |
87
- | ---------------- | ----------------------------------------- | --------------------- |
88
- | `message/send` | Send a message, get a completed task back | `message, contextId?` |
89
- | `message/stream` | Send a message, receive SSE task updates | `message, contextId?` |
90
- | `tasks/get` | Fetch a task by ID | `id` |
91
- | `tasks/cancel` | Cancel a running task | `id` |
107
+ When `message/send` is called with `async: true`, the JSON-RPC handler enqueues the task and self-fires a POST to an internal `/_agent-native/a2a/_process-task` route so the handler runs in a fresh function execution with its own full timeout. This route is authenticated with an HMAC token bound to the task ID (5-minute lifetime, signed with `A2A_SECRET`). It is mounted before the `/_agent-native/a2a` JSON-RPC route so h3's prefix matching does not swallow it.
92
108
 
93
109
  Messages contain typed parts:
94
110
 
@@ -171,7 +187,9 @@ Tasks persist in the `a2a_tasks` SQL table and can be retrieved later via `tasks
171
187
 
172
188
  ## Security {#security}
173
189
 
174
- Set `apiKeyEnv` in your config to the name of an environment variable containing the expected bearer token:
190
+ Set `A2A_SECRET` on every production app that calls or receives A2A traffic. Agent-native callers sign JWT bearer tokens with this secret so receivers can verify the caller identity before the agent loop starts.
191
+
192
+ For external peers that still use a shared static token, set `apiKeyEnv` in your config to the name of an environment variable containing the expected bearer token:
175
193
 
176
194
  ```ts
177
195
  // Config
@@ -184,7 +202,68 @@ mountA2A(app, {
184
202
  const client = new A2AClient(url, process.env.A2A_API_KEY);
185
203
  ```
186
204
 
187
- The agent card endpoint is always public (no auth) so other agents can discover capabilities. The `/a2a` JSON-RPC endpoint requires a valid bearer token when `apiKeyEnv` is set. In dev mode (no env var configured), auth is skipped.
205
+ The agent card endpoint is always public (no auth) so other agents can discover capabilities. The `/_agent-native/a2a` JSON-RPC endpoint accepts JWT bearer tokens signed by `A2A_SECRET`, and also accepts the legacy `apiKeyEnv` token when configured. In local development, auth can be omitted; in hosted production runtimes, missing A2A auth returns 503 instead of running unauthenticated.
206
+
207
+ ### Auth policy boundary {#auth-policy}
208
+
209
+ Bearer validation runs at the request boundary — in the JSON-RPC handler — before the agent loop ever sees the message. The shared helpers in `packages/core/src/a2a/auth-policy.ts` decide what the deployment requires:
210
+
211
+ - `isA2AProductionRuntime()` returns `true` on Netlify, AWS Lambda, Cloudflare Pages/Workers, Vercel, Render, Fly, and Cloud Run — even when `NODE_ENV` isn't `"production"`. Some serverless providers don't set `NODE_ENV` consistently, so the policy reads provider-specific flags too.
212
+ - `hasConfiguredA2ASecret()` returns `true` when `A2A_SECRET` is set.
213
+ - `shouldAdvertiseJwtA2AAuth()` is what the agent card uses to decide whether to publish a `jwtBearer` security scheme.
214
+
215
+ The production policy is strict: in any production runtime, the async `_process-task` route refuses to dispatch unless `A2A_SECRET` is configured (returns 503), and the JSON-RPC endpoint refuses unauthenticated calls. The dev fallback (warn once, allow) only fires when no production flag is set.
216
+
217
+ This boundary matters because the agent loop accepts free-form input from a remote caller. Putting the bearer check inside the loop, or relying on a tool to enforce it, would let prompt-injection or a buggy handler bypass auth. Keeping it at the HTTP boundary means a token failure short-circuits before any LLM call.
218
+
219
+ JWT verification (`verifyA2AToken` in `server.ts`) accepts tokens signed with either the global `A2A_SECRET` or an org-scoped secret looked up from SQL via the token's `org_domain` claim, and enforces the token's own `aud`/`iss` claims when present.
220
+
221
+ ## Continuations {#continuations}
222
+
223
+ When an agent calls a remote A2A peer that doesn't return immediately, the framework polls `tasks/get` until the task settles. This is wired through `A2AClient.sendAndWait`, which is the default mode used by the `callAgent()` helper.
224
+
225
+ ```ts
226
+ // Default: async + poll (safe on serverless hosts)
227
+ const reply = await callAgent(url, "Generate the quarterly report", {
228
+ userEmail: session.user.email,
229
+ });
230
+
231
+ // Single-shot blocking POST (avoid on Netlify/Vercel for slow handlers)
232
+ const reply2 = await callAgent(url, "Quick lookup", { async: false });
233
+ ```
234
+
235
+ For inbound continuations triggered by a messaging integration (Slack, email), the framework persists the continuation in SQL and processes it out-of-band:
236
+
237
+ - A row is written to the `a2a_continuations` table when the integration handler hands off to a remote agent.
238
+ - A self-fired `POST /_agent-native/integrations/process-a2a-continuation` claims the row, calls `tasks/get` on the remote agent, and either delivers the reply to the integration adapter or reschedules.
239
+ - If the remote task is still working, the row is rescheduled and re-dispatched. The poll budget is **bounded by ~10 minutes of remote work** (`MAX_REMOTE_WORK_MS`) and **6 dispatch attempts** (`MAX_ATTEMPTS`); after either limit, the continuation is failed with a clear error and the user gets a "the agent didn't respond in time" reply.
240
+ - A recurring sweeper (`claimDueA2AContinuations`) re-claims any continuation rows that were left in flight when the previous function execution died. Even if the calling app crashes mid-poll, the next sweep tick resumes the work.
241
+
242
+ Defined in `packages/core/src/integrations/a2a-continuation-processor.ts`. The same retry job pattern is used for integration webhook tasks (`pending-tasks-retry-job.ts`, capped at 3 attempts).
243
+
244
+ ## Workspace A2A {#workspace-a2a}
245
+
246
+ In a multi-app workspace deployed to a single Netlify site (see [multi-app workspace](/docs/multi-app-workspace)), every app under `apps/<id>/` is auto-registered as an A2A peer:
247
+
248
+ - A shared `A2A_SECRET` is mounted into every app's environment at build time.
249
+ - Cross-app calls are same-origin — `https://workspace.example.com/apps/analytics` calls `https://workspace.example.com/apps/mail` — so there is no DNS, CORS, or per-pair JWT setup.
250
+ - Outbound calls signed with the shared secret carry the caller's email as `sub` and (when present) the org domain. The receiver's JWT verifier accepts either the shared secret or the org-scoped secret from SQL, in that order.
251
+ - Agent discovery walks the workspace registry rather than relying on the operator to wire each peer by hand. See `discoverAgents` in `packages/core/src/server/agent-discovery.ts` and the org refresh path in `packages/core/src/org/handlers.ts`.
252
+
253
+ External A2A — calls to agents outside your workspace — still uses the bearer-token model (`apiKeyEnv` + `A2AClient(url, apiKey)`). Workspace A2A is layered on top; nothing about external peers changes.
254
+
255
+ ## Serverless gotchas {#serverless}
256
+
257
+ **Never rely on a fire-and-forget `Promise` outliving the response.** Serverless functions (Netlify, Vercel, AWS Lambda, Cloud Run) freeze the moment the response body is flushed — sometimes before the TCP handshake of an unawaited `fetch(...)` even completes. Patterns that work locally on Node will silently drop work in production.
258
+
259
+ The framework's pattern, used by both A2A async dispatch and the [integration webhook queue](/docs/messaging), is:
260
+
261
+ 1. Accept the request, persist what needs to happen to SQL, return 200 immediately.
262
+ 2. Self-fire a `POST` to a separate framework route (`/_agent-native/a2a/_process-task` or `/_agent-native/integrations/process-task`) so the actual work runs in a **fresh function execution** with its own full timeout.
263
+ 3. Authenticate the self-fire with an HMAC token bound to the row id, signed with `A2A_SECRET`.
264
+ 4. A recurring retry job sweeps any rows that were claimed but not finished, so a crashed function doesn't strand the work.
265
+
266
+ When you write your own A2A handler or integration adapter, follow the same shape. Don't attach work to a detached promise after `return`. If you must self-fire from a serverless handler, start the fetch before returning and give it a tiny head start (the framework uses a short timeout) so Lambda-style runtimes do not freeze before the outbound request leaves the process. The `integration-webhooks` skill is the canonical reference.
188
267
 
189
268
  ## Agent mentions {#agent-mentions}
190
269
 
@@ -60,7 +60,7 @@ Agents become available for mentioning through several mechanisms:
60
60
 
61
61
  - **Custom workspace agents** — create agent profiles in the Workspace tab as `agents/*.md`
62
62
  - **Auto-discovery** — the framework automatically discovers connected agents running on known ports or configured URLs
63
- - **Remote manifests** — add connected-agent manifests as `agents/*.json`
63
+ - **Remote manifests** — add connected-agent manifests as `remote-agents/*.json`
64
64
 
65
65
  ### Custom workspace agents
66
66
 
@@ -91,7 +91,7 @@ You can create them from the Workspace tab using:
91
91
  Remote A2A agents still use JSON manifests:
92
92
 
93
93
  ```json
94
- // agents/analytics.json
94
+ // remote-agents/analytics.json
95
95
  {
96
96
  "name": "Analytics Agent",
97
97
  "url": "https://analytics.example.com",
@@ -52,12 +52,12 @@ import { spawnTask } from "@agent-native/core/server";
52
52
 
53
53
  const task = await spawnTask({
54
54
  description: "Draft an outreach email to this lead",
55
- instructions: "Match Steve's voice from learnings.md.",
55
+ instructions: "Match Steve's voice from memory/MEMORY.md.",
56
56
  ownerEmail: user.email,
57
57
  systemPrompt: mailAgentSystemPrompt,
58
58
  actions: mailActions,
59
59
  apiKey: process.env.ANTHROPIC_API_KEY!,
60
- parentSend: emit, // SSE emit function for the parent chat stream
60
+ parentSend: emit, // streaming sender for the parent chat response
61
61
  });
62
62
  ```
63
63
 
@@ -158,7 +158,7 @@ function App() {
158
158
  | `queryClient` | `QueryClient?` | React-query client for cache invalidation |
159
159
  | `queryKeys` | `string[]?` | Query key prefixes to invalidate. Default: `["file", "fileTree"]` |
160
160
  | `pollUrl` | `string?` | Poll endpoint URL. Default: `"/_agent-native/poll"` |
161
- | `onEvent` | `(data) => void` | Optional callback for each SSE event |
161
+ | `onEvent` | `(data) => void` | Optional callback when a poll detects a newer sync version |
162
162
 
163
163
  ## cn(...inputs) {#cn}
164
164
 
@@ -15,19 +15,19 @@ We call them **cloneable SaaS**, not templates. You're not starting from scratch
15
15
 
16
16
  Each one is a real app you could use today, and the launching pad for your own version of it.
17
17
 
18
- | Template | What it is |
19
- | ------------- | --------------------------------------------------------------------------------------------------------- |
20
- | **Mail** | An agent-native Superhuman. Inbox, labels, AI triage, keyboard-first, drafts and sends through the agent. |
21
- | **Calendar** | An agent-native Google Calendar. Events, sync, public booking links, agent-driven scheduling. |
22
- | **Content** | An agent-native Notion / Google Docs. Markdown + Tiptap editor, Notion sync, real-time multi-user collab. |
23
- | **Slides** | An agent-native Google Slides. React-based decks the agent generates and edits directly. |
24
- | **Video** | An agent-native video editor on Remotion. Prompt for a cut, the agent assembles it. |
25
- | **Analytics** | An agent-native Amplitude/Mixpanel. Connect data sources, prompt for charts, pin to dashboards. |
26
- | **Clips** | An agent-native Loom. Async screen + camera recording with transcription, chapters, AI summaries. |
27
- | **Design** | An agent-native Figma/Canva. Vector design tool the agent can edit alongside you. |
28
- | **Forms** | An agent-native Typeform. Build, share, and collect; the agent handles schema and submission analysis. |
29
- | **Dispatch** | The workspace control plane: shared secrets, cross-app integrations, Slack/Telegram, scheduled jobs. |
30
- | **Starter** | The minimal scaffold. Agent chat plus the architecture, nothing else. Build something new. |
18
+ | Template | What it is |
19
+ | ------------- | -------------------------------------------------------------------------------------------------------------- |
20
+ | **Mail** | An agent-native Superhuman. Inbox, labels, AI triage, keyboard-first, drafts and sends through the agent. |
21
+ | **Calendar** | An agent-native Google Calendar. Events, sync, public booking links, agent-driven scheduling. |
22
+ | **Content** | An agent-native Notion / Google Docs. Markdown + Tiptap editor, Notion sync, real-time multi-user collab. |
23
+ | **Slides** | An agent-native Google Slides. React-based decks the agent generates and edits directly. |
24
+ | **Video** | An agent-native video editor on Remotion. Prompt for a cut, the agent assembles it. |
25
+ | **Analytics** | An agent-native Amplitude/Mixpanel. Connect data sources, prompt for charts, pin to dashboards. |
26
+ | **Clips** | An agent-native Loom. Async screen + camera recording with transcription, chapters, AI summaries. |
27
+ | **Design** | Agent-native HTML prototyping studio for interactive Alpine/Tailwind designs. |
28
+ | **Forms** | An agent-native Typeform. Build, share, collect, and route submissions to Slack, Sheets, webhooks, or Discord. |
29
+ | **Dispatch** | The workspace control plane: shared secrets, cross-app integrations, Slack/Telegram, scheduled jobs. |
30
+ | **Starter** | The minimal scaffold. Agent chat plus the architecture, nothing else. Build something new. |
31
31
 
32
32
  See the full catalog under [Templates](/templates), or jump straight to one — for example, [Dispatch](/docs/template-dispatch) is a great place to start if you want a workspace-style app.
33
33