@agent-native/core 0.48.4 → 0.49.1

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 (126) hide show
  1. package/dist/agent/context-xray/actions/context-evict.d.ts +1 -1
  2. package/dist/agent/context-xray/actions/context-pin.d.ts +1 -1
  3. package/dist/agent/context-xray/actions/context-report.d.ts +4 -4
  4. package/dist/agent/context-xray/actions/context-restore.d.ts +1 -1
  5. package/dist/application-state/handlers.d.ts +2 -2
  6. package/dist/application-state/handlers.d.ts.map +1 -1
  7. package/dist/cli/app-skill.d.ts +157 -0
  8. package/dist/cli/app-skill.d.ts.map +1 -0
  9. package/dist/cli/app-skill.js +17 -7
  10. package/dist/cli/app-skill.js.map +1 -1
  11. package/dist/cli/audit-agent-web.d.ts +2 -0
  12. package/dist/cli/audit-agent-web.d.ts.map +1 -0
  13. package/dist/cli/code-agent-connector.d.ts +17 -0
  14. package/dist/cli/code-agent-connector.d.ts.map +1 -0
  15. package/dist/cli/code.d.ts +66 -0
  16. package/dist/cli/code.d.ts.map +1 -0
  17. package/dist/cli/connect.d.ts +168 -0
  18. package/dist/cli/connect.d.ts.map +1 -0
  19. package/dist/cli/connect.js +118 -30
  20. package/dist/cli/connect.js.map +1 -1
  21. package/dist/cli/context-xray-local.d.ts +16 -0
  22. package/dist/cli/context-xray-local.d.ts.map +1 -0
  23. package/dist/cli/create-workspace.d.ts +8 -0
  24. package/dist/cli/create-workspace.d.ts.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/info.d.ts +2 -0
  28. package/dist/cli/info.d.ts.map +1 -0
  29. package/dist/cli/mcp-config-writers.d.ts +108 -0
  30. package/dist/cli/mcp-config-writers.d.ts.map +1 -0
  31. package/dist/cli/mcp-config-writers.js +143 -0
  32. package/dist/cli/mcp-config-writers.js.map +1 -1
  33. package/dist/cli/mcp.d.ts +16 -0
  34. package/dist/cli/mcp.d.ts.map +1 -0
  35. package/dist/cli/mcp.js +10 -10
  36. package/dist/cli/mcp.js.map +1 -1
  37. package/dist/cli/migrate.d.ts +38 -0
  38. package/dist/cli/migrate.d.ts.map +1 -0
  39. package/dist/cli/plan-local.d.ts +43 -0
  40. package/dist/cli/plan-local.d.ts.map +1 -0
  41. package/dist/cli/plan-publish-store.d.ts +62 -0
  42. package/dist/cli/plan-publish-store.d.ts.map +1 -0
  43. package/dist/cli/pr-visual-recap-workflow.d.ts +11 -0
  44. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -0
  45. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  46. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  47. package/dist/cli/recap.d.ts +453 -0
  48. package/dist/cli/recap.d.ts.map +1 -0
  49. package/dist/cli/recap.js +228 -95
  50. package/dist/cli/recap.js.map +1 -1
  51. package/dist/cli/skills.d.ts +193 -0
  52. package/dist/cli/skills.d.ts.map +1 -0
  53. package/dist/cli/skills.js +369 -171
  54. package/dist/cli/skills.js.map +1 -1
  55. package/dist/cli/telemetry.d.ts +13 -0
  56. package/dist/cli/telemetry.d.ts.map +1 -0
  57. package/dist/cli/telemetry.js +115 -0
  58. package/dist/cli/telemetry.js.map +1 -0
  59. package/dist/cli/workspace-dev.d.ts +96 -0
  60. package/dist/cli/workspace-dev.d.ts.map +1 -0
  61. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  62. package/dist/client/blocks/library/AnnotatedCodeBlock.js +15 -7
  63. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  64. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  65. package/dist/client/blocks/library/DiffBlock.js +17 -10
  66. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  67. package/dist/client/blocks/library/annotation-rail.d.ts +5 -0
  68. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  69. package/dist/client/blocks/library/annotation-rail.js +6 -0
  70. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  71. package/dist/client/blocks/types.d.ts +5 -0
  72. package/dist/client/blocks/types.d.ts.map +1 -1
  73. package/dist/client/blocks/types.js.map +1 -1
  74. package/dist/extensions/schema.d.ts +54 -54
  75. package/dist/extensions/slots/schema.d.ts +13 -13
  76. package/dist/file-upload/actions/upload-image.d.ts +4 -4
  77. package/dist/mcp/actions/create-org-service-token.d.ts +1 -1
  78. package/dist/mcp/actions/list-org-service-tokens.d.ts +7 -7
  79. package/dist/mcp/build-server.d.ts +12 -12
  80. package/dist/mcp/build-server.d.ts.map +1 -1
  81. package/dist/mcp/build-server.js.map +1 -1
  82. package/dist/mcp/connect-route.js +1 -1
  83. package/dist/mcp/connect-route.js.map +1 -1
  84. package/dist/mcp/oauth-route.d.ts +10 -0
  85. package/dist/mcp/oauth-route.d.ts.map +1 -1
  86. package/dist/mcp/oauth-route.js +34 -3
  87. package/dist/mcp/oauth-route.js.map +1 -1
  88. package/dist/mcp/oauth-store.d.ts +15 -1
  89. package/dist/mcp/oauth-store.d.ts.map +1 -1
  90. package/dist/mcp/oauth-store.js +60 -4
  91. package/dist/mcp/oauth-store.js.map +1 -1
  92. package/dist/mcp/oauth-token.d.ts +3 -1
  93. package/dist/mcp/oauth-token.d.ts.map +1 -1
  94. package/dist/mcp/oauth-token.js +78 -6
  95. package/dist/mcp/oauth-token.js.map +1 -1
  96. package/dist/mcp/server.d.ts.map +1 -1
  97. package/dist/mcp/server.js +8 -6
  98. package/dist/mcp/server.js.map +1 -1
  99. package/dist/observability/routes.d.ts +11 -11
  100. package/dist/org/handlers.d.ts +7 -11
  101. package/dist/org/handlers.d.ts.map +1 -1
  102. package/dist/secrets/schema.d.ts +7 -7
  103. package/dist/server/csrf.d.ts +1 -1
  104. package/dist/server/csrf.d.ts.map +1 -1
  105. package/dist/server/poll-events.d.ts +1 -1
  106. package/dist/server/security-headers.d.ts +1 -1
  107. package/dist/server/security-headers.d.ts.map +1 -1
  108. package/dist/sharing/actions/list-resource-shares.d.ts +3 -3
  109. package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
  110. package/dist/sharing/actions/share-resource.d.ts +4 -4
  111. package/dist/sharing/actions/unshare-resource.d.ts +1 -1
  112. package/dist/sharing/schema.d.ts +12 -12
  113. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
  114. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
  115. package/dist/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
  116. package/dist/workspace-files/schema.d.ts +8 -8
  117. package/docs/content/deployment.md +32 -8
  118. package/docs/content/drop-in-agent.md +24 -17
  119. package/docs/content/external-agents.md +14 -0
  120. package/docs/content/plan-plugin.md +22 -7
  121. package/docs/content/template-content.md +36 -0
  122. package/docs/content/template-plan.md +22 -0
  123. package/package.json +5 -1
  124. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
  125. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
  126. package/src/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
@@ -31,9 +31,9 @@
31
31
  * - `visibility`— coarse default: `'private' | 'org' | 'public'`. Default `'private'`.
32
32
  */
33
33
  export declare function ownableColumns(): {
34
- ownerEmail: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"owner_email", [string, ...string[]], number | undefined>>>;
35
- orgId: import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"org_id", [string, ...string[]], number | undefined>;
36
- visibility: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"visibility", ["private", "org", "public"], number | undefined>>>;
34
+ ownerEmail: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"owner_email", [string, ...string[]], number>>>;
35
+ orgId: import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"org_id", [string, ...string[]], number>;
36
+ visibility: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"visibility", ["private", "org", "public"], number>>>;
37
37
  };
38
38
  /**
39
39
  * Create a companion shares table for an ownable resource. Call this right
@@ -74,7 +74,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
74
74
  identity: undefined;
75
75
  generated: undefined;
76
76
  }, {}, {
77
- length: number | undefined;
77
+ length: number;
78
78
  }>;
79
79
  resourceId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
80
80
  name: "resource_id";
@@ -93,14 +93,14 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
93
93
  identity: undefined;
94
94
  generated: undefined;
95
95
  }, {}, {
96
- length: number | undefined;
96
+ length: number;
97
97
  }>;
98
98
  principalType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
99
99
  name: "principal_type";
100
100
  tableName: string;
101
101
  dataType: "string";
102
102
  columnType: "SQLiteText";
103
- data: "user" | "org";
103
+ data: "org" | "user";
104
104
  driverParam: string;
105
105
  notNull: true;
106
106
  hasDefault: false;
@@ -112,7 +112,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
112
112
  identity: undefined;
113
113
  generated: undefined;
114
114
  }, {}, {
115
- length: number | undefined;
115
+ length: number;
116
116
  }>;
117
117
  principalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
118
118
  name: "principal_id";
@@ -131,14 +131,14 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
131
131
  identity: undefined;
132
132
  generated: undefined;
133
133
  }, {}, {
134
- length: number | undefined;
134
+ length: number;
135
135
  }>;
136
136
  role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
137
137
  name: "role";
138
138
  tableName: string;
139
139
  dataType: "string";
140
140
  columnType: "SQLiteText";
141
- data: "editor" | "admin" | "viewer";
141
+ data: "admin" | "viewer" | "editor";
142
142
  driverParam: string;
143
143
  notNull: true;
144
144
  hasDefault: true;
@@ -150,7 +150,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
150
150
  identity: undefined;
151
151
  generated: undefined;
152
152
  }, {}, {
153
- length: number | undefined;
153
+ length: number;
154
154
  }>;
155
155
  createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
156
156
  name: "created_by";
@@ -169,7 +169,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
169
169
  identity: undefined;
170
170
  generated: undefined;
171
171
  }, {}, {
172
- length: number | undefined;
172
+ length: number;
173
173
  }>;
174
174
  createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
175
175
  name: "created_at";
@@ -188,7 +188,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
188
188
  identity: undefined;
189
189
  generated: undefined;
190
190
  }, {}, {
191
- length: number | undefined;
191
+ length: number;
192
192
  }>;
193
193
  };
194
194
  dialect: "sqlite";
@@ -43,10 +43,10 @@ client, and complete authorization-code + PKCE at
43
43
  `/_agent-native/mcp/oauth/authorize` / `/_agent-native/mcp/oauth/token`.
44
44
  Access tokens are audience-bound to the exact MCP URL and carry user/org
45
45
  identity plus `mcp:read`, `mcp:write`, and/or `mcp:apps`; refresh tokens are
46
- stored hashed and rotate. Keep `ACCESS_TOKEN` and `agent-native connect` for
46
+ stored hashed and rotate. Keep `ACCESS_TOKEN` and `pnpm exec agent-native connect` for
47
47
  local stdio proxying and fallback clients. The CLI
48
48
  uses the OAuth-native URL-only entry for Claude Code/Claude Code CLI by
49
- default; use the Connect page or `agent-native connect --token <token>` when a
49
+ default; use the Connect page or `npx @agent-native/core@latest connect --token <token>` when a
50
50
  client needs explicit bearer headers.
51
51
 
52
52
  ## Local → Real Account Migration
@@ -106,7 +106,7 @@ no-CLI equivalent is `https://<app>/_agent-native/mcp/connect`, which shows
106
106
  the copyable MCP URL, Claude / ChatGPT / Cursor / Claude Code / Codex / Other
107
107
  steps, and static-token fallback for clients that need it.
108
108
 
109
- Re-running `agent-native connect <url> --client claude-code` over an older
109
+ Re-running `npx @agent-native/core@latest connect <url> --client claude-code` over an older
110
110
  Claude bearer-token entry is the migration path: the CLI replaces
111
111
  `Authorization` headers with URL-only OAuth config and tells the user to
112
112
  authenticate from `/mcp`.
@@ -325,10 +325,10 @@ agent sees what the user actually has on screen.
325
325
  ### 5. Advanced: local development & manual setup
326
326
 
327
327
  The hosted `connect` flow above is the recommended path. For local dev, run
328
- the app (`pnpm dev` / `agent-native dev`) then point a local agent at it:
328
+ the app (`pnpm dev` / `pnpm exec agent-native dev`) then point a local agent at it:
329
329
 
330
330
  ```bash
331
- agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
331
+ pnpm exec agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
332
332
  [--app <id>] [--scope user|project]
333
333
  ```
334
334
 
@@ -336,7 +336,7 @@ It provisions a token (random `ACCESS_TOKEN` into the workspace `.env` for
336
336
  local dev, or a `signA2AToken` JWT for a detected hosted origin) and writes an
337
337
  idempotent stdio server entry — `.mcp.json` / `~/.claude.json` for Claude Code,
338
338
  the `[mcp_servers.*]` block in `~/.codex/config.toml` for Codex, the
339
- Claude-Code JSON shape for Cowork. The entry runs `agent-native mcp serve
339
+ Claude-Code JSON shape for Cowork. The entry runs `pnpm exec agent-native mcp serve
340
340
  --app <id>`, by default a **thin stdio proxy** to the running local app's
341
341
  `/_agent-native/mcp` (live registry + HMR + correct deep links stay the single
342
342
  source of truth; `--standalone` builds the registry in-process). Companion
@@ -351,7 +351,7 @@ deliberately exposes only the generic builtins plus actions with
351
351
  and mutating actions are filtered out (`filterPublicAgentActions`). The full
352
352
  surface appears when authenticated as a real caller: a deployed /
353
353
  `AGENT_MODE=production` app, or a local app reached through `connect` /
354
- `agent-native mcp install` (which provisions an identity-bearing token). A
354
+ `pnpm exec agent-native mcp install` (which provisions an identity-bearing token). A
355
355
  sparse or empty `tools/list` is diagnostic, not proof of auth failure: check
356
356
  OAuth scopes, compact-catalog filtering, and the client/server auth status
357
357
  before telling the user they are unauthenticated.
@@ -395,7 +395,7 @@ before telling the user they are unauthenticated.
395
395
  - Don't hand-write product UI in `mcpApp.resource.html`; use a real React
396
396
  route/component and embed it with `embedApp()`.
397
397
  - Don't test Claude full-app embeds against raw Vite dev modules and conclude
398
- production is broken; use `agent-native start`, a preview deploy, or prod.
398
+ production is broken; use `pnpm exec agent-native start`, a preview deploy, or prod.
399
399
  - Don't scope the `navigate` write to the agent token, or pass privileged
400
400
  state through the deep link — it's a pure pointer.
401
401
  - Don't invent a new navigation mechanism; bridge to the existing
@@ -136,8 +136,8 @@ Claude/ChatGPT conversation. Hidden context stays in model context; do not put
136
136
  internal app-state file instructions into the visible prompt. `submit: false`
137
137
  stays local as a prefill/review path.
138
138
 
139
- When testing Claude through ngrok, use a production build (`agent-native build`
140
- then `agent-native start`) or a deployed preview/production URL. Claude's
139
+ When testing Claude through ngrok, use a production build (`pnpm exec agent-native build`
140
+ then `pnpm exec agent-native start`) or a deployed preview/production URL. Claude's
141
141
  transplant path works with production asset chunks; raw Vite dev modules such
142
142
  as `/app/root.tsx` can be app-auth protected and fail dynamic imports from the
143
143
  Claude resource origin.
@@ -31,7 +31,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
31
31
  identity: undefined;
32
32
  generated: undefined;
33
33
  }, {}, {
34
- length: number | undefined;
34
+ length: number;
35
35
  }>;
36
36
  scope: import("drizzle-orm/sqlite-core").SQLiteColumn<{
37
37
  name: "scope";
@@ -50,7 +50,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
50
50
  identity: undefined;
51
51
  generated: undefined;
52
52
  }, {}, {
53
- length: number | undefined;
53
+ length: number;
54
54
  }>;
55
55
  scopeId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
56
56
  name: "scope_id";
@@ -69,7 +69,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
69
69
  identity: undefined;
70
70
  generated: undefined;
71
71
  }, {}, {
72
- length: number | undefined;
72
+ length: number;
73
73
  }>;
74
74
  path: import("drizzle-orm/sqlite-core").SQLiteColumn<{
75
75
  name: "path";
@@ -88,7 +88,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
88
88
  identity: undefined;
89
89
  generated: undefined;
90
90
  }, {}, {
91
- length: number | undefined;
91
+ length: number;
92
92
  }>;
93
93
  content: import("drizzle-orm/sqlite-core").SQLiteColumn<{
94
94
  name: "content";
@@ -107,7 +107,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
107
107
  identity: undefined;
108
108
  generated: undefined;
109
109
  }, {}, {
110
- length: number | undefined;
110
+ length: number;
111
111
  }>;
112
112
  contentType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
113
113
  name: "content_type";
@@ -126,7 +126,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
126
126
  identity: undefined;
127
127
  generated: undefined;
128
128
  }, {}, {
129
- length: number | undefined;
129
+ length: number;
130
130
  }>;
131
131
  sizeBytes: import("drizzle-orm/sqlite-core").SQLiteColumn<{
132
132
  name: "size_bytes";
@@ -162,7 +162,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
162
162
  identity: undefined;
163
163
  generated: undefined;
164
164
  }, {}, {
165
- length: number | undefined;
165
+ length: number;
166
166
  }>;
167
167
  updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
168
168
  name: "updated_at";
@@ -181,7 +181,7 @@ export declare const workspaceFiles: import("drizzle-orm/sqlite-core").SQLiteTab
181
181
  identity: undefined;
182
182
  generated: undefined;
183
183
  }, {}, {
184
- length: number | undefined;
184
+ length: number;
185
185
  }>;
186
186
  };
187
187
  dialect: "sqlite";
@@ -210,13 +210,14 @@ export default defineConfig({
210
210
 
211
211
  ### Build / Runtime {#env-runtime}
212
212
 
213
- | Variable | Description |
214
- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
215
- | `PORT` | Server port (Node.js only) |
216
- | `NITRO_PRESET` | Override build preset at build time |
217
- | `APP_BASE_PATH` | Mount the app under a prefix (e.g. `/mail`). Set automatically by `npx @agent-native/core@latest deploy`; leave unset for standalone. |
218
- | `DATABASE_URL` | Persistent SQL connection string. Required in production. See [Database](/docs/database#production) for adapter and dialect details. |
219
- | `DATABASE_AUTH_TOKEN` | Auth token for providers that require a separate token, such as Turso/libSQL. |
213
+ | Variable | Description |
214
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
215
+ | `PORT` | Server port (Node.js only) |
216
+ | `NITRO_PRESET` | Override build preset at build time |
217
+ | `APP_BASE_PATH` | Mount the app under a prefix (e.g. `/mail`). Set automatically by `npx @agent-native/core@latest deploy`; leave unset for standalone. |
218
+ | `DATABASE_URL` | Persistent SQL connection string. Required in production. See [Database](/docs/database#production) for adapter and dialect details. |
219
+ | `DATABASE_AUTH_TOKEN` | Auth token for providers that require a separate token, such as Turso/libSQL. |
220
+ | `AGENT_PROD_CODE_EXECUTION` | Optional production code-execution mode: `off` (default), `sandboxed`, or `trusted`. See [Production Code Execution](#production-code-execution). |
220
221
 
221
222
  ### Required in Production {#env-required-prod}
222
223
 
@@ -289,11 +290,34 @@ openssl rand -hex 32
289
290
 
290
291
  Rotate them by replacing the env var on every instance and redeploying — sessions / OAuth state envelopes signed under the old key become invalid, so users may need to sign in again.
291
292
 
293
+ ## Production Code Execution {#production-code-execution}
294
+
295
+ By default, production agents run without code-execution tools. They can call app actions, database tools, MCP tools, browser/session tools, and other registered framework tools, but they do not get shell or filesystem access.
296
+
297
+ Node-compatible deployments can opt into production code execution through the agent chat plugin or an environment override:
298
+
299
+ ```ts
300
+ // server/plugins/agent-chat.ts
301
+ export default createAgentChatPlugin({
302
+ codeExecution: { production: "sandboxed" },
303
+ });
304
+ ```
305
+
306
+ The available modes are:
307
+
308
+ - `off` — the default. No code-execution tools are registered in production.
309
+ - `sandboxed` — registers `run-code`, an isolated Node.js JavaScript runner with a scrubbed environment, a fresh temp directory, output/time limits, and a localhost bridge to allowlisted registered tools such as `provider-api-request`, `provider-api-docs`, `provider-api-catalog`, `web-request`, and `workspace-files`.
310
+ - `trusted` — registers `run-code` plus the full coding tool registry (`bash`, `read`, `edit`, `write`). Use this only for single-tenant or operator-controlled deployments where full shell access to the host is intentional.
311
+
312
+ Set `AGENT_PROD_CODE_EXECUTION=sandboxed` or `AGENT_PROD_CODE_EXECUTION=trusted` to override the plugin option for a specific deployment without a code change. `AGENT_PROD_CODE_EXECUTION=off` forces code execution off even when the plugin option enables it.
313
+
314
+ The `run-code` sandbox is process-level isolation, not an OS container. It strips app secrets from the child process environment and uses the Node permission model when available, but outbound network is not blocked by Node itself; authenticated calls should go through the bridge helpers the tool exposes.
315
+
292
316
  ## Updating UI in Production {#updating-ui-in-production}
293
317
 
294
318
  One of agent-native's core features is that the agent can modify your app's source code — components, routes, styles, actions. During local development this works seamlessly because the agent has full filesystem access.
295
319
 
296
- In a standard production deployment, however, the agent runs in **production mode** with access to app tools (actions, database, MCP) but **not** the filesystem. This means the agent can read and write data, run actions, and interact with external services — but it can't edit your React components or add new routes on a deployed instance.
320
+ In a standard production deployment with [production code execution](#production-code-execution) left off, the agent has access to app tools (actions, database, MCP) but not the filesystem. This means the agent can read and write data, run actions, and interact with external services — but it can't edit your React components or add new routes on a deployed instance.
297
321
 
298
322
  ### Builder.io: Visual Editing in Production {#builderio}
299
323
 
@@ -15,24 +15,27 @@ You don't need to build agent-native from scratch. The agent chat, workspace tab
15
15
 
16
16
  ## The components at a glance {#components}
17
17
 
18
- | Component | What it is | Use it when |
19
- | --------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------- |
20
- | `<AgentSidebar>` | Wraps your app, adds a toggleable side panel containing the full agent | You want the agent available alongside your app on every screen |
21
- | `<AgentToggleButton>` | Opens/closes `<AgentSidebar>` (put it in your header) | Pair with `<AgentSidebar>` |
22
- | `<AgentPanel>` | The raw panel itself — chat + CLI + workspace tabs | You want full control over layout, or a dedicated agent page |
23
- | `<AgentChatSurface>` | A pre-wired panel/page chat surface | You want chat without the sidebar wrapper |
24
- | `<AssistantChat>` | Lower-level chat renderer with composer/history hooks | You need custom chrome around the standard conversation UI |
25
- | `sendToAgentChat()` | Programmatically send a message to the chat | A button that hands work to the agent instead of running inline |
26
- | `useActionMutation()` | Typesafe frontend wrapper around an action | The UI needs to run the same operation an agent tool would run |
18
+ | Component | What it is | Use it when |
19
+ | --------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
20
+ | `<AgentSidebar>` | Wraps your root app layout and adds a toggleable side panel containing the full agent | You want the agent available alongside your app on every screen |
21
+ | `<AgentToggleButton>` | Opens/closes `<AgentSidebar>` (put it in your header) | Pair with `<AgentSidebar>` |
22
+ | `<AgentPanel>` | The raw panel itself — chat + CLI + workspace tabs | You want full control over layout, or a dedicated agent page |
23
+ | `<AgentChatSurface>` | A pre-wired panel/page chat surface | You want chat without the sidebar wrapper |
24
+ | `<AssistantChat>` | Lower-level chat renderer with composer/history hooks | You need custom chrome around the standard conversation UI |
25
+ | `sendToAgentChat()` | Programmatically send a message to the chat | A button that hands work to the agent instead of running inline |
26
+ | `useActionMutation()` | Typesafe frontend wrapper around an action | The UI needs to run the same operation an agent tool would run |
27
27
 
28
28
  All of these are exported from `@agent-native/core/client`.
29
29
 
30
30
  ## The 80% case: `<AgentSidebar>` {#sidebar}
31
31
 
32
- The most common setup is a sidebar that slides in from the right on any screen. Two pieces — the wrapper and a header button:
32
+ The most common setup is a sidebar that opens from the right on any screen.
33
+ Wrap your existing root layout with `<AgentSidebar>`; whatever you pass as
34
+ children stays in the main app area. The agent chat is the side panel.
33
35
 
34
36
  ```tsx
35
37
  // app/root.tsx
38
+ import { Outlet } from "react-router";
36
39
  import { AgentSidebar, AgentToggleButton } from "@agent-native/core/client";
37
40
 
38
41
  export default function Root() {
@@ -48,20 +51,23 @@ export default function Root() {
48
51
  defaultSidebarWidth={420}
49
52
  position="right"
50
53
  >
51
- <YourApp />
54
+ <header>
55
+ <AgentToggleButton />
56
+ </header>
57
+
58
+ <main>
59
+ <Outlet />
60
+ </main>
52
61
  </AgentSidebar>
53
62
  );
54
63
  }
55
-
56
- // somewhere in your header / navbar
57
- <AgentToggleButton />;
58
64
  ```
59
65
 
60
66
  That's it. The user now has a toggleable agent on every page — with chat history, workspace tab, CLI terminal, voice input, and a fullscreen mode. State persists across reloads via `localStorage`.
61
67
 
62
68
  ### Props
63
69
 
64
- - **`children`** — your app. Rendered in the main area; the sidebar overlays from the chosen side.
70
+ - **`children`** — your app's normal layout and routes. Rendered in the main area; the agent panel mounts beside it on desktop and over it on mobile/fullscreen.
65
71
  - **`emptyStateText`** — greeting shown when the chat has no messages. Default: `"How can I help you?"`.
66
72
  - **`suggestions`** — starter prompts rendered as clickable chips when empty.
67
73
  - **`dynamicSuggestions`** — context-aware prompt chips merged with `suggestions`. Enabled by default; pass `false` to show only static suggestions, or `{ max, includeStatic, getSuggestions }` to customize.
@@ -188,8 +194,9 @@ first so client code does not learn a second, ad hoc transport.
188
194
 
189
195
  ### Build your own sidebar from pieces {#build-your-own-sidebar}
190
196
 
191
- The stock sidebar is optional. A custom sidebar can keep your own layout and
192
- still reuse the framework runtime:
197
+ The stock sidebar is optional. This example builds the agent-side UI itself.
198
+ Render it inside your own shell, drawer, split pane, or route when you want to
199
+ own the layout around the agent runtime:
193
200
 
194
201
  ```tsx
195
202
  import { AssistantChat, useChatThreads } from "@agent-native/core/client/chat";
@@ -150,6 +150,20 @@ workspace setups should prefer the single Dispatch connector.
150
150
 
151
151
  The connection is **per-user, scoped, and revocable**. In the OAuth path, the host stores the tokens after `/mcp` authentication; in the fallback path, the browser session you authorized with is the identity the agent acts as. Nothing exposes the deployment's shared secret.
152
152
 
153
+ ### Re-authenticating after a 401 {#reconnect}
154
+
155
+ Once connected, auth should persist long-term — access tokens last 30 days by default (override with `MCP_OAUTH_ACCESS_TOKEN_TTL` on the server, e.g. `7d` or `12h`) with a sliding 365-day refresh window, so random 401s should be rare. When one does happen, use the lightweight reconnect command rather than reinstalling:
156
+
157
+ ```bash
158
+ npx @agent-native/core@latest reconnect https://plan.agent-native.com
159
+ ```
160
+
161
+ `reconnect` finds any MCP config entry whose URL ends in `/_agent-native/mcp` for the given host (matching by URL regardless of connector name), then refreshes or replaces the auth material without touching your installed skills or re-running the full install flow. Pass the base app URL (e.g. `https://plan.agent-native.com`) — the `/_agent-native/mcp` suffix is inferred.
162
+
163
+ In Claude Code, the equivalent UI path is: run `/mcp` and choose **Authenticate** (or **Reconnect**) for the relevant connector.
164
+
165
+ Never reinstall the skill from scratch just to fix a 401 — `reconnect` is the right tool.
166
+
153
167
  ### Connect page fallback {#connect-page-fallback}
154
168
 
155
169
  For MCP clients that cannot add a remote OAuth URL directly, open the app in your browser and use its **Connect** affordance (served at `https://<app>/_agent-native/mcp/connect`). While logged in, click **Connect / Authorize**. The page hands you either a one-click deep link that configures a detected agent, or a ready-to-paste `.mcp.json` block:
@@ -12,13 +12,22 @@ The Agent-Native **Plan** app ships as one installable bundle. A single install
12
12
  One install gives you:
13
13
 
14
14
  - **Two skills** — `/visual-plan` (the canonical entry point) and `/visual-recap`.
15
- - **The Plan MCP connector** — registered against the hosted app at `https://plan.agent-native.com` (MCP endpoint `https://plan.agent-native.com/_agent-native/mcp`, server name `plan`, with legacy alias `agent-native-plans` during migration).
15
+ - **The Plan MCP connector** — registered against the hosted app at `https://plan.agent-native.com` (MCP endpoint `https://plan.agent-native.com/_agent-native/mcp`, server name `plan`).
16
16
 
17
17
  By default, both skills publish to the hosted Plan app — they create a plan via
18
18
  the MCP connector and hand you a link or inline plan to review. They never dump
19
19
  an inline Markdown/ASCII plan into chat as the deliverable. If a Plan tool
20
- returns `needs auth`, `Unauthorized`, or `Session terminated`, authenticate the
21
- connector (see each route below) instead of falling back to inline output.
20
+ returns `needs auth`, `Unauthorized`, or `Session terminated`, re-authenticate
21
+ the connector instead of falling back to inline output. Access tokens are
22
+ long-lived (30-day default, sliding 365-day refresh), so this should be rare;
23
+ when it happens, the lightweight fix is:
24
+
25
+ ```bash
26
+ npx @agent-native/core@latest reconnect https://plan.agent-native.com
27
+ ```
28
+
29
+ `reconnect` finds and refreshes the connector by URL — no reinstall needed. In
30
+ Claude Code, the equivalent is `/mcp` → **Authenticate / Reconnect**.
22
31
 
23
32
  The exception is explicit **local-files privacy mode**. When you ask for no DB
24
33
  writes or set `AGENT_NATIVE_PLANS_MODE=local-files`, the skills must not call
@@ -33,6 +42,12 @@ This keeps plan content out of the Agent-Native Plan database. Hosted sharing,
33
42
  comments, screenshots, and plan history are unavailable until you explicitly
34
43
  publish later.
35
44
 
45
+ Agent Native Desktop has a separate local-file sync path for hosted plans: the
46
+ Desktop app can mirror a hosted plan to local MDX files and import edits back
47
+ without cloning the Plan app or running a CLI. That workflow keeps the hosted
48
+ Plan database as the source of truth; use local-files privacy mode when the goal
49
+ is no Plan DB writes.
50
+
36
51
  > The plugin (`agent-native-visual-plans`) carries app id `visual-plans`, which is why the Claude Code plugin name and Codex plugin name are both `agent-native-visual-plans`. The Plan app's display name is "Agent-Native Plan".
37
52
 
38
53
  ## Install routes {#install}
@@ -47,7 +62,7 @@ Works for any host — Claude Code, Codex, Cursor, Cline, Goose, ChatGPT custom
47
62
  npx @agent-native/core@latest skills add visual-plan
48
63
  ```
49
64
 
50
- This installs `visual-plan` plus the companion `visual-recap` skill, then registers the `plan` connector and its legacy `agent-native-plans` alias, then runs auth (OAuth prompt for hosted/account-backed sharing). Useful flags:
65
+ This installs `visual-plan` plus the companion `visual-recap` skill, then registers the `plan` connector, then runs auth (OAuth prompt for hosted/account-backed sharing). Useful flags:
51
66
 
52
67
  - `--client codex|claude-code|claude-code-cli|cowork|all` — which local agents to write the MCP config for (default `codex`).
53
68
  - `--no-connect` — register the connector without authenticating; run `npx @agent-native/core@latest connect https://plan.agent-native.com` later.
@@ -94,11 +109,11 @@ The same repo is a Codex plugin marketplace. Add it, install the plugin, then au
94
109
  codex plugin marketplace add BuilderIO/agent-native
95
110
  codex plugin add agent-native-visual-plans@agent-native-apps
96
111
  codex mcp login plan # OAuth in the browser
97
- # Existing installs may already be authenticated as:
98
- codex mcp login agent-native-plans
99
112
  ```
100
113
 
101
- After install, **start a new Codex thread** so the skills and MCP tools load into the session. The plugin ships URL-only connectors (`[mcp_servers.plan]` and legacy `[mcp_servers.agent-native-plans]` → `https://plan.agent-native.com/_agent-native/mcp`); `codex mcp login` runs the OAuth flow. The universal CLI route above also works for Codex (`npx @agent-native/core@latest skills add visual-plan --client codex`) if you prefer one command that installs and authenticates together.
114
+ After install, **start a new Codex thread** so the skills and MCP tools load into the session. The plugin ships a URL-only connector (`[mcp_servers.plan]` → `https://plan.agent-native.com/_agent-native/mcp`); `codex mcp login plan` runs the OAuth flow. The universal CLI route above also works for Codex (`npx @agent-native/core@latest skills add visual-plan --client codex`) if you prefer one command that installs and authenticates together.
115
+
116
+ > **Older installs:** if your config still has an `agent-native-plans` entry pointing at the same URL, running `npx @agent-native/core@latest reconnect https://plan.agent-native.com` (or `skills add visual-plan` for a full reinstall) consolidates it to the canonical `plan` name.
102
117
 
103
118
  ## Updates {#updates}
104
119
 
@@ -24,6 +24,9 @@ When you open the app, you'll see a sidebar tree of pages on the left, the edito
24
24
  - **Write rich text** with headings, lists, tables, code blocks, images, and links. Slash commands (`/`) insert blocks; selecting text pops up a formatting toolbar.
25
25
  - **Organize pages in a tree** — nest infinitely, drag to reorder, favorite pages you use often.
26
26
  - **Search across everything** with full-text search across titles and content.
27
+ - **Sync with local Markdown/MDX files.** Use the `/local-files` view to export
28
+ your workspace to files, edit them in your own tools, preview changes, and
29
+ import them back.
27
30
  - **Sync with Notion.** Link a local doc to a Notion page and pull or push content in either direction. Comments sync both ways too.
28
31
  - **Collaborate in real time.** Multiple people (and the agent) can edit the same doc at the same time.
29
32
  - **Share docs** with teammates or make them public — private by default, with viewer / editor / admin roles.
@@ -43,6 +46,24 @@ When you open the app, click **+ New page** in the sidebar, give it a title, and
43
46
 
44
47
  Select text and hit Cmd+I to focus the agent with that selection pre-loaded — "make this punchier" then operates on exactly what you highlighted.
45
48
 
49
+ ## Local Markdown files {#local-files}
50
+
51
+ Content can round-trip documents through local files without cloning or running
52
+ the Content app locally. Open `/local-files`, choose a folder in your browser or
53
+ Agent Native Desktop, and export the current document tree as Markdown/MDX under
54
+ `content/`.
55
+
56
+ Each exported file contains frontmatter for document metadata (`id`, `title`,
57
+ `parentId`, `position`, favorite/search/visibility flags, and `updatedAt`) plus
58
+ the document body as Markdown. You can edit those files in your normal editor,
59
+ then return to `/local-files` to preview and import changes back into Content.
60
+
61
+ This workflow is useful when you want content in source control, want to batch
62
+ edit docs with local tools, or want a no-clone path for teams that prefer files
63
+ as the review surface. The hosted app remains the source of truth for sharing,
64
+ comments, permissions, and live collaboration; the local folder is an explicit
65
+ sync surface.
66
+
46
67
  ## Why it's interesting
47
68
 
48
69
  Three things make Content a good showcase of the framework:
@@ -111,6 +132,21 @@ Documents can be linked to a Notion page and synced in either direction:
111
132
 
112
133
  Sync state is tracked in the `document_sync_links` table (last synced time, conflict flag, last error). Markdown-to-Notion block conversion lives in `shared/notion-markdown.ts`. Conflict and status UI is in `app/components/editor/NotionConflictBanner.tsx` and `NotionSyncBar.tsx`. See the `notion-integration` skill for the full flow.
113
134
 
135
+ ### Local file sync
136
+
137
+ The protected `/local-files` route uses the browser File System Access API (or
138
+ the same Chromium capability inside Agent Native Desktop) to read and write
139
+ Markdown/MDX files from a user-chosen folder. It calls:
140
+
141
+ - `export-content-source` — reads the accessible document tree and returns a
142
+ deterministic `content/` file bundle.
143
+ - `import-content-source` — validates files, creates new private documents,
144
+ updates documents where the caller has editor access, preserves version
145
+ history, and rejects invalid parent cycles.
146
+
147
+ The source format lives in `shared/content-source.ts`. Keep that file as the
148
+ single contract for filenames, frontmatter, parsing, and serialization.
149
+
114
150
  ### Comments
115
151
 
116
152
  Threaded comments on documents with quoted-text anchors, replies, and resolve state. Backed by the `document_comments` table and `app/components/editor/CommentsSidebar.tsx`. Actions: `list-comments`, `add-comment`. Notion comments can sync both ways via `sync-notion-comments`.
@@ -208,6 +208,28 @@ and commenting, and returns the hosted URL. It does
208
208
  not automatically make your coding agent's LLM local; choose a local or approved
209
209
  model if that privacy boundary matters too.
210
210
 
211
+ ## Desktop local file sync {#desktop-local-sync}
212
+
213
+ Agent Native Desktop also gives hosted Plans a native local-folder bridge. This
214
+ is different from local-files privacy mode: the hosted Plan database remains the
215
+ source of truth for sharing, comments, history, and live review, while Desktop
216
+ can mirror the current plan's source files to a folder you choose.
217
+
218
+ Open a plan in Agent Native Desktop, use the plan menu's **Local files** actions,
219
+ then:
220
+
221
+ - **Link local folder** — choose the folder for that plan's MDX source.
222
+ - **Sync to local folder** — write `plan.mdx`, optional `canvas.mdx`,
223
+ optional `prototype.mdx`, optional `.plan-state.json`, and image assets.
224
+ - **Import local edits** — read the folder and apply it through
225
+ `import-visual-plan-source` with the plan's current update timestamp.
226
+ - **Auto-sync changes** — keep exporting the hosted plan's latest source after
227
+ edits made in the app.
228
+
229
+ This path does not require cloning the Plan app or running a CLI. It is for
230
+ file-first review/editing around a hosted plan, not for keeping plan content out
231
+ of the hosted database.
232
+
211
233
  ## Useful prompts
212
234
 
213
235
  - "Use `/visual-plan` before changing the auth flow."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.48.4",
3
+ "version": "0.49.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -95,6 +95,10 @@
95
95
  "./client/transcription/BuilderTranscriptionCta": "./dist/client/transcription/BuilderTranscriptionCta.js",
96
96
  "./transcription/builder": "./dist/transcription/builder-transcription.js",
97
97
  "./adapters/cli": "./dist/adapters/cli/index.js",
98
+ "./cli/skills": {
99
+ "types": "./dist/cli/skills.d.ts",
100
+ "default": "./dist/cli/skills.js"
101
+ },
98
102
  "./router": "./dist/router/index.js",
99
103
  "./collab": "./dist/collab/index.js",
100
104
  "./a2a": "./dist/a2a/index.js",
@@ -43,10 +43,10 @@ client, and complete authorization-code + PKCE at
43
43
  `/_agent-native/mcp/oauth/authorize` / `/_agent-native/mcp/oauth/token`.
44
44
  Access tokens are audience-bound to the exact MCP URL and carry user/org
45
45
  identity plus `mcp:read`, `mcp:write`, and/or `mcp:apps`; refresh tokens are
46
- stored hashed and rotate. Keep `ACCESS_TOKEN` and `agent-native connect` for
46
+ stored hashed and rotate. Keep `ACCESS_TOKEN` and `pnpm exec agent-native connect` for
47
47
  local stdio proxying and fallback clients. The CLI
48
48
  uses the OAuth-native URL-only entry for Claude Code/Claude Code CLI by
49
- default; use the Connect page or `agent-native connect --token <token>` when a
49
+ default; use the Connect page or `npx @agent-native/core@latest connect --token <token>` when a
50
50
  client needs explicit bearer headers.
51
51
 
52
52
  ## Local → Real Account Migration
@@ -106,7 +106,7 @@ no-CLI equivalent is `https://<app>/_agent-native/mcp/connect`, which shows
106
106
  the copyable MCP URL, Claude / ChatGPT / Cursor / Claude Code / Codex / Other
107
107
  steps, and static-token fallback for clients that need it.
108
108
 
109
- Re-running `agent-native connect <url> --client claude-code` over an older
109
+ Re-running `npx @agent-native/core@latest connect <url> --client claude-code` over an older
110
110
  Claude bearer-token entry is the migration path: the CLI replaces
111
111
  `Authorization` headers with URL-only OAuth config and tells the user to
112
112
  authenticate from `/mcp`.
@@ -325,10 +325,10 @@ agent sees what the user actually has on screen.
325
325
  ### 5. Advanced: local development & manual setup
326
326
 
327
327
  The hosted `connect` flow above is the recommended path. For local dev, run
328
- the app (`pnpm dev` / `agent-native dev`) then point a local agent at it:
328
+ the app (`pnpm dev` / `pnpm exec agent-native dev`) then point a local agent at it:
329
329
 
330
330
  ```bash
331
- agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
331
+ pnpm exec agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
332
332
  [--app <id>] [--scope user|project]
333
333
  ```
334
334
 
@@ -336,7 +336,7 @@ It provisions a token (random `ACCESS_TOKEN` into the workspace `.env` for
336
336
  local dev, or a `signA2AToken` JWT for a detected hosted origin) and writes an
337
337
  idempotent stdio server entry — `.mcp.json` / `~/.claude.json` for Claude Code,
338
338
  the `[mcp_servers.*]` block in `~/.codex/config.toml` for Codex, the
339
- Claude-Code JSON shape for Cowork. The entry runs `agent-native mcp serve
339
+ Claude-Code JSON shape for Cowork. The entry runs `pnpm exec agent-native mcp serve
340
340
  --app <id>`, by default a **thin stdio proxy** to the running local app's
341
341
  `/_agent-native/mcp` (live registry + HMR + correct deep links stay the single
342
342
  source of truth; `--standalone` builds the registry in-process). Companion
@@ -351,7 +351,7 @@ deliberately exposes only the generic builtins plus actions with
351
351
  and mutating actions are filtered out (`filterPublicAgentActions`). The full
352
352
  surface appears when authenticated as a real caller: a deployed /
353
353
  `AGENT_MODE=production` app, or a local app reached through `connect` /
354
- `agent-native mcp install` (which provisions an identity-bearing token). A
354
+ `pnpm exec agent-native mcp install` (which provisions an identity-bearing token). A
355
355
  sparse or empty `tools/list` is diagnostic, not proof of auth failure: check
356
356
  OAuth scopes, compact-catalog filtering, and the client/server auth status
357
357
  before telling the user they are unauthenticated.
@@ -395,7 +395,7 @@ before telling the user they are unauthenticated.
395
395
  - Don't hand-write product UI in `mcpApp.resource.html`; use a real React
396
396
  route/component and embed it with `embedApp()`.
397
397
  - Don't test Claude full-app embeds against raw Vite dev modules and conclude
398
- production is broken; use `agent-native start`, a preview deploy, or prod.
398
+ production is broken; use `pnpm exec agent-native start`, a preview deploy, or prod.
399
399
  - Don't scope the `navigate` write to the agent token, or pass privileged
400
400
  state through the deep link — it's a pure pointer.
401
401
  - Don't invent a new navigation mechanism; bridge to the existing