gsd-pi 2.41.0 → 2.42.0-dev.1df898f
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 +92 -29
- package/dist/cli-web-branch.d.ts +6 -0
- package/dist/cli-web-branch.js +17 -0
- package/dist/cli.js +18 -3
- package/dist/loader.js +3 -1
- package/dist/onboarding.js +2 -1
- package/dist/resource-loader.js +39 -6
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +52 -4
- package/dist/resources/extensions/async-jobs/await-tool.js +5 -0
- package/dist/resources/extensions/async-jobs/index.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +89 -1
- package/dist/resources/extensions/gsd/auto/phases.js +29 -13
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
- package/dist/resources/extensions/gsd/auto-start.js +16 -14
- package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
- package/dist/resources/extensions/gsd/auto.js +64 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +25 -3
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
- package/dist/resources/extensions/gsd/context-injector.js +74 -0
- package/dist/resources/extensions/gsd/context-store.js +4 -3
- package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
- package/dist/resources/extensions/gsd/custom-verification.js +145 -0
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
- package/dist/resources/extensions/gsd/db-writer.js +5 -2
- package/dist/resources/extensions/gsd/definition-loader.js +352 -0
- package/dist/resources/extensions/gsd/detection.js +20 -1
- package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
- package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
- package/dist/resources/extensions/gsd/doctor-checks.js +31 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +10 -0
- package/dist/resources/extensions/gsd/doctor.js +11 -1
- package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
- package/dist/resources/extensions/gsd/engine-types.js +8 -0
- package/dist/resources/extensions/gsd/execution-policy.js +8 -0
- package/dist/resources/extensions/gsd/exit-command.js +12 -2
- package/dist/resources/extensions/gsd/export.js +9 -13
- package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
- package/dist/resources/extensions/gsd/files.js +28 -11
- package/dist/resources/extensions/gsd/forensics.js +94 -3
- package/dist/resources/extensions/gsd/git-constants.js +1 -0
- package/dist/resources/extensions/gsd/git-service.js +6 -2
- package/dist/resources/extensions/gsd/graph.js +225 -0
- package/dist/resources/extensions/gsd/gsd-db.js +25 -8
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +7 -3
- package/dist/resources/extensions/gsd/journal.js +85 -0
- package/dist/resources/extensions/gsd/md-importer.js +5 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +3 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences.js +60 -8
- package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +92 -7
- package/dist/resources/extensions/gsd/rule-registry.js +489 -0
- package/dist/resources/extensions/gsd/rule-types.js +6 -0
- package/dist/resources/extensions/gsd/run-manager.js +134 -0
- package/dist/resources/extensions/gsd/service-tier.js +147 -0
- package/dist/resources/extensions/gsd/session-lock.js +2 -2
- package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
- package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
- package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
- package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
- package/dist/resources/extensions/gsd/worktree-resolver.js +21 -4
- package/dist/resources/extensions/gsd/worktree.js +2 -2
- package/dist/resources/extensions/mcp-client/index.js +2 -1
- package/dist/resources/extensions/search-the-web/tool-search.js +3 -3
- package/dist/resources/extensions/subagent/index.js +7 -3
- package/dist/resources/extensions/voice/index.js +4 -4
- package/dist/resources/skills/create-workflow/SKILL.md +103 -0
- package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/chunks/229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.d.ts +4 -0
- package/dist/web-mode.js +69 -11
- package/package.json +1 -1
- package/packages/native/src/__tests__/text.test.mjs +33 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent.test.ts +53 -0
- package/packages/pi-agent-core/src/agent.ts +3 -0
- package/packages/pi-agent-core/src/types.ts +6 -0
- package/packages/pi-agent-core/tsconfig.json +1 -1
- package/packages/pi-ai/dist/models.d.ts +5 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +801 -1468
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +1135 -1588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +60 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +1543 -0
- package/packages/pi-ai/src/models.generated.ts +1140 -1593
- package/packages/pi-ai/src/models.ts +7 -4
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +74 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +60 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +23 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +63 -11
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +20 -6
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -5
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +34 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +68 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -2
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +18 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +29 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +3 -0
- package/packages/pi-coding-agent/src/core/package-manager.ts +99 -58
- package/packages/pi-coding-agent/src/core/resource-loader.ts +24 -6
- package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +36 -11
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +40 -4
- package/src/resources/extensions/async-jobs/await-tool.test.ts +47 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +5 -0
- package/src/resources/extensions/async-jobs/index.ts +1 -0
- package/src/resources/extensions/async-jobs/job-manager.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -2
- package/src/resources/extensions/gsd/auto/loop.ts +101 -1
- package/src/resources/extensions/gsd/auto/phases.ts +31 -13
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto/types.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -18
- package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
- package/src/resources/extensions/gsd/auto-start.ts +15 -13
- package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
- package/src/resources/extensions/gsd/auto.ts +71 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +25 -4
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
- package/src/resources/extensions/gsd/context-injector.ts +100 -0
- package/src/resources/extensions/gsd/context-store.ts +4 -3
- package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
- package/src/resources/extensions/gsd/custom-verification.ts +180 -0
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
- package/src/resources/extensions/gsd/db-writer.ts +6 -2
- package/src/resources/extensions/gsd/definition-loader.ts +462 -0
- package/src/resources/extensions/gsd/detection.ts +20 -1
- package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
- package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +32 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +13 -0
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/doctor.ts +12 -1
- package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
- package/src/resources/extensions/gsd/engine-types.ts +71 -0
- package/src/resources/extensions/gsd/execution-policy.ts +43 -0
- package/src/resources/extensions/gsd/exit-command.ts +14 -2
- package/src/resources/extensions/gsd/export.ts +8 -15
- package/src/resources/extensions/gsd/extension-manifest.json +2 -2
- package/src/resources/extensions/gsd/files.ts +29 -12
- package/src/resources/extensions/gsd/forensics.ts +101 -3
- package/src/resources/extensions/gsd/git-constants.ts +1 -0
- package/src/resources/extensions/gsd/git-service.ts +5 -5
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/graph.ts +312 -0
- package/src/resources/extensions/gsd/gsd-db.ts +37 -8
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +7 -3
- package/src/resources/extensions/gsd/journal.ts +134 -0
- package/src/resources/extensions/gsd/md-importer.ts +6 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +3 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences.ts +63 -6
- package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/prompts/queue.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +95 -7
- package/src/resources/extensions/gsd/rule-registry.ts +599 -0
- package/src/resources/extensions/gsd/rule-types.ts +68 -0
- package/src/resources/extensions/gsd/run-manager.ts +180 -0
- package/src/resources/extensions/gsd/service-tier.ts +184 -0
- package/src/resources/extensions/gsd/session-lock.ts +2 -2
- package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
- package/src/resources/extensions/gsd/templates/decisions.md +2 -2
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
- package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/journal.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +56 -3
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +156 -263
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +135 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +203 -106
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +79 -5
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
- package/src/resources/extensions/gsd/types.ts +3 -0
- package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
- package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
- package/src/resources/extensions/gsd/worktree-resolver.ts +32 -12
- package/src/resources/extensions/gsd/worktree.ts +2 -2
- package/src/resources/extensions/mcp-client/index.ts +5 -1
- package/src/resources/extensions/search-the-web/tool-search.ts +3 -3
- package/src/resources/extensions/subagent/index.ts +7 -3
- package/src/resources/extensions/voice/index.ts +4 -4
- package/src/resources/skills/create-workflow/SKILL.md +103 -0
- package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
- /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → qw8qDHXOTLUXBq1vEknSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → qw8qDHXOTLUXBq1vEknSz}/_ssgManifest.js +0 -0
package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #1850: doctor task_done_missing_summary fix leaves
|
|
3
|
+
* slice [x] done in roadmap, causing an infinite doctor loop.
|
|
4
|
+
*
|
|
5
|
+
* Scenario: A slice is [x] done in the roadmap, has S01-SUMMARY.md (so
|
|
6
|
+
* slice_checked_missing_summary never fires), but tasks are [x] done with
|
|
7
|
+
* no T##-SUMMARY.md files. Doctor unchecks the tasks but must also uncheck
|
|
8
|
+
* the slice so the state machine re-enters the executing phase.
|
|
9
|
+
*/
|
|
10
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
|
|
14
|
+
import { runGSDDoctor } from "../doctor.js";
|
|
15
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
16
|
+
|
|
17
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
18
|
+
|
|
19
|
+
async function main(): Promise<void> {
|
|
20
|
+
// ─── Setup: slice [x] done with S01-SUMMARY.md, tasks [x] but NO task summaries ───
|
|
21
|
+
console.log("\n=== #1850: task_done_missing_summary fix must also uncheck slice ===");
|
|
22
|
+
{
|
|
23
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-1850-"));
|
|
24
|
+
const gsd = join(base, ".gsd");
|
|
25
|
+
const mDir = join(gsd, "milestones", "M001");
|
|
26
|
+
const sDir = join(mDir, "slices", "S01");
|
|
27
|
+
const tDir = join(sDir, "tasks");
|
|
28
|
+
mkdirSync(tDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
// Roadmap: slice is [x] done
|
|
31
|
+
writeFileSync(join(mDir, "M001-ROADMAP.md"), `# M001: Test Milestone
|
|
32
|
+
|
|
33
|
+
## Slices
|
|
34
|
+
- [x] **S01: Guided Slice** \`risk:low\` \`depends:[]\`
|
|
35
|
+
> After this: guided flow works
|
|
36
|
+
`);
|
|
37
|
+
|
|
38
|
+
// Plan: tasks are [x] done
|
|
39
|
+
writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Guided Slice
|
|
40
|
+
|
|
41
|
+
**Goal:** Test guided flow
|
|
42
|
+
**Demo:** Works
|
|
43
|
+
|
|
44
|
+
## Tasks
|
|
45
|
+
- [x] **T01: First task** \`est:10m\`
|
|
46
|
+
Do the first thing.
|
|
47
|
+
- [x] **T02: Second task** \`est:10m\`
|
|
48
|
+
Do the second thing.
|
|
49
|
+
- [x] **T03: Third task** \`est:10m\`
|
|
50
|
+
Do the third thing.
|
|
51
|
+
`);
|
|
52
|
+
|
|
53
|
+
// Slice summary EXISTS (so slice_checked_missing_summary guard does NOT fire)
|
|
54
|
+
writeFileSync(join(sDir, "S01-SUMMARY.md"), `---
|
|
55
|
+
id: S01
|
|
56
|
+
parent: M001
|
|
57
|
+
---
|
|
58
|
+
# S01: Guided Slice
|
|
59
|
+
Done via guided flow.
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
// Slice UAT exists
|
|
63
|
+
writeFileSync(join(sDir, "S01-UAT.md"), `# S01 UAT
|
|
64
|
+
Verified.
|
|
65
|
+
`);
|
|
66
|
+
|
|
67
|
+
// NO task summaries on disk — this is the trigger condition
|
|
68
|
+
|
|
69
|
+
// ── First pass: diagnose ──
|
|
70
|
+
const diagReport = await runGSDDoctor(base, { fix: false });
|
|
71
|
+
const taskDoneMissing = diagReport.issues.filter(i => i.code === "task_done_missing_summary");
|
|
72
|
+
assertEq(taskDoneMissing.length, 3, "detects 3 tasks with task_done_missing_summary");
|
|
73
|
+
|
|
74
|
+
// ── Second pass: fix ──
|
|
75
|
+
const fixReport = await runGSDDoctor(base, { fix: true });
|
|
76
|
+
|
|
77
|
+
// Tasks should be unchecked in plan
|
|
78
|
+
const plan = readFileSync(join(sDir, "S01-PLAN.md"), "utf-8");
|
|
79
|
+
assertTrue(plan.includes("- [ ] **T01:"), "T01 is unchecked in plan after fix");
|
|
80
|
+
assertTrue(plan.includes("- [ ] **T02:"), "T02 is unchecked in plan after fix");
|
|
81
|
+
assertTrue(plan.includes("- [ ] **T03:"), "T03 is unchecked in plan after fix");
|
|
82
|
+
|
|
83
|
+
// CRITICAL: Slice must also be unchecked in roadmap to prevent infinite loop
|
|
84
|
+
const roadmap = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
|
|
85
|
+
assertTrue(
|
|
86
|
+
roadmap.includes("- [ ] **S01:"),
|
|
87
|
+
"slice is unchecked in roadmap after task_done_missing_summary fix (prevents infinite loop)"
|
|
88
|
+
);
|
|
89
|
+
assertTrue(
|
|
90
|
+
!roadmap.includes("- [x] **S01:"),
|
|
91
|
+
"slice is NOT still [x] done in roadmap"
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// ── Third pass: re-run doctor should NOT re-detect task_done_missing_summary ──
|
|
95
|
+
const rerunReport = await runGSDDoctor(base, { fix: false });
|
|
96
|
+
const rerunTaskDone = rerunReport.issues.filter(i => i.code === "task_done_missing_summary");
|
|
97
|
+
assertEq(rerunTaskDone.length, 0, "no task_done_missing_summary on re-run (no infinite loop)");
|
|
98
|
+
|
|
99
|
+
rmSync(base, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─── Partial fix: only some tasks missing summaries ───
|
|
103
|
+
console.log("\n=== #1850: partial — some tasks have summaries, some do not ===");
|
|
104
|
+
{
|
|
105
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-1850-partial-"));
|
|
106
|
+
const gsd = join(base, ".gsd");
|
|
107
|
+
const mDir = join(gsd, "milestones", "M001");
|
|
108
|
+
const sDir = join(mDir, "slices", "S01");
|
|
109
|
+
const tDir = join(sDir, "tasks");
|
|
110
|
+
mkdirSync(tDir, { recursive: true });
|
|
111
|
+
|
|
112
|
+
writeFileSync(join(mDir, "M001-ROADMAP.md"), `# M001: Test Milestone
|
|
113
|
+
|
|
114
|
+
## Slices
|
|
115
|
+
- [x] **S01: Partial Slice** \`risk:low\` \`depends:[]\`
|
|
116
|
+
> After this: partial
|
|
117
|
+
`);
|
|
118
|
+
|
|
119
|
+
writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Partial Slice
|
|
120
|
+
|
|
121
|
+
**Goal:** Test partial
|
|
122
|
+
**Demo:** Works
|
|
123
|
+
|
|
124
|
+
## Tasks
|
|
125
|
+
- [x] **T01: Has summary** \`est:10m\`
|
|
126
|
+
This task has a summary.
|
|
127
|
+
- [x] **T02: Missing summary** \`est:10m\`
|
|
128
|
+
This task does not.
|
|
129
|
+
`);
|
|
130
|
+
|
|
131
|
+
// T01 has a summary, T02 does not
|
|
132
|
+
writeFileSync(join(tDir, "T01-SUMMARY.md"), `---
|
|
133
|
+
id: T01
|
|
134
|
+
parent: S01
|
|
135
|
+
milestone: M001
|
|
136
|
+
---
|
|
137
|
+
# T01: Has summary
|
|
138
|
+
**Done**
|
|
139
|
+
## What Happened
|
|
140
|
+
Done.
|
|
141
|
+
`);
|
|
142
|
+
|
|
143
|
+
writeFileSync(join(sDir, "S01-SUMMARY.md"), `---
|
|
144
|
+
id: S01
|
|
145
|
+
parent: M001
|
|
146
|
+
---
|
|
147
|
+
# S01: Partial
|
|
148
|
+
`);
|
|
149
|
+
|
|
150
|
+
writeFileSync(join(sDir, "S01-UAT.md"), `# S01 UAT
|
|
151
|
+
Done.
|
|
152
|
+
`);
|
|
153
|
+
|
|
154
|
+
const fixReport = await runGSDDoctor(base, { fix: true });
|
|
155
|
+
|
|
156
|
+
// T02 should be unchecked, T01 should stay checked
|
|
157
|
+
const plan = readFileSync(join(sDir, "S01-PLAN.md"), "utf-8");
|
|
158
|
+
assertTrue(plan.includes("- [x] **T01:"), "T01 stays checked (has summary)");
|
|
159
|
+
assertTrue(plan.includes("- [ ] **T02:"), "T02 is unchecked (missing summary)");
|
|
160
|
+
|
|
161
|
+
// Slice must be unchecked because not all tasks are done anymore
|
|
162
|
+
const roadmap = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
|
|
163
|
+
assertTrue(
|
|
164
|
+
roadmap.includes("- [ ] **S01:"),
|
|
165
|
+
"slice is unchecked when any task is unchecked by task_done_missing_summary"
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
rmSync(base, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
report();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
main();
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* e2e-workflow-pipeline-integration.test.ts — End-to-end integration test
|
|
3
|
+
* proving the assembled workflow engine pipeline works.
|
|
4
|
+
*
|
|
5
|
+
* Exercises every engine feature in a single multi-step workflow:
|
|
6
|
+
* - Dependency-ordered dispatch
|
|
7
|
+
* - Parameter substitution ({{target}})
|
|
8
|
+
* - Content-heuristic verification (minSize)
|
|
9
|
+
* - Shell-command verification (test -f)
|
|
10
|
+
* - Context injection via context_from
|
|
11
|
+
* - Iterate/fan-out expansion
|
|
12
|
+
* - Dashboard metadata (step N/M)
|
|
13
|
+
* - Completion detection (isComplete: true)
|
|
14
|
+
*
|
|
15
|
+
* Operates at the engine level (CustomWorkflowEngine + CustomExecutionPolicy
|
|
16
|
+
* + real temp directories) — NOT through autoLoop() — to avoid the
|
|
17
|
+
* timing-dependent resolveAgentEnd pattern that causes flakiness.
|
|
18
|
+
*
|
|
19
|
+
* Follows the pattern from iterate-engine-integration.test.ts:
|
|
20
|
+
* real temp dirs via mkdtempSync, dispatch()/reconcile() helpers, afterEach cleanup.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { describe, it, afterEach } from "node:test";
|
|
24
|
+
import assert from "node:assert/strict";
|
|
25
|
+
import {
|
|
26
|
+
mkdtempSync,
|
|
27
|
+
rmSync,
|
|
28
|
+
writeFileSync,
|
|
29
|
+
mkdirSync,
|
|
30
|
+
readFileSync,
|
|
31
|
+
existsSync,
|
|
32
|
+
} from "node:fs";
|
|
33
|
+
import { join } from "node:path";
|
|
34
|
+
import { tmpdir } from "node:os";
|
|
35
|
+
import { stringify, parse } from "yaml";
|
|
36
|
+
|
|
37
|
+
import { CustomWorkflowEngine } from "../custom-workflow-engine.ts";
|
|
38
|
+
import { CustomExecutionPolicy } from "../custom-execution-policy.ts";
|
|
39
|
+
import { createRun, listRuns } from "../run-manager.ts";
|
|
40
|
+
import { readGraph, writeGraph } from "../graph.ts";
|
|
41
|
+
import { validateDefinition } from "../definition-loader.ts";
|
|
42
|
+
|
|
43
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
const tmpDirs: string[] = [];
|
|
46
|
+
|
|
47
|
+
function makeTmpDir(): string {
|
|
48
|
+
const dir = mkdtempSync(join(tmpdir(), "e2e-pipeline-"));
|
|
49
|
+
tmpDirs.push(dir);
|
|
50
|
+
return dir;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
for (const d of tmpDirs) {
|
|
55
|
+
try { rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
|
|
56
|
+
}
|
|
57
|
+
tmpDirs.length = 0;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/** Drive deriveState → resolveDispatch. */
|
|
61
|
+
async function dispatch(engine: CustomWorkflowEngine) {
|
|
62
|
+
const state = await engine.deriveState("/unused");
|
|
63
|
+
return { state, result: engine.resolveDispatch(state, { basePath: "/unused" }) };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Drive deriveState → reconcile for a given unitId. */
|
|
67
|
+
async function reconcile(engine: CustomWorkflowEngine, unitId: string) {
|
|
68
|
+
const state = await engine.deriveState("/unused");
|
|
69
|
+
return engine.reconcile(state, {
|
|
70
|
+
unitType: "custom-step",
|
|
71
|
+
unitId,
|
|
72
|
+
startedAt: Date.now() - 1000,
|
|
73
|
+
finishedAt: Date.now(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─── The multi-feature YAML definition (snake_case for loadDefinition) ───
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 4-step workflow definition exercising every engine feature:
|
|
81
|
+
*
|
|
82
|
+
* gather → scan (iterate) → analyze (context_from scan) → report (context_from analyze)
|
|
83
|
+
*
|
|
84
|
+
* Note: The scan step prompt uses a literal string instead of {{item}} in the
|
|
85
|
+
* definition YAML because substituteParams() checks for unresolved {{key}}
|
|
86
|
+
* placeholders. After createRun, we patch GRAPH.yaml to add the {{item}}
|
|
87
|
+
* placeholder so iterate expansion produces item-specific prompts.
|
|
88
|
+
*/
|
|
89
|
+
const E2E_DEFINITION_YAML = `
|
|
90
|
+
version: 1
|
|
91
|
+
name: e2e-pipeline
|
|
92
|
+
description: End-to-end integration test workflow
|
|
93
|
+
params:
|
|
94
|
+
target: default-target
|
|
95
|
+
steps:
|
|
96
|
+
- id: gather
|
|
97
|
+
name: Gather Information
|
|
98
|
+
prompt: "Gather information about {{target}} and produce a bullet list of findings"
|
|
99
|
+
requires: []
|
|
100
|
+
produces:
|
|
101
|
+
- output/gather-results.md
|
|
102
|
+
verify:
|
|
103
|
+
policy: content-heuristic
|
|
104
|
+
minSize: 10
|
|
105
|
+
- id: scan
|
|
106
|
+
name: Scan Items
|
|
107
|
+
prompt: "Scan item: ITEM_PLACEHOLDER"
|
|
108
|
+
requires:
|
|
109
|
+
- gather
|
|
110
|
+
produces:
|
|
111
|
+
- output/scan-result.txt
|
|
112
|
+
verify:
|
|
113
|
+
policy: shell-command
|
|
114
|
+
command: "test -f output/scan-result.txt"
|
|
115
|
+
iterate:
|
|
116
|
+
source: output/gather-results.md
|
|
117
|
+
pattern: "^- (.+)$"
|
|
118
|
+
- id: analyze
|
|
119
|
+
name: Analyze Results
|
|
120
|
+
prompt: "Analyze all scan results and produce a summary"
|
|
121
|
+
requires:
|
|
122
|
+
- scan
|
|
123
|
+
produces:
|
|
124
|
+
- output/analysis.md
|
|
125
|
+
context_from:
|
|
126
|
+
- scan
|
|
127
|
+
verify:
|
|
128
|
+
policy: content-heuristic
|
|
129
|
+
minSize: 5
|
|
130
|
+
- id: report
|
|
131
|
+
name: Final Report
|
|
132
|
+
prompt: "Write final report for {{target}}"
|
|
133
|
+
requires:
|
|
134
|
+
- analyze
|
|
135
|
+
produces:
|
|
136
|
+
- output/report.md
|
|
137
|
+
context_from:
|
|
138
|
+
- analyze
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create a temp project directory with the e2e-pipeline definition YAML,
|
|
143
|
+
* call createRun with param overrides, and patch GRAPH.yaml so the scan
|
|
144
|
+
* step's prompt contains {{item}} for iterate expansion.
|
|
145
|
+
*/
|
|
146
|
+
function setupProject(overrides?: Record<string, string>): {
|
|
147
|
+
basePath: string;
|
|
148
|
+
runDir: string;
|
|
149
|
+
} {
|
|
150
|
+
const basePath = makeTmpDir();
|
|
151
|
+
const defsDir = join(basePath, ".gsd", "workflow-defs");
|
|
152
|
+
mkdirSync(defsDir, { recursive: true });
|
|
153
|
+
writeFileSync(join(defsDir, "e2e-pipeline.yaml"), E2E_DEFINITION_YAML, "utf-8");
|
|
154
|
+
|
|
155
|
+
const runDir = createRun(basePath, "e2e-pipeline", overrides);
|
|
156
|
+
|
|
157
|
+
// Patch GRAPH.yaml: replace the scan step's placeholder with {{item}}
|
|
158
|
+
// so iterate expansion produces item-specific prompts. This works around
|
|
159
|
+
// substituteParams() rejecting unresolved {{item}} in the definition.
|
|
160
|
+
const graph = readGraph(runDir);
|
|
161
|
+
const scanStep = graph.steps.find((s) => s.id === "scan");
|
|
162
|
+
if (scanStep) {
|
|
163
|
+
scanStep.prompt = "Scan item: {{item}}";
|
|
164
|
+
writeGraph(runDir, graph);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { basePath, runDir };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ─── Tests ───────────────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
describe("e2e-workflow-pipeline", () => {
|
|
173
|
+
it("drives the full engine pipeline: create → dispatch → verify → complete", async () => {
|
|
174
|
+
// ── 1. Create run with param overrides ────────────────────────────
|
|
175
|
+
const { basePath, runDir } = setupProject({ target: "my-project" });
|
|
176
|
+
|
|
177
|
+
// Verify run directory structure
|
|
178
|
+
assert.ok(existsSync(join(runDir, "DEFINITION.yaml")), "DEFINITION.yaml should exist");
|
|
179
|
+
assert.ok(existsSync(join(runDir, "GRAPH.yaml")), "GRAPH.yaml should exist");
|
|
180
|
+
assert.ok(existsSync(join(runDir, "PARAMS.json")), "PARAMS.json should exist");
|
|
181
|
+
|
|
182
|
+
// Verify PARAMS.json has the override
|
|
183
|
+
const params = JSON.parse(readFileSync(join(runDir, "PARAMS.json"), "utf-8"));
|
|
184
|
+
assert.deepStrictEqual(params, { target: "my-project" });
|
|
185
|
+
|
|
186
|
+
// Verify the frozen DEFINITION.yaml has substituted params in non-iterate steps
|
|
187
|
+
const frozenDef = readFileSync(join(runDir, "DEFINITION.yaml"), "utf-8");
|
|
188
|
+
assert.ok(
|
|
189
|
+
frozenDef.includes("my-project"),
|
|
190
|
+
"Frozen definition should have substituted 'my-project' for {{target}}",
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Instantiate engine and policy
|
|
194
|
+
const engine = new CustomWorkflowEngine(runDir);
|
|
195
|
+
const policy = new CustomExecutionPolicy(runDir);
|
|
196
|
+
|
|
197
|
+
// Verify initial graph has 4 steps all pending
|
|
198
|
+
const initialGraph = readGraph(runDir);
|
|
199
|
+
assert.equal(initialGraph.steps.length, 4, "Initial graph should have 4 steps");
|
|
200
|
+
assert.ok(
|
|
201
|
+
initialGraph.steps.every((s) => s.status === "pending"),
|
|
202
|
+
"All steps should start as pending",
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// Verify initial state is not complete
|
|
206
|
+
let state = await engine.deriveState("/unused");
|
|
207
|
+
assert.equal(state.isComplete, false, "Workflow should not be complete initially");
|
|
208
|
+
|
|
209
|
+
// Dashboard metadata: 0/4 initially
|
|
210
|
+
let meta = engine.getDisplayMetadata(state);
|
|
211
|
+
assert.equal(meta.stepCount!.completed, 0);
|
|
212
|
+
assert.equal(meta.stepCount!.total, 4);
|
|
213
|
+
assert.equal(meta.progressSummary, "Step 0/4");
|
|
214
|
+
|
|
215
|
+
// ── 2. Step 1: gather ─────────────────────────────────────────────
|
|
216
|
+
const { result: r1 } = await dispatch(engine);
|
|
217
|
+
const d1 = await r1;
|
|
218
|
+
assert.equal(d1.action, "dispatch", "Should dispatch gather step");
|
|
219
|
+
if (d1.action !== "dispatch") throw new Error("unreachable");
|
|
220
|
+
|
|
221
|
+
assert.equal(d1.step.unitId, "e2e-pipeline/gather");
|
|
222
|
+
assert.ok(
|
|
223
|
+
d1.step.prompt.includes("my-project"),
|
|
224
|
+
`Gather prompt should contain substituted param "my-project", got: "${d1.step.prompt}"`,
|
|
225
|
+
);
|
|
226
|
+
assert.ok(
|
|
227
|
+
!d1.step.prompt.includes("default-target"),
|
|
228
|
+
"Gather prompt should NOT contain default param value",
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Simulate agent work: write the gather artifact with bullet items for iterate
|
|
232
|
+
const outputDir = join(runDir, "output");
|
|
233
|
+
mkdirSync(outputDir, { recursive: true });
|
|
234
|
+
writeFileSync(
|
|
235
|
+
join(runDir, "output/gather-results.md"),
|
|
236
|
+
"# Findings for my-project\n\n- security-audit\n- performance-review\n- code-quality\n",
|
|
237
|
+
"utf-8",
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// Reconcile gather
|
|
241
|
+
await reconcile(engine, "e2e-pipeline/gather");
|
|
242
|
+
|
|
243
|
+
// Verify gather: content-heuristic (minSize: 10) should pass
|
|
244
|
+
const gatherVerify = await policy.verify("custom-step", "e2e-pipeline/gather", {
|
|
245
|
+
basePath: "/unused",
|
|
246
|
+
});
|
|
247
|
+
assert.equal(
|
|
248
|
+
gatherVerify,
|
|
249
|
+
"continue",
|
|
250
|
+
"Gather verification (content-heuristic) should pass",
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Dashboard after gather: 1 completed (gather), total still 4
|
|
254
|
+
state = await engine.deriveState("/unused");
|
|
255
|
+
meta = engine.getDisplayMetadata(state);
|
|
256
|
+
assert.equal(meta.stepCount!.completed, 1);
|
|
257
|
+
assert.equal(meta.progressSummary, "Step 1/4");
|
|
258
|
+
assert.equal(state.isComplete, false);
|
|
259
|
+
|
|
260
|
+
// ── 3. Step 2: scan with iterate ──────────────────────────────────
|
|
261
|
+
// Dispatch should trigger iterate expansion from gather-results.md
|
|
262
|
+
const { result: r2 } = await dispatch(engine);
|
|
263
|
+
const d2 = await r2;
|
|
264
|
+
assert.equal(d2.action, "dispatch", "Should dispatch first scan instance");
|
|
265
|
+
if (d2.action !== "dispatch") throw new Error("unreachable");
|
|
266
|
+
|
|
267
|
+
// First instance should be scan--001 for "security-audit"
|
|
268
|
+
assert.equal(d2.step.unitId, "e2e-pipeline/scan--001");
|
|
269
|
+
assert.ok(
|
|
270
|
+
d2.step.prompt.includes("security-audit"),
|
|
271
|
+
`First scan instance prompt should contain "security-audit", got: "${d2.step.prompt}"`,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
// Verify graph expanded: parent "scan" is "expanded", 3 instances exist
|
|
275
|
+
let graph = readGraph(runDir);
|
|
276
|
+
const scanParent = graph.steps.find((s) => s.id === "scan");
|
|
277
|
+
assert.ok(scanParent, "Parent scan step should exist");
|
|
278
|
+
assert.equal(scanParent.status, "expanded", "Parent scan should be expanded");
|
|
279
|
+
|
|
280
|
+
const scanInstances = graph.steps.filter((s) => s.parentStepId === "scan");
|
|
281
|
+
assert.equal(scanInstances.length, 3, "Should have 3 scan instances");
|
|
282
|
+
assert.equal(scanInstances[0].id, "scan--001");
|
|
283
|
+
assert.equal(scanInstances[1].id, "scan--002");
|
|
284
|
+
assert.equal(scanInstances[2].id, "scan--003");
|
|
285
|
+
|
|
286
|
+
// Verify iterate prompts contain item-specific content
|
|
287
|
+
assert.ok(scanInstances[0].prompt.includes("security-audit"));
|
|
288
|
+
assert.ok(scanInstances[1].prompt.includes("performance-review"));
|
|
289
|
+
assert.ok(scanInstances[2].prompt.includes("code-quality"));
|
|
290
|
+
|
|
291
|
+
// Verify dependency rewriting: analyze should now depend on scan--001, scan--002, scan--003
|
|
292
|
+
const analyzeStep = graph.steps.find((s) => s.id === "analyze");
|
|
293
|
+
assert.ok(analyzeStep);
|
|
294
|
+
assert.deepStrictEqual(
|
|
295
|
+
analyzeStep.dependsOn.sort(),
|
|
296
|
+
["scan--001", "scan--002", "scan--003"],
|
|
297
|
+
"Analyze should depend on all scan instances after expansion",
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
// Graph step count increased: 4 original + 3 instances = 7 (parent stays as "expanded")
|
|
301
|
+
assert.equal(graph.steps.length, 7, "Graph should have 7 steps after expansion");
|
|
302
|
+
|
|
303
|
+
// Dashboard after expansion: total now includes instance steps
|
|
304
|
+
state = await engine.deriveState("/unused");
|
|
305
|
+
meta = engine.getDisplayMetadata(state);
|
|
306
|
+
// completed: gather(1), expanded steps don't count as "complete" in getDisplayMetadata
|
|
307
|
+
assert.equal(meta.stepCount!.completed, 1, "Only gather should be complete");
|
|
308
|
+
|
|
309
|
+
// Write scan artifact (same path for all instances since the verify command checks run-dir-relative path)
|
|
310
|
+
writeFileSync(join(runDir, "output/scan-result.txt"), "scan output data", "utf-8");
|
|
311
|
+
|
|
312
|
+
// Complete scan--001, dispatch scan--002
|
|
313
|
+
await reconcile(engine, "e2e-pipeline/scan--001");
|
|
314
|
+
|
|
315
|
+
// Verify analyze is still blocked (not all scan instances complete)
|
|
316
|
+
const { result: r3a } = await dispatch(engine);
|
|
317
|
+
const d3a = await r3a;
|
|
318
|
+
assert.equal(d3a.action, "dispatch");
|
|
319
|
+
if (d3a.action !== "dispatch") throw new Error("unreachable");
|
|
320
|
+
assert.equal(
|
|
321
|
+
d3a.step.unitId,
|
|
322
|
+
"e2e-pipeline/scan--002",
|
|
323
|
+
"Should dispatch scan--002 (analyze still blocked)",
|
|
324
|
+
);
|
|
325
|
+
assert.ok(d3a.step.prompt.includes("performance-review"));
|
|
326
|
+
|
|
327
|
+
// Complete scan--002, dispatch scan--003
|
|
328
|
+
await reconcile(engine, "e2e-pipeline/scan--002");
|
|
329
|
+
const { result: r3b } = await dispatch(engine);
|
|
330
|
+
const d3b = await r3b;
|
|
331
|
+
assert.equal(d3b.action, "dispatch");
|
|
332
|
+
if (d3b.action !== "dispatch") throw new Error("unreachable");
|
|
333
|
+
assert.equal(d3b.step.unitId, "e2e-pipeline/scan--003");
|
|
334
|
+
assert.ok(d3b.step.prompt.includes("code-quality"));
|
|
335
|
+
|
|
336
|
+
// Complete scan--003 — now analyze should be unblocked
|
|
337
|
+
await reconcile(engine, "e2e-pipeline/scan--003");
|
|
338
|
+
|
|
339
|
+
// Dashboard after all scan instances: 4 complete (gather + 3 instances)
|
|
340
|
+
state = await engine.deriveState("/unused");
|
|
341
|
+
meta = engine.getDisplayMetadata(state);
|
|
342
|
+
assert.equal(meta.stepCount!.completed, 4, "gather + 3 scan instances should be complete");
|
|
343
|
+
assert.equal(state.isComplete, false);
|
|
344
|
+
|
|
345
|
+
// ── 4. Step 3: analyze (with context_from scan) ───────────────────
|
|
346
|
+
const { result: r4 } = await dispatch(engine);
|
|
347
|
+
const d4 = await r4;
|
|
348
|
+
assert.equal(d4.action, "dispatch", "Should dispatch analyze step");
|
|
349
|
+
if (d4.action !== "dispatch") throw new Error("unreachable");
|
|
350
|
+
|
|
351
|
+
assert.equal(d4.step.unitId, "e2e-pipeline/analyze");
|
|
352
|
+
|
|
353
|
+
// Context injection: the analyze prompt should include content from scan's produces
|
|
354
|
+
// scan produces output/scan-result.txt and context_from references "scan"
|
|
355
|
+
assert.ok(
|
|
356
|
+
d4.step.prompt.includes("scan output data"),
|
|
357
|
+
`Analyze prompt should include injected context from scan artifact, got: "${d4.step.prompt.slice(0, 200)}"`,
|
|
358
|
+
);
|
|
359
|
+
assert.ok(
|
|
360
|
+
d4.step.prompt.includes("Analyze all scan results"),
|
|
361
|
+
"Analyze prompt should still contain the original prompt text",
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Write analyze artifact
|
|
365
|
+
writeFileSync(
|
|
366
|
+
join(runDir, "output/analysis.md"),
|
|
367
|
+
"# Analysis Summary\n\nAll scans completed successfully with findings.\n",
|
|
368
|
+
"utf-8",
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
await reconcile(engine, "e2e-pipeline/analyze");
|
|
372
|
+
|
|
373
|
+
// Verify analyze: content-heuristic (minSize: 5) should pass
|
|
374
|
+
const analyzeVerify = await policy.verify("custom-step", "e2e-pipeline/analyze", {
|
|
375
|
+
basePath: "/unused",
|
|
376
|
+
});
|
|
377
|
+
assert.equal(
|
|
378
|
+
analyzeVerify,
|
|
379
|
+
"continue",
|
|
380
|
+
"Analyze verification (content-heuristic) should pass",
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// Dashboard after analyze: 5 complete
|
|
384
|
+
state = await engine.deriveState("/unused");
|
|
385
|
+
meta = engine.getDisplayMetadata(state);
|
|
386
|
+
assert.equal(meta.stepCount!.completed, 5);
|
|
387
|
+
assert.equal(state.isComplete, false, "Should not be complete yet (report remaining)");
|
|
388
|
+
|
|
389
|
+
// ── 5. Step 4: report (with context_from analyze + param) ─────────
|
|
390
|
+
const { result: r5 } = await dispatch(engine);
|
|
391
|
+
const d5 = await r5;
|
|
392
|
+
assert.equal(d5.action, "dispatch", "Should dispatch report step");
|
|
393
|
+
if (d5.action !== "dispatch") throw new Error("unreachable");
|
|
394
|
+
|
|
395
|
+
assert.equal(d5.step.unitId, "e2e-pipeline/report");
|
|
396
|
+
|
|
397
|
+
// Context injection: report prompt should include content from analyze's produces
|
|
398
|
+
assert.ok(
|
|
399
|
+
d5.step.prompt.includes("Analysis Summary"),
|
|
400
|
+
`Report prompt should include injected context from analyze artifact, got: "${d5.step.prompt.slice(0, 200)}"`,
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
// Parameter substitution: report prompt should contain "my-project"
|
|
404
|
+
assert.ok(
|
|
405
|
+
d5.step.prompt.includes("my-project"),
|
|
406
|
+
`Report prompt should contain substituted param "my-project", got: "${d5.step.prompt}"`,
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
// Write report artifact
|
|
410
|
+
writeFileSync(
|
|
411
|
+
join(runDir, "output/report.md"),
|
|
412
|
+
"# Final Report for my-project\n\nComprehensive findings documented.\n",
|
|
413
|
+
"utf-8",
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
await reconcile(engine, "e2e-pipeline/report");
|
|
417
|
+
|
|
418
|
+
// ── 6. Completion ─────────────────────────────────────────────────
|
|
419
|
+
state = await engine.deriveState("/unused");
|
|
420
|
+
assert.equal(state.isComplete, true, "Workflow should be complete after all steps");
|
|
421
|
+
assert.equal(state.phase, "complete");
|
|
422
|
+
|
|
423
|
+
// Dashboard: all steps complete
|
|
424
|
+
meta = engine.getDisplayMetadata(state);
|
|
425
|
+
assert.equal(meta.stepCount!.completed, 6, "All 6 dispatchable steps should be complete");
|
|
426
|
+
assert.equal(meta.currentPhase, "complete");
|
|
427
|
+
|
|
428
|
+
// Dispatch should return stop
|
|
429
|
+
const { result: rFinal } = await dispatch(engine);
|
|
430
|
+
const dFinal = await rFinal;
|
|
431
|
+
assert.equal(dFinal.action, "stop");
|
|
432
|
+
if (dFinal.action === "stop") {
|
|
433
|
+
assert.equal(dFinal.reason, "All steps complete");
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Verify shell-command policy works on the scan step (parent, not instance)
|
|
437
|
+
const shellVerify = await policy.verify("custom-step", "e2e-pipeline/scan", {
|
|
438
|
+
basePath: "/unused",
|
|
439
|
+
});
|
|
440
|
+
assert.equal(
|
|
441
|
+
shellVerify,
|
|
442
|
+
"continue",
|
|
443
|
+
"Shell-command verification (test -f output/scan-result.txt) should pass",
|
|
444
|
+
);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
describe("createRun + listRuns integration", () => {
|
|
448
|
+
it("created run appears in listRuns with correct metadata", () => {
|
|
449
|
+
const { basePath, runDir } = setupProject({ target: "list-test" });
|
|
450
|
+
|
|
451
|
+
const runs = listRuns(basePath, "e2e-pipeline");
|
|
452
|
+
assert.ok(runs.length >= 1, "Should list at least one run");
|
|
453
|
+
|
|
454
|
+
const thisRun = runs.find((r) => r.runDir === runDir);
|
|
455
|
+
assert.ok(thisRun, "Created run should appear in listRuns");
|
|
456
|
+
assert.equal(thisRun.name, "e2e-pipeline");
|
|
457
|
+
assert.equal(thisRun.status, "pending", "New run should have pending status");
|
|
458
|
+
assert.equal(thisRun.steps.total, 4, "Should have 4 steps");
|
|
459
|
+
assert.equal(thisRun.steps.completed, 0);
|
|
460
|
+
assert.equal(thisRun.steps.pending, 4);
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
describe("validateDefinition accepts the e2e definition", () => {
|
|
465
|
+
it("validates the e2e-pipeline YAML as valid V1 schema", () => {
|
|
466
|
+
const parsed = parse(E2E_DEFINITION_YAML);
|
|
467
|
+
const { valid, errors } = validateDefinition(parsed);
|
|
468
|
+
assert.equal(
|
|
469
|
+
valid,
|
|
470
|
+
true,
|
|
471
|
+
`Definition should be valid but got errors: ${errors.join(", ")}`,
|
|
472
|
+
);
|
|
473
|
+
assert.deepStrictEqual(errors, []);
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
});
|