@agent-native/core 0.51.15 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/README.md +42 -96
  2. package/blueprints/action/crud.md +98 -0
  3. package/blueprints/channel/discord.md +74 -0
  4. package/blueprints/provider/stripe.md +87 -0
  5. package/blueprints/sandbox/docker.md +78 -0
  6. package/dist/action.d.ts +24 -0
  7. package/dist/action.d.ts.map +1 -1
  8. package/dist/action.js +4 -0
  9. package/dist/action.js.map +1 -1
  10. package/dist/agent/observational-memory/compactor.d.ts +43 -0
  11. package/dist/agent/observational-memory/compactor.d.ts.map +1 -0
  12. package/dist/agent/observational-memory/compactor.js +50 -0
  13. package/dist/agent/observational-memory/compactor.js.map +1 -0
  14. package/dist/agent/observational-memory/config.d.ts +37 -0
  15. package/dist/agent/observational-memory/config.d.ts.map +1 -0
  16. package/dist/agent/observational-memory/config.js +48 -0
  17. package/dist/agent/observational-memory/config.js.map +1 -0
  18. package/dist/agent/observational-memory/index.d.ts +26 -0
  19. package/dist/agent/observational-memory/index.d.ts.map +1 -0
  20. package/dist/agent/observational-memory/index.js +25 -0
  21. package/dist/agent/observational-memory/index.js.map +1 -0
  22. package/dist/agent/observational-memory/internal-run.d.ts +37 -0
  23. package/dist/agent/observational-memory/internal-run.d.ts.map +1 -0
  24. package/dist/agent/observational-memory/internal-run.js +59 -0
  25. package/dist/agent/observational-memory/internal-run.js.map +1 -0
  26. package/dist/agent/observational-memory/message-text.d.ts +13 -0
  27. package/dist/agent/observational-memory/message-text.d.ts.map +1 -0
  28. package/dist/agent/observational-memory/message-text.js +46 -0
  29. package/dist/agent/observational-memory/message-text.js.map +1 -0
  30. package/dist/agent/observational-memory/migrations.d.ts +13 -0
  31. package/dist/agent/observational-memory/migrations.d.ts.map +1 -0
  32. package/dist/agent/observational-memory/migrations.js +43 -0
  33. package/dist/agent/observational-memory/migrations.js.map +1 -0
  34. package/dist/agent/observational-memory/observer.d.ts +37 -0
  35. package/dist/agent/observational-memory/observer.d.ts.map +1 -0
  36. package/dist/agent/observational-memory/observer.js +82 -0
  37. package/dist/agent/observational-memory/observer.js.map +1 -0
  38. package/dist/agent/observational-memory/plugin.d.ts +16 -0
  39. package/dist/agent/observational-memory/plugin.d.ts.map +1 -0
  40. package/dist/agent/observational-memory/plugin.js +26 -0
  41. package/dist/agent/observational-memory/plugin.js.map +1 -0
  42. package/dist/agent/observational-memory/prompts.d.ts +27 -0
  43. package/dist/agent/observational-memory/prompts.d.ts.map +1 -0
  44. package/dist/agent/observational-memory/prompts.js +42 -0
  45. package/dist/agent/observational-memory/prompts.js.map +1 -0
  46. package/dist/agent/observational-memory/read.d.ts +47 -0
  47. package/dist/agent/observational-memory/read.d.ts.map +1 -0
  48. package/dist/agent/observational-memory/read.js +99 -0
  49. package/dist/agent/observational-memory/read.js.map +1 -0
  50. package/dist/agent/observational-memory/reflector.d.ts +31 -0
  51. package/dist/agent/observational-memory/reflector.d.ts.map +1 -0
  52. package/dist/agent/observational-memory/reflector.js +76 -0
  53. package/dist/agent/observational-memory/reflector.js.map +1 -0
  54. package/dist/agent/observational-memory/schema.d.ts +267 -0
  55. package/dist/agent/observational-memory/schema.d.ts.map +1 -0
  56. package/dist/agent/observational-memory/schema.js +48 -0
  57. package/dist/agent/observational-memory/schema.js.map +1 -0
  58. package/dist/agent/observational-memory/store.d.ts +52 -0
  59. package/dist/agent/observational-memory/store.d.ts.map +1 -0
  60. package/dist/agent/observational-memory/store.js +197 -0
  61. package/dist/agent/observational-memory/store.js.map +1 -0
  62. package/dist/agent/observational-memory/types.d.ts +61 -0
  63. package/dist/agent/observational-memory/types.d.ts.map +1 -0
  64. package/dist/agent/observational-memory/types.js +9 -0
  65. package/dist/agent/observational-memory/types.js.map +1 -0
  66. package/dist/agent/production-agent.d.ts +15 -0
  67. package/dist/agent/production-agent.d.ts.map +1 -1
  68. package/dist/agent/production-agent.js +240 -1
  69. package/dist/agent/production-agent.js.map +1 -1
  70. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  71. package/dist/agent/run-loop-with-resume.js +49 -0
  72. package/dist/agent/run-loop-with-resume.js.map +1 -1
  73. package/dist/agent/run-store.d.ts +17 -0
  74. package/dist/agent/run-store.d.ts.map +1 -1
  75. package/dist/agent/run-store.js +55 -0
  76. package/dist/agent/run-store.js.map +1 -1
  77. package/dist/agent/runtime-context.d.ts +30 -0
  78. package/dist/agent/runtime-context.d.ts.map +1 -1
  79. package/dist/agent/runtime-context.js +54 -1
  80. package/dist/agent/runtime-context.js.map +1 -1
  81. package/dist/agent/tool-call-journal.d.ts +101 -0
  82. package/dist/agent/tool-call-journal.d.ts.map +1 -0
  83. package/dist/agent/tool-call-journal.js +214 -0
  84. package/dist/agent/tool-call-journal.js.map +1 -0
  85. package/dist/agent/types.d.ts +24 -0
  86. package/dist/agent/types.d.ts.map +1 -1
  87. package/dist/agent/types.js.map +1 -1
  88. package/dist/cli/add.d.ts +109 -0
  89. package/dist/cli/add.d.ts.map +1 -0
  90. package/dist/cli/add.js +352 -0
  91. package/dist/cli/add.js.map +1 -0
  92. package/dist/cli/connect.d.ts +5 -4
  93. package/dist/cli/connect.d.ts.map +1 -1
  94. package/dist/cli/connect.js +157 -48
  95. package/dist/cli/connect.js.map +1 -1
  96. package/dist/cli/eval.d.ts +17 -0
  97. package/dist/cli/eval.d.ts.map +1 -0
  98. package/dist/cli/eval.js +121 -0
  99. package/dist/cli/eval.js.map +1 -0
  100. package/dist/cli/index.js +44 -3
  101. package/dist/cli/index.js.map +1 -1
  102. package/dist/cli/mcp-config-writers.d.ts +20 -13
  103. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  104. package/dist/cli/mcp-config-writers.js +152 -13
  105. package/dist/cli/mcp-config-writers.js.map +1 -1
  106. package/dist/cli/mcp.d.ts +2 -2
  107. package/dist/cli/mcp.d.ts.map +1 -1
  108. package/dist/cli/mcp.js +50 -196
  109. package/dist/cli/mcp.js.map +1 -1
  110. package/dist/cli/plan-local.d.ts +69 -6
  111. package/dist/cli/plan-local.d.ts.map +1 -1
  112. package/dist/cli/plan-local.js +517 -23
  113. package/dist/cli/plan-local.js.map +1 -1
  114. package/dist/cli/recap.d.ts.map +1 -1
  115. package/dist/cli/recap.js +1 -1
  116. package/dist/cli/recap.js.map +1 -1
  117. package/dist/cli/skills.d.ts +13 -6
  118. package/dist/cli/skills.d.ts.map +1 -1
  119. package/dist/cli/skills.js +287 -111
  120. package/dist/cli/skills.js.map +1 -1
  121. package/dist/client/AssistantChat.d.ts.map +1 -1
  122. package/dist/client/AssistantChat.js +118 -92
  123. package/dist/client/AssistantChat.js.map +1 -1
  124. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  125. package/dist/client/agent-chat-adapter.js +16 -0
  126. package/dist/client/agent-chat-adapter.js.map +1 -1
  127. package/dist/client/agent-engine-key.d.ts +6 -4
  128. package/dist/client/agent-engine-key.d.ts.map +1 -1
  129. package/dist/client/agent-engine-key.js +9 -6
  130. package/dist/client/agent-engine-key.js.map +1 -1
  131. package/dist/client/chat/run-recovery.js +1 -1
  132. package/dist/client/chat/run-recovery.js.map +1 -1
  133. package/dist/client/chat/tool-call-display.d.ts +20 -1
  134. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  135. package/dist/client/chat/tool-call-display.js +32 -7
  136. package/dist/client/chat/tool-call-display.js.map +1 -1
  137. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  138. package/dist/client/settings/SettingsPanel.js +7 -14
  139. package/dist/client/settings/SettingsPanel.js.map +1 -1
  140. package/dist/client/sse-event-processor.d.ts +13 -0
  141. package/dist/client/sse-event-processor.d.ts.map +1 -1
  142. package/dist/client/sse-event-processor.js +21 -0
  143. package/dist/client/sse-event-processor.js.map +1 -1
  144. package/dist/coding-tools/run-code.d.ts +7 -0
  145. package/dist/coding-tools/run-code.d.ts.map +1 -1
  146. package/dist/coding-tools/run-code.js +21 -106
  147. package/dist/coding-tools/run-code.js.map +1 -1
  148. package/dist/coding-tools/sandbox/adapter.d.ts +79 -0
  149. package/dist/coding-tools/sandbox/adapter.d.ts.map +1 -0
  150. package/dist/coding-tools/sandbox/adapter.js +24 -0
  151. package/dist/coding-tools/sandbox/adapter.js.map +1 -0
  152. package/dist/coding-tools/sandbox/index.d.ts +51 -0
  153. package/dist/coding-tools/sandbox/index.d.ts.map +1 -0
  154. package/dist/coding-tools/sandbox/index.js +79 -0
  155. package/dist/coding-tools/sandbox/index.js.map +1 -0
  156. package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts +24 -0
  157. package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts.map +1 -0
  158. package/dist/coding-tools/sandbox/local-child-process-adapter.js +141 -0
  159. package/dist/coding-tools/sandbox/local-child-process-adapter.js.map +1 -0
  160. package/dist/db/client.d.ts +4 -2
  161. package/dist/db/client.d.ts.map +1 -1
  162. package/dist/db/client.js +6 -4
  163. package/dist/db/client.js.map +1 -1
  164. package/dist/deploy/route-discovery.d.ts.map +1 -1
  165. package/dist/deploy/route-discovery.js +1 -0
  166. package/dist/deploy/route-discovery.js.map +1 -1
  167. package/dist/eval/agent-runner.d.ts +63 -0
  168. package/dist/eval/agent-runner.d.ts.map +1 -0
  169. package/dist/eval/agent-runner.js +142 -0
  170. package/dist/eval/agent-runner.js.map +1 -0
  171. package/dist/eval/define-eval.d.ts +29 -0
  172. package/dist/eval/define-eval.d.ts.map +1 -0
  173. package/dist/eval/define-eval.js +43 -0
  174. package/dist/eval/define-eval.js.map +1 -0
  175. package/dist/eval/index.d.ts +18 -0
  176. package/dist/eval/index.d.ts.map +1 -0
  177. package/dist/eval/index.js +17 -0
  178. package/dist/eval/index.js.map +1 -0
  179. package/dist/eval/report.d.ts +8 -0
  180. package/dist/eval/report.d.ts.map +1 -0
  181. package/dist/eval/report.js +44 -0
  182. package/dist/eval/report.js.map +1 -0
  183. package/dist/eval/runner.d.ts +67 -0
  184. package/dist/eval/runner.d.ts.map +1 -0
  185. package/dist/eval/runner.js +256 -0
  186. package/dist/eval/runner.js.map +1 -0
  187. package/dist/eval/scorer.d.ts +83 -0
  188. package/dist/eval/scorer.d.ts.map +1 -0
  189. package/dist/eval/scorer.js +195 -0
  190. package/dist/eval/scorer.js.map +1 -0
  191. package/dist/eval/types.d.ts +162 -0
  192. package/dist/eval/types.d.ts.map +1 -0
  193. package/dist/eval/types.js +20 -0
  194. package/dist/eval/types.js.map +1 -0
  195. package/dist/observability/traces.d.ts.map +1 -1
  196. package/dist/observability/traces.js +100 -1
  197. package/dist/observability/traces.js.map +1 -1
  198. package/dist/observability/tracing.d.ts +73 -0
  199. package/dist/observability/tracing.d.ts.map +1 -0
  200. package/dist/observability/tracing.js +126 -0
  201. package/dist/observability/tracing.js.map +1 -0
  202. package/dist/onboarding/default-steps.d.ts.map +1 -1
  203. package/dist/onboarding/default-steps.js +4 -1
  204. package/dist/onboarding/default-steps.js.map +1 -1
  205. package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
  206. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  207. package/dist/scripts/agent-engines/list-agent-engines.js +10 -3
  208. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  209. package/dist/server/action-discovery.d.ts.map +1 -1
  210. package/dist/server/action-discovery.js +4 -0
  211. package/dist/server/action-discovery.js.map +1 -1
  212. package/dist/server/agent-chat-plugin.d.ts +9 -0
  213. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  214. package/dist/server/agent-chat-plugin.js +118 -110
  215. package/dist/server/agent-chat-plugin.js.map +1 -1
  216. package/dist/server/agent-engine-api-key-route.d.ts +37 -0
  217. package/dist/server/agent-engine-api-key-route.d.ts.map +1 -0
  218. package/dist/server/agent-engine-api-key-route.js +105 -0
  219. package/dist/server/agent-engine-api-key-route.js.map +1 -0
  220. package/dist/server/agent-teams.d.ts +62 -0
  221. package/dist/server/agent-teams.d.ts.map +1 -1
  222. package/dist/server/agent-teams.js +99 -2
  223. package/dist/server/agent-teams.js.map +1 -1
  224. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  225. package/dist/server/core-routes-plugin.js +17 -10
  226. package/dist/server/core-routes-plugin.js.map +1 -1
  227. package/dist/server/create-server.js +1 -1
  228. package/dist/server/create-server.js.map +1 -1
  229. package/dist/server/credential-provider.d.ts.map +1 -1
  230. package/dist/server/credential-provider.js +2 -0
  231. package/dist/server/credential-provider.js.map +1 -1
  232. package/dist/server/framework-request-handler.d.ts.map +1 -1
  233. package/dist/server/framework-request-handler.js +33 -1
  234. package/dist/server/framework-request-handler.js.map +1 -1
  235. package/dist/server/index.d.ts +1 -0
  236. package/dist/server/index.d.ts.map +1 -1
  237. package/dist/server/index.js +1 -0
  238. package/dist/server/index.js.map +1 -1
  239. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +17 -4
  240. package/dist/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
  241. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
  242. package/docs/content/agent-teams.md +32 -0
  243. package/docs/content/blueprint-installer.md +73 -0
  244. package/docs/content/evals.md +141 -0
  245. package/docs/content/pr-visual-recap.md +7 -4
  246. package/docs/content/sandbox-adapters.md +134 -0
  247. package/docs/content/template-plan.md +20 -8
  248. package/package.json +5 -1
  249. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +17 -4
  250. package/src/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
  251. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
@@ -1 +1 @@
1
- {"version":3,"file":"plan-local.d.ts","sourceRoot":"","sources":["../../src/cli/plan-local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAcH,KAAK,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtC,KAAK,cAAc,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAyCF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUzD;AAyMD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAiB9D;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,qBAAqB,GAC3B,MAAM,CA2GR;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,CAAC;CAC/C,GAAG,sBAAsB,CAoCzB;AAiMD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C3D"}
1
+ {"version":3,"file":"plan-local.d.ts","sourceRoot":"","sources":["../../src/cli/plan-local.ts"],"names":[],"mappings":"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"}
@@ -2,17 +2,29 @@
2
2
  * Plan helper commands.
3
3
  *
4
4
  * The `plan local` commands are intentionally separate from the Plan app
5
- * actions. They do not call MCP, HTTP, SQLite, or the Plan template runtime;
6
- * they only read and write local files so privacy-focused users have an
7
- * auditable no-DB path. The top-level `plan blocks` command is a schema-only,
8
- * no-auth helper for fetching the public block catalog before authoring local
9
- * MDX; it never sends plan content.
5
+ * actions. They do not call MCP, hosted write actions, SQLite, or hosted
6
+ * storage; they only read local files or serve them from a localhost bridge so
7
+ * privacy-focused users have an auditable no-DB path. The top-level
8
+ * `plan blocks` command is a schema-only, no-auth helper for fetching the
9
+ * public block catalog before authoring local MDX; it never sends plan content.
10
10
  */
11
11
  import fs from "node:fs";
12
+ import crypto from "node:crypto";
13
+ import http from "node:http";
12
14
  import path from "node:path";
13
15
  import { spawnSync } from "node:child_process";
14
16
  import { pathToFileURL } from "node:url";
15
17
  import { DEFAULT_PLAN_APP_URL, defaultPlanBlocksOut, fetchPlanBlockCatalog, normalizePlanBlockFormat, } from "./plan-blocks.js";
18
+ const LOCAL_PLAN_ASSET_MAX_SINGLE_BYTES = 2 * 1024 * 1024;
19
+ const LOCAL_PLAN_ASSET_MAX_TOTAL_BYTES = 10 * 1024 * 1024;
20
+ const LOCAL_PLAN_ASSET_EXTENSIONS = new Set([
21
+ "png",
22
+ "jpg",
23
+ "jpeg",
24
+ "gif",
25
+ "webp",
26
+ "svg",
27
+ ]);
16
28
  function parseArgs(argv) {
17
29
  const out = {};
18
30
  for (let i = 0; i < argv.length; i += 1) {
@@ -65,6 +77,28 @@ function normalizeKind(value) {
65
77
  function defaultPlansDir() {
66
78
  return path.resolve(process.env.PLAN_LOCAL_DIR || "plans");
67
79
  }
80
+ function defaultLocalPlanAppUrl() {
81
+ return (process.env.PLAN_LOCAL_APP_URL ||
82
+ process.env.PLAN_BASE_URL ||
83
+ "http://localhost:8096");
84
+ }
85
+ function defaultLocalPlanBridgeAppUrl() {
86
+ return (process.env.PLAN_LOCAL_BRIDGE_APP_URL ||
87
+ process.env.PLAN_BASE_URL ||
88
+ DEFAULT_PLAN_APP_URL);
89
+ }
90
+ function normalizeAppUrl(value) {
91
+ return (value || defaultLocalPlanAppUrl()).replace(/\/+$/, "");
92
+ }
93
+ function normalizeBridgeAppUrl(value) {
94
+ return (value || defaultLocalPlanBridgeAppUrl()).replace(/\/+$/, "");
95
+ }
96
+ function localPlanPreviewUrl(dir, appUrl) {
97
+ return `${normalizeAppUrl(appUrl)}/local-plans/${encodeURIComponent(path.basename(path.resolve(dir)))}`;
98
+ }
99
+ function localPlanBridgePageUrl(input) {
100
+ return `${normalizeBridgeAppUrl(input.appUrl)}/local-plans/${encodeURIComponent(path.basename(path.resolve(input.dir)))}?bridge=${encodeURIComponent(input.bridgeUrl)}`;
101
+ }
68
102
  function openLocalUrl(url) {
69
103
  const platform = process.platform;
70
104
  const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
@@ -230,6 +264,33 @@ function renderMarkdownish(source) {
230
264
  flushList();
231
265
  return html.join("\n");
232
266
  }
267
+ function readLocalPlanAssets(dir) {
268
+ const assetsDir = path.join(dir, "assets");
269
+ if (!fs.existsSync(assetsDir))
270
+ return undefined;
271
+ const assets = {};
272
+ let totalBytes = 0;
273
+ for (const entry of fs.readdirSync(assetsDir, { withFileTypes: true })) {
274
+ if (!entry.isFile())
275
+ continue;
276
+ const filename = path.basename(entry.name);
277
+ if (!filename || filename !== entry.name)
278
+ continue;
279
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
280
+ if (!LOCAL_PLAN_ASSET_EXTENSIONS.has(ext))
281
+ continue;
282
+ const abs = path.join(assetsDir, filename);
283
+ const bytes = fs.readFileSync(abs);
284
+ if (bytes.byteLength > LOCAL_PLAN_ASSET_MAX_SINGLE_BYTES)
285
+ continue;
286
+ if (totalBytes + bytes.byteLength > LOCAL_PLAN_ASSET_MAX_TOTAL_BYTES) {
287
+ continue;
288
+ }
289
+ totalBytes += bytes.byteLength;
290
+ assets[filename] = bytes.toString("base64");
291
+ }
292
+ return Object.keys(assets).length > 0 ? assets : undefined;
293
+ }
233
294
  export function readLocalPlanFiles(dir) {
234
295
  const resolved = path.resolve(dir);
235
296
  const planPath = path.join(resolved, "plan.mdx");
@@ -246,10 +307,244 @@ export function readLocalPlanFiles(dir) {
246
307
  canvasMdx: readOptional("canvas.mdx"),
247
308
  prototypeMdx: readOptional("prototype.mdx"),
248
309
  stateJson: readOptional(".plan-state.json"),
310
+ assets: readLocalPlanAssets(resolved),
249
311
  };
250
312
  }
313
+ function localPlanMdxFolder(files) {
314
+ return {
315
+ "plan.mdx": files.planMdx,
316
+ ...(files.canvasMdx ? { "canvas.mdx": files.canvasMdx } : {}),
317
+ ...(files.prototypeMdx ? { "prototype.mdx": files.prototypeMdx } : {}),
318
+ ...(files.stateJson ? { ".plan-state.json": files.stateJson } : {}),
319
+ ...(files.assets ? { "assets/": files.assets } : {}),
320
+ };
321
+ }
322
+ function localPlanFileList(files) {
323
+ return [
324
+ "plan.mdx",
325
+ ...(files.canvasMdx ? ["canvas.mdx"] : []),
326
+ ...(files.prototypeMdx ? ["prototype.mdx"] : []),
327
+ ...(files.stateJson ? [".plan-state.json"] : []),
328
+ ...Object.keys(files.assets ?? {}).map((filename) => `assets/${filename}`),
329
+ ];
330
+ }
331
+ function localPlanSourceEntries(files) {
332
+ return [
333
+ { file: "plan.mdx", source: files.planMdx },
334
+ ...(files.canvasMdx
335
+ ? [{ file: "canvas.mdx", source: files.canvasMdx }]
336
+ : []),
337
+ ...(files.prototypeMdx
338
+ ? [{ file: "prototype.mdx", source: files.prototypeMdx }]
339
+ : []),
340
+ ];
341
+ }
342
+ function lineNumberAt(source, index) {
343
+ let line = 1;
344
+ for (let i = 0; i < index; i += 1) {
345
+ if (source.charCodeAt(i) === 10)
346
+ line += 1;
347
+ }
348
+ return line;
349
+ }
350
+ function maskFencedCode(source) {
351
+ return source.replace(/(^|\n)(```|~~~)[\s\S]*?(\n\2[^\n]*(?=\n|$))/g, (match) => match.replace(/[^\n]/g, " "));
352
+ }
353
+ function findJsxOpeningTagEnd(source, start) {
354
+ let quote = null;
355
+ let braceDepth = 0;
356
+ for (let i = start; i < source.length; i += 1) {
357
+ const char = source[i];
358
+ if (quote) {
359
+ if (char === "\\" && i + 1 < source.length) {
360
+ i += 1;
361
+ continue;
362
+ }
363
+ if (char === quote)
364
+ quote = null;
365
+ continue;
366
+ }
367
+ if (char === '"' || char === "'" || char === "`") {
368
+ quote = char;
369
+ continue;
370
+ }
371
+ if (char === "{") {
372
+ braceDepth += 1;
373
+ continue;
374
+ }
375
+ if (char === "}") {
376
+ braceDepth = Math.max(0, braceDepth - 1);
377
+ continue;
378
+ }
379
+ if (char === ">" && braceDepth === 0)
380
+ return i;
381
+ }
382
+ return -1;
383
+ }
384
+ function addValidationIssue(issues, file, source, index, message) {
385
+ issues.push({ file, line: lineNumberAt(source, index), message });
386
+ }
387
+ const ENTITY_RE = /&(?:[a-z][a-z0-9]+|#[0-9]+|#x[0-9a-f]+);/gi;
388
+ const HTML_TEXT_ATTR_RE = /\b(?:aria-label|alt|placeholder|title|value)=\s*(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/gi;
389
+ const WIREFRAME_TEXT_ATTR_RE = /\b(?:text|value|label|placeholder|title|note|due)=\s*(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/gi;
390
+ function normalizeVisibleText(value) {
391
+ return value
392
+ .replace(/&nbsp;|&#160;|&#x0*a0;/gi, " ")
393
+ .replace(ENTITY_RE, "x")
394
+ .replace(/\s+/g, " ")
395
+ .trim();
396
+ }
397
+ function meaningfulTextLength(value) {
398
+ return normalizeVisibleText(value ?? "").length;
399
+ }
400
+ function htmlMeaningfulTextLength(html) {
401
+ let length = 0;
402
+ for (const match of html.matchAll(HTML_TEXT_ATTR_RE)) {
403
+ length += meaningfulTextLength(match[1] ?? match[2] ?? match[3]);
404
+ }
405
+ const visibleText = html
406
+ .replace(/<!--[\s\S]*?-->/g, " ")
407
+ .replace(/<script\b[\s\S]*?<\/script>/gi, " ")
408
+ .replace(/<style\b[\s\S]*?<\/style>/gi, " ")
409
+ .replace(/<[^>]+>/g, " ");
410
+ length += meaningfulTextLength(visibleText);
411
+ return length;
412
+ }
413
+ function hasSkeletonGeometry(html) {
414
+ return (/<(?:div|span|section|main|article|ul|li)\b/i.test(html) &&
415
+ /\b(?:height|width|background|border|padding|wf-card|wf-box|wf-pill|wf-chip)\b/i.test(html));
416
+ }
417
+ function stringAttributeValues(source, name) {
418
+ const values = [];
419
+ const re = new RegExp(`\\b${name}\\s*=\\s*(?:\\{\\s*\`([\\s\\S]*?)\`\\s*\\}|\\{\\s*"([^"]*)"\\s*\\}|\\{\\s*'([^']*)'\\s*\\}|"([^"]*)"|'([^']*)')`, "g");
420
+ for (const match of source.matchAll(re)) {
421
+ const value = match[1] ?? match[2] ?? match[3] ?? match[4] ?? match[5];
422
+ if (value !== undefined)
423
+ values.push(value);
424
+ }
425
+ return values;
426
+ }
427
+ function hasUnparsedAttributeExpression(source, name) {
428
+ return new RegExp(`\\b${name}\\s*=\\s*\\{`).test(source);
429
+ }
430
+ function hasMeaningfulWireframeHtml(screenOpening) {
431
+ const htmlValues = stringAttributeValues(screenOpening, "html");
432
+ if (htmlValues.length === 0) {
433
+ return hasUnparsedAttributeExpression(screenOpening, "html") ? null : false;
434
+ }
435
+ return htmlValues.some((html) => htmlMeaningfulTextLength(html) >= 2 || hasSkeletonGeometry(html));
436
+ }
437
+ function hasMeaningfulKitScreen(screenSource) {
438
+ for (const match of screenSource.matchAll(WIREFRAME_TEXT_ATTR_RE)) {
439
+ if (meaningfulTextLength(match[1] ?? match[2] ?? match[3]) >= 2) {
440
+ return true;
441
+ }
442
+ }
443
+ if (/\bitems\s*=\s*\{[\s\S]*?\blabel\s*:/i.test(screenSource))
444
+ return true;
445
+ if (/\brows\s*=\s*\{[\s\S]*?\b[klv]\s*:/i.test(screenSource))
446
+ return true;
447
+ return false;
448
+ }
449
+ function hasMeaningfulWireframeScreen(blockSource) {
450
+ const screenMatch = /<Screen\b/.exec(blockSource);
451
+ if (!screenMatch)
452
+ return false;
453
+ const screenStart = screenMatch.index;
454
+ const screenOpeningEnd = findJsxOpeningTagEnd(blockSource, screenStart);
455
+ if (screenOpeningEnd < 0)
456
+ return false;
457
+ const screenOpening = blockSource.slice(screenStart, screenOpeningEnd + 1);
458
+ const htmlMeaningful = hasMeaningfulWireframeHtml(screenOpening);
459
+ if (htmlMeaningful === true)
460
+ return true;
461
+ const selfClosing = /\/\s*>$/.test(screenOpening);
462
+ const closeIndex = selfClosing
463
+ ? -1
464
+ : blockSource.indexOf("</Screen>", screenOpeningEnd + 1);
465
+ const screenSource = closeIndex >= 0
466
+ ? blockSource.slice(screenStart, closeIndex + "</Screen>".length)
467
+ : screenOpening;
468
+ if (hasMeaningfulKitScreen(screenSource))
469
+ return true;
470
+ return htmlMeaningful === null ? null : false;
471
+ }
472
+ function lintWireframeBlocks(file, source, issues) {
473
+ const scanSource = maskFencedCode(source);
474
+ const re = /<WireframeBlock\b/g;
475
+ let match;
476
+ while ((match = re.exec(scanSource))) {
477
+ const start = match.index;
478
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
479
+ if (openingEnd < 0) {
480
+ addValidationIssue(issues, file, source, start, "WireframeBlock opening tag is not closed.");
481
+ continue;
482
+ }
483
+ const opening = scanSource.slice(start, openingEnd + 1);
484
+ const unsupportedAttr = opening.match(/\b(data|screens|screen|elements)\s*=/);
485
+ if (unsupportedAttr) {
486
+ addValidationIssue(issues, file, source, start, `WireframeBlock uses unsupported "${unsupportedAttr[1]}" prop. Put content inside a <Screen> child instead.`);
487
+ }
488
+ const selfClosing = /\/\s*>$/.test(opening);
489
+ const closeTag = "</WireframeBlock>";
490
+ const closeIndex = selfClosing
491
+ ? -1
492
+ : scanSource.indexOf(closeTag, openingEnd + 1);
493
+ const blockSource = selfClosing
494
+ ? opening
495
+ : closeIndex >= 0
496
+ ? scanSource.slice(start, closeIndex + closeTag.length)
497
+ : scanSource.slice(start, openingEnd + 1);
498
+ if (!selfClosing && closeIndex < 0) {
499
+ addValidationIssue(issues, file, source, start, "WireframeBlock must have a closing </WireframeBlock> tag.");
500
+ }
501
+ if (selfClosing || !/<Screen\b/.test(blockSource)) {
502
+ addValidationIssue(issues, file, source, start, 'WireframeBlock must wrap a <Screen> child; self-closing wireframes render empty. Use <WireframeBlock><Screen surface="browser">...</Screen></WireframeBlock>.');
503
+ continue;
504
+ }
505
+ const meaningfulScreen = hasMeaningfulWireframeScreen(blockSource);
506
+ if (meaningfulScreen === false) {
507
+ addValidationIssue(issues, file, source, start, 'WireframeBlock contains an empty <Screen>; local previews render blank wireframes. Add visible html text/controls or kit nodes such as <Title text="Checkout" /> and <Btn label="Pay" />.');
508
+ }
509
+ }
510
+ }
511
+ function lintColumnsBlocks(file, source, issues) {
512
+ const scanSource = maskFencedCode(source);
513
+ const re = /<Columns\b/g;
514
+ let match;
515
+ while ((match = re.exec(scanSource))) {
516
+ const start = match.index;
517
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
518
+ if (openingEnd < 0)
519
+ continue;
520
+ const opening = scanSource.slice(start, openingEnd + 1);
521
+ if (/\bcolumns\s*=/.test(opening)) {
522
+ addValidationIssue(issues, file, source, start, 'Columns must use <Column> children, not a columns= prop. Use <Columns><Column label="Before">...</Column><Column label="After">...</Column></Columns>.');
523
+ }
524
+ }
525
+ }
526
+ export function validateLocalPlanFiles(files) {
527
+ const issues = [];
528
+ for (const entry of localPlanSourceEntries(files)) {
529
+ lintWireframeBlocks(entry.file, entry.source, issues);
530
+ lintColumnsBlocks(entry.file, entry.source, issues);
531
+ }
532
+ return issues;
533
+ }
534
+ export function assertLocalPlanFilesValid(files) {
535
+ const issues = validateLocalPlanFiles(files);
536
+ if (issues.length === 0)
537
+ return;
538
+ const details = issues
539
+ .slice(0, 8)
540
+ .map((issue) => `${issue.file}:${issue.line} ${issue.message}`)
541
+ .join("\n");
542
+ const overflow = issues.length > 8 ? `\n...plus ${issues.length - 8} more issues` : "";
543
+ throw new Error(`Local plan source validation failed:\n${details}${overflow}\nRun \`npx @agent-native/core@latest plan blocks --out plan-blocks.md\` and update the MDX to the documented block shapes.`);
544
+ }
251
545
  export function buildLocalPlanPreviewHtml(input) {
252
546
  const files = readLocalPlanFiles(input.dir);
547
+ assertLocalPlanFilesValid(files);
253
548
  const parsed = stripFrontmatter(files.planMdx);
254
549
  const title = input.title ||
255
550
  parsed.frontmatter.title ||
@@ -347,29 +642,27 @@ export function buildLocalPlanPreviewHtml(input) {
347
642
  }
348
643
  export function writeLocalPlanPreview(input) {
349
644
  const dir = path.resolve(input.dir);
350
- const parsed = stripFrontmatter(readLocalPlanFiles(dir).planMdx);
645
+ const files = readLocalPlanFiles(dir);
646
+ assertLocalPlanFilesValid(files);
647
+ const parsed = stripFrontmatter(files.planMdx);
351
648
  const kind = input.kind || normalizeKind(parsed.frontmatter.kind);
352
649
  const title = input.title ||
353
650
  parsed.frontmatter.title ||
354
651
  firstHeading(parsed.body) ||
355
652
  path.basename(dir);
356
- const out = path.resolve(input.out || path.join(dir, "preview.html"));
357
- fs.mkdirSync(path.dirname(out), { recursive: true });
358
- fs.writeFileSync(out, buildLocalPlanPreviewHtml({ ...input, dir, kind }));
359
- const files = [
360
- "plan.mdx",
361
- "canvas.mdx",
362
- "prototype.mdx",
363
- ".plan-state.json",
364
- ].filter((file) => fs.existsSync(path.join(dir, file)));
653
+ const out = input.out ? path.resolve(input.out) : undefined;
654
+ if (out) {
655
+ fs.mkdirSync(path.dirname(out), { recursive: true });
656
+ fs.writeFileSync(out, buildLocalPlanPreviewHtml({ ...input, dir, kind }));
657
+ }
365
658
  const result = {
366
659
  ok: true,
367
660
  dir,
368
- out,
369
- url: pathToFileURL(out).href,
661
+ ...(out ? { out } : {}),
662
+ url: out ? pathToFileURL(out).href : localPlanPreviewUrl(dir, input.appUrl),
370
663
  title,
371
664
  kind,
372
- files,
665
+ files: localPlanFileList(files),
373
666
  };
374
667
  if (!input.open)
375
668
  return result;
@@ -381,6 +674,160 @@ export function writeLocalPlanPreview(input) {
381
674
  ...(openResult.error ? { openError: openResult.error } : {}),
382
675
  };
383
676
  }
677
+ function buildLocalPlanBridgePayload(input) {
678
+ const dir = path.resolve(input.dir);
679
+ const files = readLocalPlanFiles(dir);
680
+ assertLocalPlanFilesValid(files);
681
+ const parsed = stripFrontmatter(files.planMdx);
682
+ const kind = input.kind || normalizeKind(parsed.frontmatter.kind);
683
+ const title = input.title ||
684
+ parsed.frontmatter.title ||
685
+ firstHeading(parsed.body) ||
686
+ path.basename(dir);
687
+ const brief = input.brief || parsed.frontmatter.brief || "";
688
+ return {
689
+ ok: true,
690
+ version: 1,
691
+ source: "agent-native-local-bridge",
692
+ localOnly: true,
693
+ slug: path.basename(dir),
694
+ dir,
695
+ title,
696
+ brief,
697
+ kind,
698
+ updatedAt: latestLocalPlanMtime(dir, files),
699
+ files: localPlanFileList(files),
700
+ mdx: localPlanMdxFolder(files),
701
+ };
702
+ }
703
+ function latestLocalPlanMtime(dir, files) {
704
+ const candidates = [
705
+ path.join(dir, "plan.mdx"),
706
+ ...(files.canvasMdx ? [path.join(dir, "canvas.mdx")] : []),
707
+ ...(files.prototypeMdx ? [path.join(dir, "prototype.mdx")] : []),
708
+ ...(files.stateJson ? [path.join(dir, ".plan-state.json")] : []),
709
+ ...Object.keys(files.assets ?? {}).map((filename) => path.join(dir, "assets", filename)),
710
+ ];
711
+ let latest = 0;
712
+ for (const file of candidates) {
713
+ try {
714
+ latest = Math.max(latest, fs.statSync(file).mtimeMs);
715
+ }
716
+ catch {
717
+ // Ignore files deleted between the read and stat passes.
718
+ }
719
+ }
720
+ return new Date(latest || Date.now()).toISOString();
721
+ }
722
+ function sendBridgeJson(res, status, payload) {
723
+ res.writeHead(status, {
724
+ "access-control-allow-origin": "*",
725
+ "access-control-allow-methods": "GET, OPTIONS",
726
+ "access-control-allow-headers": "content-type",
727
+ "cache-control": "no-store",
728
+ "content-type": "application/json; charset=utf-8",
729
+ "x-agent-native-local-bridge": "1",
730
+ });
731
+ res.end(`${JSON.stringify(payload)}\n`);
732
+ }
733
+ function bridgeRequestUrl(req) {
734
+ return new URL(req.url || "/", "http://127.0.0.1");
735
+ }
736
+ function bridgeHostForUrl(host) {
737
+ if (host === "0.0.0.0" || host === "::")
738
+ return "127.0.0.1";
739
+ return host;
740
+ }
741
+ export async function startLocalPlanBridge(input) {
742
+ const dir = path.resolve(input.dir);
743
+ const initialPayload = buildLocalPlanBridgePayload({
744
+ dir,
745
+ kind: input.kind,
746
+ title: input.title,
747
+ brief: input.brief,
748
+ });
749
+ const token = input.token || crypto.randomBytes(24).toString("base64url");
750
+ const host = input.host || "127.0.0.1";
751
+ const appUrl = normalizeBridgeAppUrl(input.appUrl);
752
+ const server = http.createServer((req, res) => {
753
+ if (req.method === "OPTIONS") {
754
+ sendBridgeJson(res, 204, "");
755
+ return;
756
+ }
757
+ if (req.method !== "GET") {
758
+ sendBridgeJson(res, 405, { ok: false, error: "Method not allowed." });
759
+ return;
760
+ }
761
+ const url = bridgeRequestUrl(req);
762
+ if (url.pathname !== "/local-plan.json") {
763
+ sendBridgeJson(res, 404, { ok: false, error: "Not found." });
764
+ return;
765
+ }
766
+ if (url.searchParams.get("token") !== token) {
767
+ sendBridgeJson(res, 403, { ok: false, error: "Invalid bridge token." });
768
+ return;
769
+ }
770
+ try {
771
+ sendBridgeJson(res, 200, buildLocalPlanBridgePayload({
772
+ dir,
773
+ kind: input.kind,
774
+ title: input.title,
775
+ brief: input.brief,
776
+ }));
777
+ }
778
+ catch (error) {
779
+ sendBridgeJson(res, 500, {
780
+ ok: false,
781
+ error: error instanceof Error ? error.message : String(error),
782
+ });
783
+ }
784
+ });
785
+ await new Promise((resolve, reject) => {
786
+ const onError = (error) => {
787
+ server.off("listening", onListening);
788
+ reject(error);
789
+ };
790
+ const onListening = () => {
791
+ server.off("error", onError);
792
+ resolve();
793
+ };
794
+ server.once("error", onError);
795
+ server.once("listening", onListening);
796
+ server.listen(input.port ?? 0, host);
797
+ });
798
+ const address = server.address();
799
+ if (!address || typeof address === "string") {
800
+ server.close();
801
+ throw new Error("Local plan bridge did not bind to a TCP port.");
802
+ }
803
+ const bridgeUrl = `http://${bridgeHostForUrl(host)}:${address.port}/local-plan.json?token=${encodeURIComponent(token)}`;
804
+ const url = localPlanBridgePageUrl({ dir, bridgeUrl, appUrl });
805
+ const openResult = input.open
806
+ ? (input.openUrl || openLocalUrl)(url)
807
+ : undefined;
808
+ return {
809
+ server,
810
+ result: {
811
+ ok: true,
812
+ dir,
813
+ url,
814
+ bridgeUrl,
815
+ appUrl,
816
+ title: initialPayload.title,
817
+ kind: initialPayload.kind,
818
+ files: initialPayload.files,
819
+ host,
820
+ port: address.port,
821
+ ...(openResult
822
+ ? {
823
+ opened: openResult.ok,
824
+ openCommand: openResult.command,
825
+ ...(openResult.error ? { openError: openResult.error } : {}),
826
+ }
827
+ : {}),
828
+ },
829
+ };
830
+ }
384
831
  function writeLocalPlanSkeleton(input) {
385
832
  const dir = path.resolve(input.dir || path.join(defaultPlansDir(), localPlanFolderName(input.title)));
386
833
  const planPath = path.join(dir, "plan.mdx");
@@ -408,9 +855,9 @@ function writeLocalPlanSkeleton(input) {
408
855
  "## Review Surface",
409
856
  "",
410
857
  "Author the structured plan or recap here. You can add Agent-Native Plan MDX",
411
- "blocks such as `<WireframeBlock />`, `<Diagram />`, `<TabsBlock />`,",
412
- "`<FileTree />`, or `<Diff />`; the local preview will show the source",
413
- "without publishing it to the Plan app.",
858
+ 'blocks such as `<WireframeBlock><Screen surface="browser">...</Screen></WireframeBlock>`,',
859
+ "`<Diagram />`, `<TabsBlock />`, `<FileTree />`, or `<Diff />`; the local",
860
+ "preview will show the source without publishing it to the Plan app.",
414
861
  "",
415
862
  ].join("\n");
416
863
  fs.writeFileSync(planPath, mdx, "utf-8");
@@ -435,10 +882,12 @@ function runInit(args) {
435
882
  function runCheck(args) {
436
883
  const dir = stringArg(args, "dir");
437
884
  const files = readLocalPlanFiles(dir);
885
+ assertLocalPlanFilesValid(files);
438
886
  const parsed = stripFrontmatter(files.planMdx);
439
887
  const result = {
440
888
  ok: true,
441
889
  noDb: true,
890
+ validation: "passed",
442
891
  dir: files.dir,
443
892
  title: parsed.frontmatter.title || firstHeading(parsed.body),
444
893
  kind: normalizeKind(parsed.frontmatter.kind),
@@ -453,6 +902,12 @@ function runCheck(args) {
453
902
  ...(files.stateJson
454
903
  ? { ".plan-state.json": Buffer.byteLength(files.stateJson) }
455
904
  : {}),
905
+ ...(files.assets
906
+ ? Object.fromEntries(Object.entries(files.assets).map(([filename, base64]) => [
907
+ `assets/${filename}`,
908
+ Buffer.byteLength(base64, "base64"),
909
+ ]))
910
+ : {}),
456
911
  },
457
912
  };
458
913
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
@@ -461,6 +916,7 @@ function runPreview(args) {
461
916
  const result = writeLocalPlanPreview({
462
917
  dir: stringArg(args, "dir"),
463
918
  out: optionalArg(args, "out"),
919
+ appUrl: optionalArg(args, "app-url"),
464
920
  title: optionalArg(args, "title"),
465
921
  brief: optionalArg(args, "brief"),
466
922
  open: boolArg(args, "open"),
@@ -470,6 +926,34 @@ function runPreview(args) {
470
926
  });
471
927
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
472
928
  }
929
+ async function runServe(args) {
930
+ const portValue = optionalArg(args, "port");
931
+ const port = portValue ? Number(portValue) : undefined;
932
+ if (portValue && (!Number.isInteger(port) || port < 0 || port > 65535)) {
933
+ throw new Error("--port must be an integer between 0 and 65535.");
934
+ }
935
+ const bridge = await startLocalPlanBridge({
936
+ dir: stringArg(args, "dir"),
937
+ appUrl: optionalArg(args, "app-url"),
938
+ title: optionalArg(args, "title"),
939
+ brief: optionalArg(args, "brief"),
940
+ host: optionalArg(args, "host"),
941
+ port,
942
+ open: boolArg(args, "open"),
943
+ kind: optionalArg(args, "kind")
944
+ ? normalizeKind(optionalArg(args, "kind"))
945
+ : undefined,
946
+ });
947
+ process.stdout.write(`${JSON.stringify(bridge.result, null, 2)}\n`);
948
+ process.stderr.write(`Local Plan bridge running at ${bridge.result.bridgeUrl}\nPress Ctrl+C to stop.\n`);
949
+ await new Promise((resolve) => {
950
+ const stop = () => {
951
+ bridge.server.close(() => resolve());
952
+ };
953
+ process.once("SIGINT", stop);
954
+ process.once("SIGTERM", stop);
955
+ });
956
+ }
473
957
  async function runBlocks(args) {
474
958
  const format = normalizePlanBlockFormat(optionalArg(args, "format"));
475
959
  const appUrl = optionalArg(args, "app-url") ||
@@ -522,7 +1006,8 @@ Usage:
522
1006
  agent-native plan blocks [--format reference|schema] [--app-url <url>] [--out <file>] [--json]
523
1007
  agent-native plan local init --title <title> [--brief <text>] [--kind plan|recap] [--dir <folder>] [--force]
524
1008
  agent-native plan local check --dir <folder>
525
- agent-native plan local preview --dir <folder> [--out preview.html] [--kind plan|recap] [--open]
1009
+ agent-native plan local serve --dir <folder> [--app-url <url>] [--kind plan|recap] [--open] [--port <port>]
1010
+ agent-native plan local preview --dir <folder> [--app-url <url>] [--kind plan|recap] [--open] [--out preview.html]
526
1011
 
527
1012
  The blocks command fetches the no-auth, read-only get-plan-blocks catalog from
528
1013
  the Plan app and writes plan-blocks.md (or plan-blocks.schema.json). It sends no
@@ -538,7 +1023,13 @@ write actions, hosted storage, or SQLite.
538
1023
  Common flow:
539
1024
  agent-native plan blocks --out plan-blocks.md
540
1025
  agent-native plan local init --title "Checkout review" --kind plan
541
- agent-native plan local preview --dir plans/checkout-review --open
1026
+ agent-native plan local serve --dir plans/checkout-review --open
1027
+
1028
+ \`plan local serve\` starts a tiny localhost bridge and opens the hosted Plan UI
1029
+ against that local-only source. The hosted app fetches the MDX from localhost in
1030
+ the browser; it does not write plan content to the hosted database. Use
1031
+ \`plan local preview\` for a local Plan dev server route. \`preview --out\` is a
1032
+ legacy/debug escape hatch that writes a standalone static HTML file.
542
1033
  `;
543
1034
  export async function runPlan(argv) {
544
1035
  const [area, sub, ...rest] = argv;
@@ -574,6 +1065,9 @@ export async function runPlan(argv) {
574
1065
  case "preview":
575
1066
  runPreview(args);
576
1067
  return;
1068
+ case "serve":
1069
+ await runServe(args);
1070
+ return;
577
1071
  case "help":
578
1072
  case "--help":
579
1073
  case "-h":