@agent-native/core 0.7.19 → 0.7.20

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 (258) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  3. package/dist/agent/engine/builder-engine.js +45 -2
  4. package/dist/agent/engine/builder-engine.js.map +1 -1
  5. package/dist/agent/loop-settings.d.ts +37 -0
  6. package/dist/agent/loop-settings.d.ts.map +1 -0
  7. package/dist/agent/loop-settings.js +127 -0
  8. package/dist/agent/loop-settings.js.map +1 -0
  9. package/dist/agent/production-agent.d.ts +8 -0
  10. package/dist/agent/production-agent.d.ts.map +1 -1
  11. package/dist/agent/production-agent.js +268 -29
  12. package/dist/agent/production-agent.js.map +1 -1
  13. package/dist/agent/run-manager.d.ts.map +1 -1
  14. package/dist/agent/run-manager.js +76 -3
  15. package/dist/agent/run-manager.js.map +1 -1
  16. package/dist/agent/run-store.d.ts +1 -1
  17. package/dist/agent/run-store.d.ts.map +1 -1
  18. package/dist/agent/run-store.js +65 -2
  19. package/dist/agent/run-store.js.map +1 -1
  20. package/dist/agent/thread-data-builder.d.ts +3 -0
  21. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  22. package/dist/agent/thread-data-builder.js +52 -10
  23. package/dist/agent/thread-data-builder.js.map +1 -1
  24. package/dist/agent/tool-search.d.ts +37 -0
  25. package/dist/agent/tool-search.d.ts.map +1 -0
  26. package/dist/agent/tool-search.js +201 -0
  27. package/dist/agent/tool-search.js.map +1 -0
  28. package/dist/agent/types.d.ts +8 -1
  29. package/dist/agent/types.d.ts.map +1 -1
  30. package/dist/agent/types.js.map +1 -1
  31. package/dist/cli/create.d.ts.map +1 -1
  32. package/dist/cli/create.js +44 -9
  33. package/dist/cli/create.js.map +1 -1
  34. package/dist/cli/workspacify.d.ts +2 -0
  35. package/dist/cli/workspacify.d.ts.map +1 -1
  36. package/dist/cli/workspacify.js +34 -1
  37. package/dist/cli/workspacify.js.map +1 -1
  38. package/dist/client/AssistantChat.d.ts.map +1 -1
  39. package/dist/client/AssistantChat.js +277 -18
  40. package/dist/client/AssistantChat.js.map +1 -1
  41. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  42. package/dist/client/ConnectBuilderCard.js +1 -1
  43. package/dist/client/ConnectBuilderCard.js.map +1 -1
  44. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  45. package/dist/client/MultiTabAssistantChat.js +14 -6
  46. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  47. package/dist/client/NewWorkspaceAppFlow.d.ts +14 -0
  48. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -0
  49. package/dist/client/NewWorkspaceAppFlow.js +200 -0
  50. package/dist/client/NewWorkspaceAppFlow.js.map +1 -0
  51. package/dist/client/PoweredByBadge.d.ts +10 -1
  52. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  53. package/dist/client/PoweredByBadge.js +120 -8
  54. package/dist/client/PoweredByBadge.js.map +1 -1
  55. package/dist/client/agent-chat-adapter.d.ts +3 -5
  56. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  57. package/dist/client/agent-chat-adapter.js +26 -19
  58. package/dist/client/agent-chat-adapter.js.map +1 -1
  59. package/dist/client/agent-chat.d.ts.map +1 -1
  60. package/dist/client/agent-chat.js +15 -3
  61. package/dist/client/agent-chat.js.map +1 -1
  62. package/dist/client/analytics.d.ts +1 -1
  63. package/dist/client/analytics.d.ts.map +1 -1
  64. package/dist/client/analytics.js +141 -1
  65. package/dist/client/analytics.js.map +1 -1
  66. package/dist/client/builder-frame.d.ts +10 -0
  67. package/dist/client/builder-frame.d.ts.map +1 -0
  68. package/dist/client/builder-frame.js +94 -0
  69. package/dist/client/builder-frame.js.map +1 -0
  70. package/dist/client/composer/MentionPopover.d.ts.map +1 -1
  71. package/dist/client/composer/MentionPopover.js +5 -1
  72. package/dist/client/composer/MentionPopover.js.map +1 -1
  73. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  74. package/dist/client/composer/TiptapComposer.js +11 -6
  75. package/dist/client/composer/TiptapComposer.js.map +1 -1
  76. package/dist/client/error-format.d.ts +20 -1
  77. package/dist/client/error-format.d.ts.map +1 -1
  78. package/dist/client/error-format.js +53 -5
  79. package/dist/client/error-format.js.map +1 -1
  80. package/dist/client/index.d.ts +3 -1
  81. package/dist/client/index.d.ts.map +1 -1
  82. package/dist/client/index.js +3 -1
  83. package/dist/client/index.js.map +1 -1
  84. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  85. package/dist/client/onboarding/OnboardingPanel.js +88 -6
  86. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  87. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  88. package/dist/client/settings/SettingsPanel.js +145 -9
  89. package/dist/client/settings/SettingsPanel.js.map +1 -1
  90. package/dist/client/settings/useBuilderStatus.d.ts +13 -0
  91. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  92. package/dist/client/settings/useBuilderStatus.js +50 -9
  93. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  94. package/dist/client/sse-event-processor.d.ts +3 -0
  95. package/dist/client/sse-event-processor.d.ts.map +1 -1
  96. package/dist/client/sse-event-processor.js +88 -7
  97. package/dist/client/sse-event-processor.js.map +1 -1
  98. package/dist/client/tools/ToolsListPage.d.ts.map +1 -1
  99. package/dist/client/tools/ToolsListPage.js +16 -1
  100. package/dist/client/tools/ToolsListPage.js.map +1 -1
  101. package/dist/client/tools/ToolsSidebarSection.d.ts.map +1 -1
  102. package/dist/client/tools/ToolsSidebarSection.js +63 -8
  103. package/dist/client/tools/ToolsSidebarSection.js.map +1 -1
  104. package/dist/client/tools/tool-order.d.ts +7 -0
  105. package/dist/client/tools/tool-order.d.ts.map +1 -0
  106. package/dist/client/tools/tool-order.js +47 -0
  107. package/dist/client/tools/tool-order.js.map +1 -0
  108. package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -1
  109. package/dist/client/transcription/BuilderTranscriptionCta.js +71 -6
  110. package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -1
  111. package/dist/client/use-send-to-agent-chat.d.ts.map +1 -1
  112. package/dist/client/use-send-to-agent-chat.js +11 -3
  113. package/dist/client/use-send-to-agent-chat.js.map +1 -1
  114. package/dist/client/useProductionAgent.d.ts.map +1 -1
  115. package/dist/client/useProductionAgent.js +1 -1
  116. package/dist/client/useProductionAgent.js.map +1 -1
  117. package/dist/db/client.d.ts.map +1 -1
  118. package/dist/db/client.js +5 -1
  119. package/dist/db/client.js.map +1 -1
  120. package/dist/deploy/build.d.ts +1 -0
  121. package/dist/deploy/build.d.ts.map +1 -1
  122. package/dist/deploy/build.js +4 -1
  123. package/dist/deploy/build.js.map +1 -1
  124. package/dist/oauth-tokens/index.d.ts +1 -1
  125. package/dist/oauth-tokens/index.d.ts.map +1 -1
  126. package/dist/oauth-tokens/index.js +1 -1
  127. package/dist/oauth-tokens/index.js.map +1 -1
  128. package/dist/oauth-tokens/store.d.ts.map +1 -1
  129. package/dist/oauth-tokens/store.js +6 -0
  130. package/dist/oauth-tokens/store.js.map +1 -1
  131. package/dist/observability/store.d.ts.map +1 -1
  132. package/dist/observability/store.js +19 -19
  133. package/dist/observability/store.js.map +1 -1
  134. package/dist/onboarding/default-steps.d.ts.map +1 -1
  135. package/dist/onboarding/default-steps.js +95 -61
  136. package/dist/onboarding/default-steps.js.map +1 -1
  137. package/dist/onboarding/plugin.d.ts.map +1 -1
  138. package/dist/onboarding/plugin.js +17 -8
  139. package/dist/onboarding/plugin.js.map +1 -1
  140. package/dist/org/migrations.js +2 -2
  141. package/dist/org/migrations.js.map +1 -1
  142. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  143. package/dist/scripts/agent-engines/list-agent-engines.js +2 -3
  144. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  145. package/dist/scripts/db/exec.d.ts +2 -1
  146. package/dist/scripts/db/exec.d.ts.map +1 -1
  147. package/dist/scripts/db/exec.js +264 -61
  148. package/dist/scripts/db/exec.js.map +1 -1
  149. package/dist/scripts/db/schema.d.ts.map +1 -1
  150. package/dist/scripts/db/schema.js +16 -4
  151. package/dist/scripts/db/schema.js.map +1 -1
  152. package/dist/scripts/dev/index.d.ts.map +1 -1
  153. package/dist/scripts/dev/index.js +36 -11
  154. package/dist/scripts/dev/index.js.map +1 -1
  155. package/dist/scripts/manage-agent-loop-settings.d.ts +7 -0
  156. package/dist/scripts/manage-agent-loop-settings.d.ts.map +1 -0
  157. package/dist/scripts/manage-agent-loop-settings.js +63 -0
  158. package/dist/scripts/manage-agent-loop-settings.js.map +1 -0
  159. package/dist/scripts/runner.d.ts.map +1 -1
  160. package/dist/scripts/runner.js +11 -0
  161. package/dist/scripts/runner.js.map +1 -1
  162. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  163. package/dist/server/agent-chat-plugin.js +60 -18
  164. package/dist/server/agent-chat-plugin.js.map +1 -1
  165. package/dist/server/app-url.d.ts +5 -4
  166. package/dist/server/app-url.d.ts.map +1 -1
  167. package/dist/server/app-url.js +8 -4
  168. package/dist/server/app-url.js.map +1 -1
  169. package/dist/server/auth.d.ts +8 -0
  170. package/dist/server/auth.d.ts.map +1 -1
  171. package/dist/server/auth.js +82 -29
  172. package/dist/server/auth.js.map +1 -1
  173. package/dist/server/better-auth-instance.d.ts.map +1 -1
  174. package/dist/server/better-auth-instance.js +16 -5
  175. package/dist/server/better-auth-instance.js.map +1 -1
  176. package/dist/server/builder-browser.d.ts +12 -0
  177. package/dist/server/builder-browser.d.ts.map +1 -1
  178. package/dist/server/builder-browser.js +36 -4
  179. package/dist/server/builder-browser.js.map +1 -1
  180. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  181. package/dist/server/core-routes-plugin.js +350 -53
  182. package/dist/server/core-routes-plugin.js.map +1 -1
  183. package/dist/server/credential-provider.d.ts +21 -3
  184. package/dist/server/credential-provider.d.ts.map +1 -1
  185. package/dist/server/credential-provider.js +51 -21
  186. package/dist/server/credential-provider.js.map +1 -1
  187. package/dist/server/google-oauth.d.ts +3 -0
  188. package/dist/server/google-oauth.d.ts.map +1 -1
  189. package/dist/server/google-oauth.js +27 -3
  190. package/dist/server/google-oauth.js.map +1 -1
  191. package/dist/server/index.d.ts +4 -3
  192. package/dist/server/index.d.ts.map +1 -1
  193. package/dist/server/index.js +4 -3
  194. package/dist/server/index.js.map +1 -1
  195. package/dist/server/schema-prompt.d.ts.map +1 -1
  196. package/dist/server/schema-prompt.js +2 -1
  197. package/dist/server/schema-prompt.js.map +1 -1
  198. package/dist/server/security-headers.d.ts +3 -0
  199. package/dist/server/security-headers.d.ts.map +1 -1
  200. package/dist/server/security-headers.js +7 -1
  201. package/dist/server/security-headers.js.map +1 -1
  202. package/dist/server/ssr-handler.d.ts.map +1 -1
  203. package/dist/server/ssr-handler.js +24 -4
  204. package/dist/server/ssr-handler.js.map +1 -1
  205. package/dist/templates/default/_gitignore +5 -1
  206. package/dist/templates/default/app/root.tsx +1 -0
  207. package/dist/templates/default/public/favicon.svg +3 -3
  208. package/dist/templates/default/public/icon-180.svg +3 -3
  209. package/dist/templates/default/public/icon-192.svg +3 -3
  210. package/dist/templates/default/public/icon-512.svg +3 -3
  211. package/dist/templates/workspace-core/AGENTS.md +23 -7
  212. package/dist/templates/workspace-core/package.json +2 -1
  213. package/dist/templates/workspace-core/src/credentials.ts +22 -11
  214. package/dist/templates/workspace-root/.env.example +7 -0
  215. package/dist/templates/workspace-root/README.md +6 -3
  216. package/dist/templates/workspace-root/_gitignore +3 -0
  217. package/dist/templates/workspace-root/package.json +3 -1
  218. package/dist/templates/workspace-root/scripts/workspace-dev.ts +410 -0
  219. package/dist/tools/actions.d.ts.map +1 -1
  220. package/dist/tools/actions.js +2 -0
  221. package/dist/tools/actions.js.map +1 -1
  222. package/dist/tools/html-shell.d.ts.map +1 -1
  223. package/dist/tools/html-shell.js +13 -1
  224. package/dist/tools/html-shell.js.map +1 -1
  225. package/dist/tools/store.d.ts.map +1 -1
  226. package/dist/tools/store.js +10 -10
  227. package/dist/tools/store.js.map +1 -1
  228. package/dist/tracking/providers.d.ts +1 -0
  229. package/dist/tracking/providers.d.ts.map +1 -1
  230. package/dist/tracking/providers.js +72 -0
  231. package/dist/tracking/providers.js.map +1 -1
  232. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  233. package/dist/vite/action-types-plugin.js +106 -9
  234. package/dist/vite/action-types-plugin.js.map +1 -1
  235. package/dist/vite/client.d.ts.map +1 -1
  236. package/dist/vite/client.js +67 -2
  237. package/dist/vite/client.js.map +1 -1
  238. package/docs/content/authentication.md +17 -13
  239. package/docs/content/deployment.md +11 -11
  240. package/docs/content/mcp-clients.md +2 -2
  241. package/docs/content/onboarding.md +32 -30
  242. package/docs/content/security.md +1 -1
  243. package/docs/content/tools.md +4 -0
  244. package/package.json +2 -2
  245. package/src/templates/default/_gitignore +5 -1
  246. package/src/templates/default/app/root.tsx +1 -0
  247. package/src/templates/default/public/favicon.svg +3 -3
  248. package/src/templates/default/public/icon-180.svg +3 -3
  249. package/src/templates/default/public/icon-192.svg +3 -3
  250. package/src/templates/default/public/icon-512.svg +3 -3
  251. package/src/templates/workspace-core/AGENTS.md +23 -7
  252. package/src/templates/workspace-core/package.json +2 -1
  253. package/src/templates/workspace-core/src/credentials.ts +22 -11
  254. package/src/templates/workspace-root/.env.example +7 -0
  255. package/src/templates/workspace-root/README.md +6 -3
  256. package/src/templates/workspace-root/_gitignore +3 -0
  257. package/src/templates/workspace-root/package.json +3 -1
  258. package/src/templates/workspace-root/scripts/workspace-dev.ts +410 -0
@@ -12,17 +12,18 @@
12
12
  * DATABASE_URL by default, so storing a credential once makes it
13
13
  * available everywhere.
14
14
  *
15
- * Once @agent-native/core publishes the upcoming 2-arg signature you can
16
- * extend this to take a `{ userEmail, orgId }` context and pass it through
17
- * for per-user / per-org scoping. The current shape works against both
18
- * versions — the published 1-arg signature ignores the second argument.
15
+ * A request/action context is required so credentials stay scoped to the
16
+ * correct user and organization. This helper can read that context
17
+ * automatically inside agent-native actions; otherwise pass it explicitly.
19
18
  */
20
19
  import { resolveCredential } from "@agent-native/core/credentials";
20
+ import {
21
+ getRequestOrgId,
22
+ getRequestUserEmail,
23
+ } from "@agent-native/core/server";
21
24
 
22
25
  /**
23
- * Optional context for scoping a credential lookup to a specific user or
24
- * org. Forward-compatible with the upcoming 2-arg @agent-native/core
25
- * signature; ignored by the current 1-arg published one.
26
+ * Optional context for scoping a credential lookup to a specific user or org.
26
27
  */
27
28
  export interface CompanyCredentialContext {
28
29
  userEmail?: string;
@@ -31,7 +32,7 @@ export interface CompanyCredentialContext {
31
32
 
32
33
  type ResolveCredentialFn = (
33
34
  key: string,
34
- ctx?: CompanyCredentialContext,
35
+ ctx: CompanyCredentialContext,
35
36
  ) => Promise<string | undefined>;
36
37
 
37
38
  /**
@@ -39,10 +40,10 @@ type ResolveCredentialFn = (
39
40
  * directly — it keeps your keys organized under a workspace namespace and
40
41
  * makes "where does this secret come from" greppable.
41
42
  *
42
- * Example:
43
+ * Inside an agent-native action:
43
44
  * const slackToken = await resolveCompanyCredential("SLACK_BOT_TOKEN");
44
45
  *
45
- * With per-user scoping (after upgrading @agent-native/core):
46
+ * Outside request context:
46
47
  * const slackToken = await resolveCompanyCredential("SLACK_BOT_TOKEN", {
47
48
  * userEmail: session.email,
48
49
  * orgId: session.orgId ?? null,
@@ -52,5 +53,15 @@ export async function resolveCompanyCredential(
52
53
  key: string,
53
54
  ctx?: CompanyCredentialContext,
54
55
  ): Promise<string | undefined> {
55
- return await (resolveCredential as ResolveCredentialFn)(key, ctx);
56
+ const effectiveCtx: CompanyCredentialContext = ctx?.userEmail
57
+ ? ctx
58
+ : {
59
+ userEmail: getRequestUserEmail() ?? undefined,
60
+ orgId: getRequestOrgId(),
61
+ };
62
+ if (!effectiveCtx.userEmail) return undefined;
63
+ return await (resolveCredential as ResolveCredentialFn)(key, {
64
+ userEmail: effectiveCtx.userEmail,
65
+ orgId: effectiveCtx.orgId ?? null,
66
+ });
56
67
  }
@@ -22,6 +22,13 @@ OPENAI_API_KEY=
22
22
  BUILDER_PRIVATE_KEY=
23
23
  BUILDER_PUBLIC_KEY=
24
24
 
25
+ # Builder app creation / branching. In local dev these can live in .env.
26
+ # In production, configure deploy env vars instead; production app creation
27
+ # never writes credentials or project IDs to the filesystem.
28
+ ENABLE_BUILDER=
29
+ DISPATCH_BUILDER_PROJECT_ID=
30
+ BUILDER_BRANCH_PROJECT_ID=
31
+
25
32
  # A2A shared secret — required for cross-app JWT verification. Every app
26
33
  # in the workspace should use the same value. Generate with:
27
34
  # openssl rand -hex 32
@@ -40,14 +40,17 @@ the workspace core package (`@{{APP_NAME}}/core-module`).
40
40
  ```bash
41
41
  pnpm install
42
42
  cp .env.example .env # fill in DATABASE_URL, BETTER_AUTH_SECRET, ANTHROPIC_API_KEY
43
- pnpm dev # starts the example app
43
+ pnpm dev # starts the workspace gateway and opens Dispatch
44
44
  ```
45
45
 
46
+ The dev gateway serves Dispatch at `/dispatch` and every app at its own path
47
+ such as `/starter`. It watches `apps/`, so newly-created apps are detected and
48
+ started without restarting `pnpm dev`.
49
+
46
50
  ## Adding a new app
47
51
 
48
52
  ```bash
49
- cd apps
50
- pnpm exec agent-native create crm
53
+ pnpm exec agent-native create crm --template=starter
51
54
  ```
52
55
 
53
56
  The CLI detects the workspace root and scaffolds a minimal app that already
@@ -19,5 +19,8 @@ packages/*/.env
19
19
  .pnpm-store/
20
20
  pnpm-debug.log*
21
21
 
22
+ # Local workspace data
23
+ data/
24
+
22
25
  # Personal agent memory — per-developer, not shared
23
26
  learnings.md
@@ -3,7 +3,7 @@
3
3
  "private": true,
4
4
  "version": "0.0.0",
5
5
  "scripts": {
6
- "dev": "pnpm --filter example dev",
6
+ "dev": "tsx scripts/workspace-dev.ts",
7
7
  "build": "pnpm -r build",
8
8
  "typecheck": "pnpm -r typecheck"
9
9
  },
@@ -11,7 +11,9 @@
11
11
  "workspaceCore": "@{{APP_NAME}}/core-module"
12
12
  },
13
13
  "devDependencies": {
14
+ "@types/node": "^24.2.1",
14
15
  "prettier": "^3.6.2",
16
+ "tsx": "catalog:",
15
17
  "typescript": "^6.0.3"
16
18
  },
17
19
  "packageManager": "pnpm@10.14.0"
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env tsx
2
+ import { spawn, type ChildProcess } from "node:child_process";
3
+ import fs from "node:fs";
4
+ import http from "node:http";
5
+ import net from "node:net";
6
+ import path from "node:path";
7
+
8
+ interface WorkspaceApp {
9
+ id: string;
10
+ name: string;
11
+ dir: string;
12
+ port: number;
13
+ process?: ChildProcess;
14
+ }
15
+
16
+ const root = process.cwd();
17
+ const appsDir = path.join(root, "apps");
18
+ const gatewayHost = process.env.WORKSPACE_HOST || "127.0.0.1";
19
+ const requestedPort = Number(
20
+ process.env.WORKSPACE_PORT || process.env.PORT || 8080,
21
+ );
22
+ const appPortStart = Number(process.env.WORKSPACE_APP_PORT_START || 8100);
23
+ let gatewayUrl = `http://${gatewayHost}:${requestedPort}`;
24
+
25
+ function readJson(file: string): any {
26
+ try {
27
+ return JSON.parse(fs.readFileSync(file, "utf8"));
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ function discoverApps(): WorkspaceApp[] {
34
+ if (!fs.existsSync(appsDir)) return [];
35
+ return fs
36
+ .readdirSync(appsDir, { withFileTypes: true })
37
+ .filter((entry) => entry.isDirectory())
38
+ .map((entry) => {
39
+ const dir = path.join(appsDir, entry.name);
40
+ const pkg = readJson(path.join(dir, "package.json"));
41
+ if (!pkg) return null;
42
+ return {
43
+ id: entry.name,
44
+ name: pkg.displayName || pkg.name || entry.name,
45
+ dir,
46
+ port: appPortStart,
47
+ } satisfies WorkspaceApp;
48
+ })
49
+ .filter((app): app is WorkspaceApp => !!app)
50
+ .sort((a, b) => {
51
+ if (a.id === "dispatch") return -1;
52
+ if (b.id === "dispatch") return 1;
53
+ return a.id.localeCompare(b.id);
54
+ })
55
+ .map((app, index) => ({ ...app, port: appPortStart + index }));
56
+ }
57
+
58
+ const apps = discoverApps();
59
+ if (apps.length === 0) {
60
+ console.error("[workspace] No apps found under ./apps");
61
+ process.exit(1);
62
+ }
63
+
64
+ const appById = new Map(apps.map((app) => [app.id, app]));
65
+ const defaultApp =
66
+ process.env.WORKSPACE_DEFAULT_APP &&
67
+ appById.has(process.env.WORKSPACE_DEFAULT_APP)
68
+ ? process.env.WORKSPACE_DEFAULT_APP
69
+ : appById.has("dispatch")
70
+ ? "dispatch"
71
+ : apps[0].id;
72
+
73
+ function syncApps(): void {
74
+ const discovered = discoverApps();
75
+ for (const app of discovered) {
76
+ if (appById.has(app.id)) continue;
77
+ const usedPorts = new Set(apps.map((existing) => existing.port));
78
+ let port = appPortStart;
79
+ while (usedPorts.has(port)) port++;
80
+ const next = { ...app, port };
81
+ apps.push(next);
82
+ apps.sort((a, b) => {
83
+ if (a.id === "dispatch") return -1;
84
+ if (b.id === "dispatch") return 1;
85
+ return a.id.localeCompare(b.id);
86
+ });
87
+ appById.set(next.id, next);
88
+ console.log(`[workspace] Detected new app: /${next.id}`);
89
+ startApp(next);
90
+ }
91
+ }
92
+
93
+ let syncTimer: NodeJS.Timeout | undefined;
94
+ function scheduleSync(): void {
95
+ if (syncTimer) clearTimeout(syncTimer);
96
+ syncTimer = setTimeout(syncApps, 400);
97
+ }
98
+
99
+ function firstPathSegment(url: string | undefined): string | null {
100
+ if (!url) return null;
101
+ try {
102
+ const parsed = new URL(url, "http://workspace.local");
103
+ const [segment] = parsed.pathname.split("/").filter(Boolean);
104
+ return segment || null;
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+
110
+ function appForRequest(req: http.IncomingMessage): WorkspaceApp | null {
111
+ const direct = firstPathSegment(req.url);
112
+ if (direct && appById.has(direct)) return appById.get(direct) ?? null;
113
+ const referer = req.headers.referer;
114
+ const fromReferer =
115
+ typeof referer === "string" ? firstPathSegment(referer) : null;
116
+ return fromReferer && appById.has(fromReferer)
117
+ ? (appById.get(fromReferer) ?? null)
118
+ : null;
119
+ }
120
+
121
+ function stripAppPrefixForDevAsset(
122
+ app: WorkspaceApp,
123
+ requestUrl: string | undefined,
124
+ ): string | undefined {
125
+ if (!requestUrl) return requestUrl;
126
+ const basePath = `/${app.id}`;
127
+ try {
128
+ const parsed = new URL(requestUrl, "http://workspace.local");
129
+ if (
130
+ parsed.pathname !== basePath &&
131
+ !parsed.pathname.startsWith(`${basePath}/`)
132
+ ) {
133
+ return requestUrl;
134
+ }
135
+
136
+ const innerPath = parsed.pathname.slice(basePath.length) || "/";
137
+ const isDevAsset =
138
+ innerPath === "/@vite/client" ||
139
+ innerPath.startsWith("/@vite/") ||
140
+ innerPath.startsWith("/@id/") ||
141
+ innerPath.startsWith("/@fs/") ||
142
+ innerPath.startsWith("/@react-router/") ||
143
+ innerPath.startsWith("/.vite/") ||
144
+ innerPath.startsWith("/app/") ||
145
+ innerPath.startsWith("/node_modules/") ||
146
+ (/\.[a-z0-9]+$/i.test(innerPath) && !innerPath.endsWith(".data"));
147
+ if (!isDevAsset) return requestUrl;
148
+
149
+ parsed.pathname = innerPath;
150
+ return `${parsed.pathname}${parsed.search}`;
151
+ } catch {
152
+ return requestUrl;
153
+ }
154
+ }
155
+
156
+ function startApp(app: WorkspaceApp): void {
157
+ const basePath = `/${app.id}`;
158
+ const child = spawn(
159
+ "pnpm",
160
+ [
161
+ "--dir",
162
+ app.dir,
163
+ "exec",
164
+ "vite",
165
+ "--host",
166
+ "127.0.0.1",
167
+ "--port",
168
+ String(app.port),
169
+ "--strictPort",
170
+ ],
171
+ {
172
+ cwd: root,
173
+ stdio: ["ignore", "pipe", "pipe"],
174
+ env: {
175
+ ...process.env,
176
+ APP_NAME: app.id,
177
+ APP_BASE_PATH: basePath,
178
+ VITE_APP_BASE_PATH: basePath,
179
+ AGENT_NATIVE_VITE_BASE_PATH: "/",
180
+ PORT: String(app.port),
181
+ WORKSPACE_GATEWAY_URL: gatewayUrl,
182
+ },
183
+ },
184
+ );
185
+ app.process = child;
186
+
187
+ const prefix = `[${app.id}]`;
188
+ child.stdout?.on("data", (chunk) => {
189
+ process.stdout.write(
190
+ String(chunk)
191
+ .split(/\r?\n/)
192
+ .filter(Boolean)
193
+ .map((line) => `${prefix} ${line}`)
194
+ .join("\n") + "\n",
195
+ );
196
+ });
197
+ child.stderr?.on("data", (chunk) => {
198
+ process.stderr.write(
199
+ String(chunk)
200
+ .split(/\r?\n/)
201
+ .filter(Boolean)
202
+ .map((line) => `${prefix} ${line}`)
203
+ .join("\n") + "\n",
204
+ );
205
+ });
206
+ child.on("exit", (code) => {
207
+ if (code === 0 || shuttingDown) return;
208
+ console.error(`${prefix} exited with code ${code}`);
209
+ });
210
+ }
211
+
212
+ function renderIndex(): string {
213
+ return `<!doctype html>
214
+ <html>
215
+ <head>
216
+ <meta charset="utf-8" />
217
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
218
+ <title>Agent-Native Workspace</title>
219
+ <style>
220
+ body { font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; margin: 0; padding: 32px; background: #fafafa; color: #171717; }
221
+ main { max-width: 760px; margin: 0 auto; }
222
+ a { color: inherit; text-decoration: none; }
223
+ .grid { display: grid; gap: 12px; margin-top: 20px; }
224
+ .card { display: flex; justify-content: space-between; border: 1px solid #d4d4d4; border-radius: 8px; padding: 14px 16px; background: white; }
225
+ .muted { color: #737373; }
226
+ </style>
227
+ </head>
228
+ <body>
229
+ <main>
230
+ <h1>Agent-Native Workspace</h1>
231
+ <p class="muted">Open an app below. Dispatch is the workspace control plane.</p>
232
+ <div class="grid">
233
+ ${apps
234
+ .map(
235
+ (app) =>
236
+ `<a class="card" href="/${app.id}"><strong>${app.name}</strong><span class="muted">/${app.id}</span></a>`,
237
+ )
238
+ .join("")}
239
+ </div>
240
+ </main>
241
+ </body>
242
+ </html>`;
243
+ }
244
+
245
+ function proxyHttp(
246
+ app: WorkspaceApp,
247
+ req: http.IncomingMessage,
248
+ res: http.ServerResponse,
249
+ ): void {
250
+ const headers = { ...req.headers, host: `127.0.0.1:${app.port}` };
251
+ const proxyReq = http.request(
252
+ {
253
+ hostname: "127.0.0.1",
254
+ port: app.port,
255
+ method: req.method,
256
+ path: stripAppPrefixForDevAsset(app, req.url),
257
+ headers,
258
+ },
259
+ (proxyRes) => {
260
+ res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
261
+ proxyRes.pipe(res);
262
+ },
263
+ );
264
+
265
+ proxyReq.on("error", (err) => {
266
+ res.writeHead(502, { "content-type": "text/plain" });
267
+ res.end(`App "${app.id}" is not ready yet: ${err.message}`);
268
+ });
269
+
270
+ req.pipe(proxyReq);
271
+ }
272
+
273
+ function proxyUpgrade(
274
+ app: WorkspaceApp,
275
+ req: http.IncomingMessage,
276
+ socket: net.Socket,
277
+ head: Buffer,
278
+ ): void {
279
+ const target = net.connect(app.port, "127.0.0.1", () => {
280
+ const headers = Object.entries({
281
+ ...req.headers,
282
+ host: `127.0.0.1:${app.port}`,
283
+ })
284
+ .flatMap(([key, value]) =>
285
+ Array.isArray(value)
286
+ ? value.map((item) => `${key}: ${item}`)
287
+ : [`${key}: ${value ?? ""}`],
288
+ )
289
+ .join("\r\n");
290
+ target.write(
291
+ `${req.method} ${stripAppPrefixForDevAsset(app, req.url)} HTTP/${req.httpVersion}\r\n${headers}\r\n\r\n`,
292
+ );
293
+ if (head.length) target.write(head);
294
+ socket.pipe(target).pipe(socket);
295
+ });
296
+
297
+ target.on("error", () => socket.destroy());
298
+ }
299
+
300
+ let shuttingDown = false;
301
+ let workspaceStarted = false;
302
+
303
+ function startWorkspaceProcesses(): void {
304
+ if (workspaceStarted) return;
305
+ workspaceStarted = true;
306
+ for (const app of apps) startApp(app);
307
+ try {
308
+ fs.watch(appsDir, { recursive: true }, scheduleSync);
309
+ } catch {
310
+ // Some platforms do not support recursive directory watches.
311
+ }
312
+ setInterval(syncApps, 2_000).unref();
313
+ }
314
+
315
+ function openBrowser(url: string): void {
316
+ if (process.env.WORKSPACE_NO_OPEN === "1") return;
317
+ const command =
318
+ process.platform === "darwin"
319
+ ? "open"
320
+ : process.platform === "win32"
321
+ ? "cmd"
322
+ : "xdg-open";
323
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
324
+ const child = spawn(command, args, {
325
+ stdio: "ignore",
326
+ detached: true,
327
+ });
328
+ child.unref();
329
+ }
330
+
331
+ const server = http.createServer((req, res) => {
332
+ if (req.url === "/" || req.url === "/index.html") {
333
+ res.writeHead(302, { location: `/${defaultApp}` });
334
+ res.end();
335
+ return;
336
+ }
337
+
338
+ if (req.url === "/_workspace/apps") {
339
+ res.writeHead(200, { "content-type": "application/json" });
340
+ res.end(
341
+ JSON.stringify(
342
+ apps.map((app) => ({
343
+ id: app.id,
344
+ name: app.name,
345
+ path: `/${app.id}`,
346
+ port: app.port,
347
+ })),
348
+ ),
349
+ );
350
+ return;
351
+ }
352
+
353
+ const app = appForRequest(req);
354
+ if (!app) {
355
+ res.writeHead(404, { "content-type": "text/html" });
356
+ res.end(renderIndex());
357
+ return;
358
+ }
359
+ proxyHttp(app, req, res);
360
+ });
361
+
362
+ server.on("upgrade", (req, socket, head) => {
363
+ const app = appForRequest(req);
364
+ if (!app) {
365
+ socket.destroy();
366
+ return;
367
+ }
368
+ proxyUpgrade(app, req, socket, head);
369
+ });
370
+
371
+ function listen(port: number, attempts = 20): void {
372
+ server.once("error", (err: NodeJS.ErrnoException) => {
373
+ if (err.code === "EADDRINUSE" && attempts > 0) {
374
+ listen(port + 1, attempts - 1);
375
+ return;
376
+ }
377
+ console.error(`[workspace] Could not start gateway: ${err.message}`);
378
+ process.exit(1);
379
+ });
380
+ server.listen(port, gatewayHost, () => {
381
+ const address = server.address();
382
+ const actualPort =
383
+ typeof address === "object" && address ? address.port : port;
384
+ gatewayUrl = `http://${gatewayHost}:${actualPort}`;
385
+ console.log(`[workspace] Gateway: http://${gatewayHost}:${actualPort}`);
386
+ console.log(
387
+ `[workspace] Default: http://${gatewayHost}:${actualPort}/${defaultApp}`,
388
+ );
389
+ for (const app of apps) {
390
+ console.log(`[workspace] ${app.id}: /${app.id} -> 127.0.0.1:${app.port}`);
391
+ }
392
+ startWorkspaceProcesses();
393
+ openBrowser(`http://${gatewayHost}:${actualPort}/${defaultApp}`);
394
+ });
395
+ }
396
+
397
+ function shutdown(): void {
398
+ if (shuttingDown) return;
399
+ shuttingDown = true;
400
+ server.close();
401
+ for (const app of apps) {
402
+ app.process?.kill("SIGTERM");
403
+ }
404
+ setTimeout(() => process.exit(0), 300).unref();
405
+ }
406
+
407
+ process.on("SIGINT", shutdown);
408
+ process.on("SIGTERM", shutdown);
409
+
410
+ listen(requestedPort);
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAYhE,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CA+QrE"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAYhE,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAiRrE"}
@@ -233,6 +233,7 @@ export function createToolActionEntries() {
233
233
  return "Error: slotId is required.";
234
234
  return { tools: await listToolsForSlot(slotId) };
235
235
  },
236
+ readOnly: true,
236
237
  },
237
238
  "list-tool-slots": {
238
239
  tool: {
@@ -251,6 +252,7 @@ export function createToolActionEntries() {
251
252
  return "Error: toolId is required.";
252
253
  return { slots: await listSlotsForTool(toolId) };
253
254
  },
255
+ readOnly: true,
254
256
  },
255
257
  };
256
258
  }
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { createTool, getTool, updateTool, updateToolContent } from \"./store.js\";\nimport {\n addToolSlotTarget,\n installToolSlot,\n uninstallToolSlot,\n listToolsForSlot,\n listSlotsForTool,\n} from \"./slots/store.js\";\n\ntype ToolPatch = { find: string; replace: string };\n\nexport function createToolActionEntries(): Record<string, ActionEntry> {\n return {\n \"create-tool\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app tool. Use this when the user asks to create, build, or make a tool/widget/dashboard/calculator. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), toolFetch(), and toolData.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the tool. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the tool does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe body has no padding, so add p-4 or p-6 to the outermost element. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const tool = await createTool({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n return {\n ok: true,\n tool,\n next: `Navigate to /tools/${tool.id} or use the navigate action with --view=tools --toolId=${tool.id}.`,\n };\n },\n },\n\n \"update-tool\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app tool. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Tool id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateToolContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateTool(id, meta as any);\n }\n\n if (!result) result = await getTool(id);\n if (!result) return `Error: tool not found: ${id}`;\n return { ok: true, tool: result };\n },\n },\n\n \"add-tool-slot-target\": {\n tool: {\n description:\n 'Declare that a tool can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers a tool as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the tool.',\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addToolSlotTarget(\n toolId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install a tool as a widget in an extension-point slot for the current user. The tool must already declare the slot via add-tool-slot-target. Per-user installation — only affects the calling user's view. Use after creating a tool that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id to install.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installToolSlot(toolId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove a tool from an extension-point slot for the current user. Does not delete the tool itself.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallToolSlot(toolId, slotId);\n return { ok: true };\n },\n },\n\n \"list-tools-for-slot\": {\n tool: {\n description:\n \"List tools the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { tools: await listToolsForSlot(slotId) };\n },\n },\n\n \"list-tool-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific tool declares it can render in. Caller must have viewer access to the tool.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n },\n required: [\"toolId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n return { slots: await listSlotsForTool(toolId) };\n },\n },\n };\n}\n\nfunction parsePatches(value: unknown): ToolPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { createTool, getTool, updateTool, updateToolContent } from \"./store.js\";\nimport {\n addToolSlotTarget,\n installToolSlot,\n uninstallToolSlot,\n listToolsForSlot,\n listSlotsForTool,\n} from \"./slots/store.js\";\n\ntype ToolPatch = { find: string; replace: string };\n\nexport function createToolActionEntries(): Record<string, ActionEntry> {\n return {\n \"create-tool\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app tool. Use this when the user asks to create, build, or make a tool/widget/dashboard/calculator. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), toolFetch(), and toolData.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the tool. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the tool does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe body has no padding, so add p-4 or p-6 to the outermost element. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const tool = await createTool({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n return {\n ok: true,\n tool,\n next: `Navigate to /tools/${tool.id} or use the navigate action with --view=tools --toolId=${tool.id}.`,\n };\n },\n },\n\n \"update-tool\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app tool. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Tool id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateToolContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateTool(id, meta as any);\n }\n\n if (!result) result = await getTool(id);\n if (!result) return `Error: tool not found: ${id}`;\n return { ok: true, tool: result };\n },\n },\n\n \"add-tool-slot-target\": {\n tool: {\n description:\n 'Declare that a tool can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers a tool as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the tool.',\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addToolSlotTarget(\n toolId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install a tool as a widget in an extension-point slot for the current user. The tool must already declare the slot via add-tool-slot-target. Per-user installation — only affects the calling user's view. Use after creating a tool that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id to install.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installToolSlot(toolId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove a tool from an extension-point slot for the current user. Does not delete the tool itself.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallToolSlot(toolId, slotId);\n return { ok: true };\n },\n },\n\n \"list-tools-for-slot\": {\n tool: {\n description:\n \"List tools the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { tools: await listToolsForSlot(slotId) };\n },\n readOnly: true,\n },\n\n \"list-tool-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific tool declares it can render in. Caller must have viewer access to the tool.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n },\n required: [\"toolId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n return { slots: await listSlotsForTool(toolId) };\n },\n readOnly: true,\n },\n };\n}\n\nfunction parsePatches(value: unknown): ToolPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8YACiX,CAAC;AAE9Y,eAAO,MAAM,oBAAoB,QAGhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CAC/C;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM,CA8eR"}
1
+ {"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8YACiX,CAAC;AAE9Y,eAAO,MAAM,oBAAoB,QAGhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CAC/C;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM,CA0fR"}