@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.
- package/README.md +42 -96
- package/blueprints/action/crud.md +98 -0
- package/blueprints/channel/discord.md +74 -0
- package/blueprints/provider/stripe.md +87 -0
- package/blueprints/sandbox/docker.md +78 -0
- package/dist/action.d.ts +24 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +4 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/observational-memory/compactor.d.ts +43 -0
- package/dist/agent/observational-memory/compactor.d.ts.map +1 -0
- package/dist/agent/observational-memory/compactor.js +50 -0
- package/dist/agent/observational-memory/compactor.js.map +1 -0
- package/dist/agent/observational-memory/config.d.ts +37 -0
- package/dist/agent/observational-memory/config.d.ts.map +1 -0
- package/dist/agent/observational-memory/config.js +48 -0
- package/dist/agent/observational-memory/config.js.map +1 -0
- package/dist/agent/observational-memory/index.d.ts +26 -0
- package/dist/agent/observational-memory/index.d.ts.map +1 -0
- package/dist/agent/observational-memory/index.js +25 -0
- package/dist/agent/observational-memory/index.js.map +1 -0
- package/dist/agent/observational-memory/internal-run.d.ts +37 -0
- package/dist/agent/observational-memory/internal-run.d.ts.map +1 -0
- package/dist/agent/observational-memory/internal-run.js +59 -0
- package/dist/agent/observational-memory/internal-run.js.map +1 -0
- package/dist/agent/observational-memory/message-text.d.ts +13 -0
- package/dist/agent/observational-memory/message-text.d.ts.map +1 -0
- package/dist/agent/observational-memory/message-text.js +46 -0
- package/dist/agent/observational-memory/message-text.js.map +1 -0
- package/dist/agent/observational-memory/migrations.d.ts +13 -0
- package/dist/agent/observational-memory/migrations.d.ts.map +1 -0
- package/dist/agent/observational-memory/migrations.js +43 -0
- package/dist/agent/observational-memory/migrations.js.map +1 -0
- package/dist/agent/observational-memory/observer.d.ts +37 -0
- package/dist/agent/observational-memory/observer.d.ts.map +1 -0
- package/dist/agent/observational-memory/observer.js +82 -0
- package/dist/agent/observational-memory/observer.js.map +1 -0
- package/dist/agent/observational-memory/plugin.d.ts +16 -0
- package/dist/agent/observational-memory/plugin.d.ts.map +1 -0
- package/dist/agent/observational-memory/plugin.js +26 -0
- package/dist/agent/observational-memory/plugin.js.map +1 -0
- package/dist/agent/observational-memory/prompts.d.ts +27 -0
- package/dist/agent/observational-memory/prompts.d.ts.map +1 -0
- package/dist/agent/observational-memory/prompts.js +42 -0
- package/dist/agent/observational-memory/prompts.js.map +1 -0
- package/dist/agent/observational-memory/read.d.ts +47 -0
- package/dist/agent/observational-memory/read.d.ts.map +1 -0
- package/dist/agent/observational-memory/read.js +99 -0
- package/dist/agent/observational-memory/read.js.map +1 -0
- package/dist/agent/observational-memory/reflector.d.ts +31 -0
- package/dist/agent/observational-memory/reflector.d.ts.map +1 -0
- package/dist/agent/observational-memory/reflector.js +76 -0
- package/dist/agent/observational-memory/reflector.js.map +1 -0
- package/dist/agent/observational-memory/schema.d.ts +267 -0
- package/dist/agent/observational-memory/schema.d.ts.map +1 -0
- package/dist/agent/observational-memory/schema.js +48 -0
- package/dist/agent/observational-memory/schema.js.map +1 -0
- package/dist/agent/observational-memory/store.d.ts +52 -0
- package/dist/agent/observational-memory/store.d.ts.map +1 -0
- package/dist/agent/observational-memory/store.js +197 -0
- package/dist/agent/observational-memory/store.js.map +1 -0
- package/dist/agent/observational-memory/types.d.ts +61 -0
- package/dist/agent/observational-memory/types.d.ts.map +1 -0
- package/dist/agent/observational-memory/types.js +9 -0
- package/dist/agent/observational-memory/types.js.map +1 -0
- package/dist/agent/production-agent.d.ts +15 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +240 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +49 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-store.d.ts +17 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +55 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/runtime-context.d.ts +30 -0
- package/dist/agent/runtime-context.d.ts.map +1 -1
- package/dist/agent/runtime-context.js +54 -1
- package/dist/agent/runtime-context.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +101 -0
- package/dist/agent/tool-call-journal.d.ts.map +1 -0
- package/dist/agent/tool-call-journal.js +214 -0
- package/dist/agent/tool-call-journal.js.map +1 -0
- package/dist/agent/types.d.ts +24 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/add.d.ts +109 -0
- package/dist/cli/add.d.ts.map +1 -0
- package/dist/cli/add.js +352 -0
- package/dist/cli/add.js.map +1 -0
- package/dist/cli/connect.d.ts +5 -4
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +157 -48
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/eval.d.ts +17 -0
- package/dist/cli/eval.d.ts.map +1 -0
- package/dist/cli/eval.js +121 -0
- package/dist/cli/eval.js.map +1 -0
- package/dist/cli/index.js +44 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +20 -13
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +152 -13
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts +2 -2
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +50 -196
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/plan-local.d.ts +69 -6
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +517 -23
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +1 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +13 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +287 -111
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +118 -92
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +16 -0
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-engine-key.d.ts +6 -4
- package/dist/client/agent-engine-key.d.ts.map +1 -1
- package/dist/client/agent-engine-key.js +9 -6
- package/dist/client/agent-engine-key.js.map +1 -1
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +20 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +32 -7
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +7 -14
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +13 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +21 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts +7 -0
- package/dist/coding-tools/run-code.d.ts.map +1 -1
- package/dist/coding-tools/run-code.js +21 -106
- package/dist/coding-tools/run-code.js.map +1 -1
- package/dist/coding-tools/sandbox/adapter.d.ts +79 -0
- package/dist/coding-tools/sandbox/adapter.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/adapter.js +24 -0
- package/dist/coding-tools/sandbox/adapter.js.map +1 -0
- package/dist/coding-tools/sandbox/index.d.ts +51 -0
- package/dist/coding-tools/sandbox/index.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/index.js +79 -0
- package/dist/coding-tools/sandbox/index.js.map +1 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts +24 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.js +141 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.js.map +1 -0
- package/dist/db/client.d.ts +4 -2
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +6 -4
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/route-discovery.d.ts.map +1 -1
- package/dist/deploy/route-discovery.js +1 -0
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/eval/agent-runner.d.ts +63 -0
- package/dist/eval/agent-runner.d.ts.map +1 -0
- package/dist/eval/agent-runner.js +142 -0
- package/dist/eval/agent-runner.js.map +1 -0
- package/dist/eval/define-eval.d.ts +29 -0
- package/dist/eval/define-eval.d.ts.map +1 -0
- package/dist/eval/define-eval.js +43 -0
- package/dist/eval/define-eval.js.map +1 -0
- package/dist/eval/index.d.ts +18 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +17 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/report.d.ts +8 -0
- package/dist/eval/report.d.ts.map +1 -0
- package/dist/eval/report.js +44 -0
- package/dist/eval/report.js.map +1 -0
- package/dist/eval/runner.d.ts +67 -0
- package/dist/eval/runner.d.ts.map +1 -0
- package/dist/eval/runner.js +256 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/eval/scorer.d.ts +83 -0
- package/dist/eval/scorer.d.ts.map +1 -0
- package/dist/eval/scorer.js +195 -0
- package/dist/eval/scorer.js.map +1 -0
- package/dist/eval/types.d.ts +162 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +20 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +100 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/observability/tracing.d.ts +73 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +126 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +4 -1
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +10 -3
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +9 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +118 -110
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +37 -0
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -0
- package/dist/server/agent-engine-api-key-route.js +105 -0
- package/dist/server/agent-engine-api-key-route.js.map +1 -0
- package/dist/server/agent-teams.d.ts +62 -0
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +99 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +17 -10
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/create-server.js +1 -1
- package/dist/server/create-server.js.map +1 -1
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +2 -0
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +33 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +17 -4
- package/dist/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/docs/content/agent-teams.md +32 -0
- package/docs/content/blueprint-installer.md +73 -0
- package/docs/content/evals.md +141 -0
- package/docs/content/pr-visual-recap.md +7 -4
- package/docs/content/sandbox-adapters.md +134 -0
- package/docs/content/template-plan.md +20 -8
- package/package.json +5 -1
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +17 -4
- package/src/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
- 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;
|
|
1
|
+
{"version":3,"file":"plan-local.d.ts","sourceRoot":"","sources":["../../src/cli/plan-local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAa,EAEX,KAAK,MAAM,EAEZ,MAAM,WAAW,CAAC;AAYnB,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;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,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;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,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,wBAAwB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,2BAA2B,CAAC;IACpC,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,wBAAwB,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAoDF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUzD;AA2QD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAkB9D;AA8SD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,GACpB,wBAAwB,EAAE,CAO5B;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAYrE;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,qBAAqB,GAC3B,MAAM,CA4GR;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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,CAAC;CAC/C,GAAG,sBAAsB,CAkCzB;AAkFD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,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,OAAO,CAAC,qBAAqB,CAAC,CAoGjC;AAqPD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiD3D"}
|
package/dist/cli/plan-local.js
CHANGED
|
@@ -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,
|
|
6
|
-
* they only read
|
|
7
|
-
* auditable no-DB path. The top-level
|
|
8
|
-
* no-auth helper for fetching the
|
|
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(/ | |�*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
|
|
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 =
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
412
|
-
"`<FileTree />`, or `<Diff />`; the local
|
|
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
|
|
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
|
|
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":
|