gsd-pi 2.41.0-dev.0acbce9 ā 2.41.0-dev.5a170d0
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 +1 -1
- package/dist/cli-web-branch.d.ts +6 -0
- package/dist/cli-web-branch.js +17 -0
- package/dist/onboarding.js +2 -1
- package/dist/resources/extensions/gsd/auto/loop.js +89 -1
- package/dist/resources/extensions/gsd/auto/phases.js +28 -10
- 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-recovery.js +12 -4
- package/dist/resources/extensions/gsd/auto-start.js +8 -3
- 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 +16 -0
- 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 +1 -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.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 +10 -3
- package/dist/resources/extensions/gsd/git-service.js +5 -1
- 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 +2 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences.js +1 -0
- 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/queue.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +46 -2
- 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 +138 -0
- 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 +19 -2
- 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 +16 -16
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- 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/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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.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/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.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/skill-health/route.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/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
- package/dist/web/standalone/.next/server/chunks/229.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/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/{webpack-9afaaebf6042a1d7.js ā webpack-fa307370fcf9fb2c.js} +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +29 -7
- package/package.json +1 -1
- package/packages/native/src/__tests__/text.test.mjs +33 -0
- 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/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 +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
- 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 +5 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
- package/src/resources/extensions/gsd/auto/loop.ts +101 -1
- package/src/resources/extensions/gsd/auto/phases.ts +30 -10
- 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-recovery.ts +12 -4
- package/src/resources/extensions/gsd/auto-start.ts +8 -3
- 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 +13 -0
- 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 +1 -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.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 +9 -3
- package/src/resources/extensions/gsd/git-service.ts +5 -4
- 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 +2 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences.ts +1 -0
- 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/queue.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +47 -2
- 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 +171 -0
- 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/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/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 +386 -0
- 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 +98 -0
- 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/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/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 +178 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +195 -105
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
- 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 +30 -9
- 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/{SwbKZ7JPNFlEmU4f8pKEv ā K7GYOOPvQWX6TKYEKhODM}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{SwbKZ7JPNFlEmU4f8pKEv ā K7GYOOPvQWX6TKYEKhODM}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* custom-workflow-engine.test.ts ā Tests for CustomWorkflowEngine and CustomExecutionPolicy.
|
|
3
|
+
*
|
|
4
|
+
* Uses real temp directories with actual GRAPH.yaml files ā no mocks.
|
|
5
|
+
* Tests the full engine lifecycle: deriveState ā resolveDispatch ā reconcile.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, afterEach } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdtempSync, rmSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { parse } from "yaml";
|
|
14
|
+
|
|
15
|
+
import { CustomWorkflowEngine } from "../custom-workflow-engine.ts";
|
|
16
|
+
import { CustomExecutionPolicy } from "../custom-execution-policy.ts";
|
|
17
|
+
import { writeGraph, readGraph, type WorkflowGraph, type GraphStep } from "../graph.ts";
|
|
18
|
+
import { stringify } from "yaml";
|
|
19
|
+
|
|
20
|
+
// āāā Helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
21
|
+
|
|
22
|
+
const tmpDirs: string[] = [];
|
|
23
|
+
|
|
24
|
+
function makeTmpDir(): string {
|
|
25
|
+
const dir = mkdtempSync(join(tmpdir(), "engine-test-"));
|
|
26
|
+
tmpDirs.push(dir);
|
|
27
|
+
return dir;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
for (const d of tmpDirs) {
|
|
32
|
+
try { rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
|
|
33
|
+
}
|
|
34
|
+
tmpDirs.length = 0;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function makeStep(overrides: Partial<GraphStep> & { id: string }): GraphStep {
|
|
38
|
+
return {
|
|
39
|
+
title: overrides.id,
|
|
40
|
+
status: "pending",
|
|
41
|
+
prompt: `Do ${overrides.id}`,
|
|
42
|
+
dependsOn: [],
|
|
43
|
+
...overrides,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function makeGraph(steps: GraphStep[], name = "test-wf"): WorkflowGraph {
|
|
48
|
+
return {
|
|
49
|
+
steps,
|
|
50
|
+
metadata: { name, createdAt: "2026-01-01T00:00:00.000Z" },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Write a graph to a temp dir and return engine + dir. Also writes a minimal DEFINITION.yaml so resolveDispatch/injectContext can read it. */
|
|
55
|
+
function setupEngine(
|
|
56
|
+
steps: GraphStep[],
|
|
57
|
+
name = "test-wf",
|
|
58
|
+
): { engine: CustomWorkflowEngine; runDir: string } {
|
|
59
|
+
const runDir = makeTmpDir();
|
|
60
|
+
const graph = makeGraph(steps, name);
|
|
61
|
+
writeGraph(runDir, graph);
|
|
62
|
+
|
|
63
|
+
// Write a minimal DEFINITION.yaml matching the graph steps
|
|
64
|
+
const def = {
|
|
65
|
+
version: 1,
|
|
66
|
+
name,
|
|
67
|
+
steps: steps.map((s) => ({
|
|
68
|
+
id: s.id,
|
|
69
|
+
name: s.title,
|
|
70
|
+
prompt: s.prompt,
|
|
71
|
+
requires: s.dependsOn,
|
|
72
|
+
produces: [],
|
|
73
|
+
})),
|
|
74
|
+
};
|
|
75
|
+
writeFileSync(join(runDir, "DEFINITION.yaml"), stringify(def), "utf-8");
|
|
76
|
+
|
|
77
|
+
return { engine: new CustomWorkflowEngine(runDir), runDir };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// āāā deriveState āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
81
|
+
|
|
82
|
+
describe("CustomWorkflowEngine.deriveState", () => {
|
|
83
|
+
it("returns running phase when steps are pending", async () => {
|
|
84
|
+
const { engine } = setupEngine([
|
|
85
|
+
makeStep({ id: "a" }),
|
|
86
|
+
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
const state = await engine.deriveState("/unused");
|
|
90
|
+
|
|
91
|
+
assert.equal(state.phase, "running");
|
|
92
|
+
assert.equal(state.isComplete, false);
|
|
93
|
+
assert.ok(state.raw, "raw should contain the graph");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("returns complete phase when all steps are complete", async () => {
|
|
97
|
+
const { engine } = setupEngine([
|
|
98
|
+
makeStep({ id: "a", status: "complete" }),
|
|
99
|
+
makeStep({ id: "b", status: "complete" }),
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
const state = await engine.deriveState("/unused");
|
|
103
|
+
|
|
104
|
+
assert.equal(state.phase, "complete");
|
|
105
|
+
assert.equal(state.isComplete, true);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("treats expanded steps as done for completion check", async () => {
|
|
109
|
+
const { engine } = setupEngine([
|
|
110
|
+
makeStep({ id: "a", status: "expanded" }),
|
|
111
|
+
makeStep({ id: "a--001", status: "complete", parentStepId: "a" }),
|
|
112
|
+
makeStep({ id: "b", status: "complete" }),
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
const state = await engine.deriveState("/unused");
|
|
116
|
+
|
|
117
|
+
assert.equal(state.phase, "complete");
|
|
118
|
+
assert.equal(state.isComplete, true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// āāā resolveDispatch āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
123
|
+
|
|
124
|
+
describe("CustomWorkflowEngine.resolveDispatch", () => {
|
|
125
|
+
it("returns dispatch for first pending step", async () => {
|
|
126
|
+
const { engine } = setupEngine([
|
|
127
|
+
makeStep({ id: "step-1", prompt: "Do the first thing" }),
|
|
128
|
+
makeStep({ id: "step-2", dependsOn: ["step-1"] }),
|
|
129
|
+
], "my-workflow");
|
|
130
|
+
|
|
131
|
+
const state = await engine.deriveState("/unused");
|
|
132
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
133
|
+
|
|
134
|
+
assert.equal(dispatch.action, "dispatch");
|
|
135
|
+
if (dispatch.action === "dispatch") {
|
|
136
|
+
assert.equal(dispatch.step.unitType, "custom-step");
|
|
137
|
+
assert.equal(dispatch.step.unitId, "my-workflow/step-1");
|
|
138
|
+
assert.equal(dispatch.step.prompt, "Do the first thing");
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("returns stop when all steps are complete", async () => {
|
|
143
|
+
const { engine } = setupEngine([
|
|
144
|
+
makeStep({ id: "a", status: "complete" }),
|
|
145
|
+
makeStep({ id: "b", status: "complete" }),
|
|
146
|
+
]);
|
|
147
|
+
|
|
148
|
+
const state = await engine.deriveState("/unused");
|
|
149
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
150
|
+
|
|
151
|
+
assert.equal(dispatch.action, "stop");
|
|
152
|
+
if (dispatch.action === "stop") {
|
|
153
|
+
assert.equal(dispatch.reason, "All steps complete");
|
|
154
|
+
assert.equal(dispatch.level, "info");
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("respects dependency ordering", async () => {
|
|
159
|
+
const { engine } = setupEngine([
|
|
160
|
+
makeStep({ id: "a" }),
|
|
161
|
+
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
162
|
+
makeStep({ id: "c", dependsOn: ["b"] }),
|
|
163
|
+
], "dep-wf");
|
|
164
|
+
|
|
165
|
+
const state = await engine.deriveState("/unused");
|
|
166
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
167
|
+
|
|
168
|
+
// Should pick "a" (no deps), not "b" or "c"
|
|
169
|
+
assert.equal(dispatch.action, "dispatch");
|
|
170
|
+
if (dispatch.action === "dispatch") {
|
|
171
|
+
assert.equal(dispatch.step.unitId, "dep-wf/a");
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("picks next eligible step when earlier deps are complete", async () => {
|
|
176
|
+
const { engine } = setupEngine([
|
|
177
|
+
makeStep({ id: "a", status: "complete" }),
|
|
178
|
+
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
179
|
+
makeStep({ id: "c", dependsOn: ["b"] }),
|
|
180
|
+
], "dep-wf");
|
|
181
|
+
|
|
182
|
+
const state = await engine.deriveState("/unused");
|
|
183
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
184
|
+
|
|
185
|
+
// "a" is done, "b" deps met, should pick "b"
|
|
186
|
+
assert.equal(dispatch.action, "dispatch");
|
|
187
|
+
if (dispatch.action === "dispatch") {
|
|
188
|
+
assert.equal(dispatch.step.unitId, "dep-wf/b");
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// āāā reconcile āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
194
|
+
|
|
195
|
+
describe("CustomWorkflowEngine.reconcile", () => {
|
|
196
|
+
it("marks step complete in GRAPH.yaml on disk", async () => {
|
|
197
|
+
const { engine, runDir } = setupEngine([
|
|
198
|
+
makeStep({ id: "step-1" }),
|
|
199
|
+
makeStep({ id: "step-2", dependsOn: ["step-1"] }),
|
|
200
|
+
], "wf");
|
|
201
|
+
|
|
202
|
+
const state = await engine.deriveState("/unused");
|
|
203
|
+
const result = await engine.reconcile(state, {
|
|
204
|
+
unitType: "custom-step",
|
|
205
|
+
unitId: "wf/step-1",
|
|
206
|
+
startedAt: Date.now() - 1000,
|
|
207
|
+
finishedAt: Date.now(),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
assert.equal(result.outcome, "continue");
|
|
211
|
+
|
|
212
|
+
// Verify on-disk state
|
|
213
|
+
const graph = readGraph(runDir);
|
|
214
|
+
assert.equal(graph.steps[0].status, "complete");
|
|
215
|
+
assert.ok(graph.steps[0].finishedAt, "finishedAt should be set");
|
|
216
|
+
assert.equal(graph.steps[1].status, "pending");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("returns milestone-complete when all steps done", async () => {
|
|
220
|
+
const { engine } = setupEngine([
|
|
221
|
+
makeStep({ id: "only-step" }),
|
|
222
|
+
], "wf");
|
|
223
|
+
|
|
224
|
+
const state = await engine.deriveState("/unused");
|
|
225
|
+
const result = await engine.reconcile(state, {
|
|
226
|
+
unitType: "custom-step",
|
|
227
|
+
unitId: "wf/only-step",
|
|
228
|
+
startedAt: Date.now() - 1000,
|
|
229
|
+
finishedAt: Date.now(),
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
assert.equal(result.outcome, "milestone-complete");
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("handles multi-segment unitId correctly", async () => {
|
|
236
|
+
const { engine, runDir } = setupEngine([
|
|
237
|
+
makeStep({ id: "deep-step" }),
|
|
238
|
+
], "nested/workflow");
|
|
239
|
+
|
|
240
|
+
const state = await engine.deriveState("/unused");
|
|
241
|
+
const result = await engine.reconcile(state, {
|
|
242
|
+
unitType: "custom-step",
|
|
243
|
+
unitId: "nested/workflow/deep-step",
|
|
244
|
+
startedAt: Date.now() - 1000,
|
|
245
|
+
finishedAt: Date.now(),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
assert.equal(result.outcome, "milestone-complete");
|
|
249
|
+
const graph = readGraph(runDir);
|
|
250
|
+
assert.equal(graph.steps[0].status, "complete");
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// āāā getDisplayMetadata āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
255
|
+
|
|
256
|
+
describe("CustomWorkflowEngine.getDisplayMetadata", () => {
|
|
257
|
+
it("returns correct progress summary", async () => {
|
|
258
|
+
const { engine } = setupEngine([
|
|
259
|
+
makeStep({ id: "a", status: "complete" }),
|
|
260
|
+
makeStep({ id: "b" }),
|
|
261
|
+
makeStep({ id: "c" }),
|
|
262
|
+
]);
|
|
263
|
+
|
|
264
|
+
const state = await engine.deriveState("/unused");
|
|
265
|
+
const meta = engine.getDisplayMetadata(state);
|
|
266
|
+
|
|
267
|
+
assert.equal(meta.engineLabel, "WORKFLOW");
|
|
268
|
+
assert.equal(meta.currentPhase, "running");
|
|
269
|
+
assert.equal(meta.progressSummary, "Step 1/3");
|
|
270
|
+
assert.deepStrictEqual(meta.stepCount, { completed: 1, total: 3 });
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("shows 0/N when no steps complete", async () => {
|
|
274
|
+
const { engine } = setupEngine([
|
|
275
|
+
makeStep({ id: "a" }),
|
|
276
|
+
makeStep({ id: "b" }),
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
const state = await engine.deriveState("/unused");
|
|
280
|
+
const meta = engine.getDisplayMetadata(state);
|
|
281
|
+
|
|
282
|
+
assert.equal(meta.progressSummary, "Step 0/2");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("shows N/N when all steps complete", async () => {
|
|
286
|
+
const { engine } = setupEngine([
|
|
287
|
+
makeStep({ id: "a", status: "complete" }),
|
|
288
|
+
makeStep({ id: "b", status: "complete" }),
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
const state = await engine.deriveState("/unused");
|
|
292
|
+
const meta = engine.getDisplayMetadata(state);
|
|
293
|
+
|
|
294
|
+
assert.equal(meta.progressSummary, "Step 2/2");
|
|
295
|
+
assert.equal(meta.currentPhase, "complete");
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// āāā CustomExecutionPolicy āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
300
|
+
|
|
301
|
+
describe("CustomExecutionPolicy", () => {
|
|
302
|
+
it("verify returns continue", async () => {
|
|
303
|
+
// verify() reads DEFINITION.yaml from runDir to find step's verify policy
|
|
304
|
+
const runDir = makeTmpDir();
|
|
305
|
+
writeFileSync(join(runDir, "DEFINITION.yaml"), stringify({
|
|
306
|
+
version: 1, name: "wf", description: "test",
|
|
307
|
+
steps: [{ id: "step-1", name: "Step 1", prompt: "do it", produces: "step-1/output.md" }],
|
|
308
|
+
}));
|
|
309
|
+
const policy = new CustomExecutionPolicy(runDir);
|
|
310
|
+
const result = await policy.verify("custom-step", "wf/step-1", { basePath: runDir });
|
|
311
|
+
assert.equal(result, "continue");
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("selectModel returns null", async () => {
|
|
315
|
+
const policy = new CustomExecutionPolicy("/tmp/run");
|
|
316
|
+
const result = await policy.selectModel("custom-step", "wf/step-1", { basePath: "/tmp" });
|
|
317
|
+
assert.equal(result, null);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("recover returns retry", async () => {
|
|
321
|
+
const policy = new CustomExecutionPolicy("/tmp/run");
|
|
322
|
+
const result = await policy.recover("custom-step", "wf/step-1", { basePath: "/tmp" });
|
|
323
|
+
assert.deepStrictEqual(result, { outcome: "retry", reason: "Default retry" });
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("closeout returns no artifacts", async () => {
|
|
327
|
+
const policy = new CustomExecutionPolicy("/tmp/run");
|
|
328
|
+
const result = await policy.closeout("custom-step", "wf/step-1", {
|
|
329
|
+
basePath: "/tmp",
|
|
330
|
+
startedAt: Date.now(),
|
|
331
|
+
});
|
|
332
|
+
assert.deepStrictEqual(result, { committed: false, artifacts: [] });
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("prepareWorkspace resolves without error", async () => {
|
|
336
|
+
const policy = new CustomExecutionPolicy("/tmp/run");
|
|
337
|
+
await policy.prepareWorkspace("/tmp", "M001"); // Should not throw
|
|
338
|
+
});
|
|
339
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-custom-engine.test.ts ā Tests that the custom engine path
|
|
3
|
+
* calls updateProgressWidget and that unitLabel handles "custom-step".
|
|
4
|
+
*
|
|
5
|
+
* Uses source-level assertions for the non-exported unitLabel function
|
|
6
|
+
* and the updateProgressWidget call placement. Tests exported helpers
|
|
7
|
+
* (unitVerb, unitPhaseLabel) directly.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it } from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
import { unitVerb, unitPhaseLabel } from "../auto-dashboard.js";
|
|
17
|
+
|
|
18
|
+
// āāā Tests āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
19
|
+
|
|
20
|
+
describe("Dashboard custom-engine: unitLabel and related helpers", () => {
|
|
21
|
+
it('unitVerb("custom-step") returns "executing workflow step"', () => {
|
|
22
|
+
assert.equal(unitVerb("custom-step"), "executing workflow step");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('unitPhaseLabel("custom-step") returns "WORKFLOW"', () => {
|
|
26
|
+
assert.equal(unitPhaseLabel("custom-step"), "WORKFLOW");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('dashboard-overlay.ts contains a case for "custom-step" returning "Workflow Step"', () => {
|
|
30
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
+
const overlayPath = resolve(__filename, "../../dashboard-overlay.ts");
|
|
32
|
+
const source = readFileSync(overlayPath, "utf-8");
|
|
33
|
+
assert.ok(
|
|
34
|
+
source.includes('"custom-step"') && source.includes('"Workflow Step"'),
|
|
35
|
+
'dashboard-overlay.ts should contain case "custom-step": return "Workflow Step"',
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("Dashboard custom-engine: updateProgressWidget in custom engine path", () => {
|
|
41
|
+
it("loop.ts custom engine path includes updateProgressWidget call before runGuards", () => {
|
|
42
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
43
|
+
const loopPath = resolve(__filename, "../../auto/loop.ts");
|
|
44
|
+
const source = readFileSync(loopPath, "utf-8");
|
|
45
|
+
|
|
46
|
+
// Find the custom engine block
|
|
47
|
+
const customEngineStart = source.indexOf('s.activeEngineId !== "dev"');
|
|
48
|
+
assert.ok(customEngineStart > -1, "Should find custom engine path in loop.ts");
|
|
49
|
+
|
|
50
|
+
// The updateProgressWidget call should appear after the custom engine block start
|
|
51
|
+
// and before the runGuards call in that block
|
|
52
|
+
const afterCustomEngine = source.slice(customEngineStart);
|
|
53
|
+
const widgetCallIndex = afterCustomEngine.indexOf(
|
|
54
|
+
"deps.updateProgressWidget(ctx, iterData.unitType, iterData.unitId, iterData.state)",
|
|
55
|
+
);
|
|
56
|
+
const guardsCallIndex = afterCustomEngine.indexOf("runGuards(ic,");
|
|
57
|
+
assert.ok(widgetCallIndex > -1, "updateProgressWidget should be called in custom engine path");
|
|
58
|
+
assert.ok(
|
|
59
|
+
widgetCallIndex < guardsCallIndex,
|
|
60
|
+
"updateProgressWidget should be called before runGuards in custom engine path",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("updateProgressWidget call is placed after iterData is built", () => {
|
|
65
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
66
|
+
const loopPath = resolve(__filename, "../../auto/loop.ts");
|
|
67
|
+
const source = readFileSync(loopPath, "utf-8");
|
|
68
|
+
|
|
69
|
+
const customEngineStart = source.indexOf('s.activeEngineId !== "dev"');
|
|
70
|
+
const afterCustomEngine = source.slice(customEngineStart);
|
|
71
|
+
|
|
72
|
+
// Verify custom engine path has iterData built before the widget call
|
|
73
|
+
const iterDataIndex = afterCustomEngine.indexOf("iterData = {");
|
|
74
|
+
const widgetIndex = afterCustomEngine.indexOf("deps.updateProgressWidget");
|
|
75
|
+
assert.ok(iterDataIndex > -1 && widgetIndex > -1, "Both iterData and widget call should exist");
|
|
76
|
+
assert.ok(
|
|
77
|
+
iterDataIndex < widgetIndex,
|
|
78
|
+
"iterData should be built before updateProgressWidget is called",
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Verify the call uses iterData.state (which holds the derived GSD state)
|
|
82
|
+
assert.ok(
|
|
83
|
+
afterCustomEngine.includes("iterData.state"),
|
|
84
|
+
"Custom engine updateProgressWidget should reference iterData.state",
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -59,6 +59,7 @@ const SAMPLE_DECISIONS: Decision[] = [
|
|
|
59
59
|
choice: 'better-sqlite3',
|
|
60
60
|
rationale: 'Sync API',
|
|
61
61
|
revisable: 'No',
|
|
62
|
+
made_by: 'collaborative',
|
|
62
63
|
superseded_by: null,
|
|
63
64
|
},
|
|
64
65
|
{
|
|
@@ -70,6 +71,7 @@ const SAMPLE_DECISIONS: Decision[] = [
|
|
|
70
71
|
choice: '.gsd/gsd.db',
|
|
71
72
|
rationale: 'Derived state',
|
|
72
73
|
revisable: 'No',
|
|
74
|
+
made_by: 'agent',
|
|
73
75
|
superseded_by: null,
|
|
74
76
|
},
|
|
75
77
|
{
|
|
@@ -81,6 +83,7 @@ const SAMPLE_DECISIONS: Decision[] = [
|
|
|
81
83
|
choice: 'node:sqlite fallback',
|
|
82
84
|
rationale: 'Zero deps',
|
|
83
85
|
revisable: 'Yes',
|
|
86
|
+
made_by: 'human',
|
|
84
87
|
superseded_by: null,
|
|
85
88
|
},
|
|
86
89
|
];
|
|
@@ -166,6 +169,7 @@ console.log('\nāā generateDecisionsMd round-trip āā');
|
|
|
166
169
|
assertEq(rt.choice, orig.choice, `decision ${orig.id} choice round-trips`);
|
|
167
170
|
assertEq(rt.rationale, orig.rationale, `decision ${orig.id} rationale round-trips`);
|
|
168
171
|
assertEq(rt.revisable, orig.revisable, `decision ${orig.id} revisable round-trips`);
|
|
172
|
+
assertEq(rt.made_by, orig.made_by, `decision ${orig.id} made_by round-trips`);
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
175
|
|
|
@@ -177,6 +181,7 @@ console.log('\nāā generateDecisionsMd format āā');
|
|
|
177
181
|
assertTrue(md.includes('<!-- Append-only'), 'contains HTML comment block');
|
|
178
182
|
assertTrue(md.includes('| # | When | Scope'), 'contains table header');
|
|
179
183
|
assertTrue(md.includes('|---|------|-------'), 'contains separator row');
|
|
184
|
+
assertTrue(md.includes('| Made By |'), 'contains Made By column header');
|
|
180
185
|
}
|
|
181
186
|
|
|
182
187
|
console.log('\nāā generateDecisionsMd empty input āā');
|
|
@@ -200,6 +205,7 @@ console.log('\nāā generateDecisionsMd pipe escaping āā');
|
|
|
200
205
|
choice: 'A',
|
|
201
206
|
rationale: 'Better',
|
|
202
207
|
revisable: 'No',
|
|
208
|
+
made_by: 'agent',
|
|
203
209
|
superseded_by: null,
|
|
204
210
|
};
|
|
205
211
|
const md = generateDecisionsMd([withPipe]);
|
|
@@ -291,6 +297,7 @@ console.log('\nāā nextDecisionId āā');
|
|
|
291
297
|
choice: 'test choice',
|
|
292
298
|
rationale: 'test',
|
|
293
299
|
revisable: 'No',
|
|
300
|
+
made_by: 'agent',
|
|
294
301
|
superseded_by: null,
|
|
295
302
|
});
|
|
296
303
|
upsertDecision({
|
|
@@ -301,6 +308,7 @@ console.log('\nāā nextDecisionId āā');
|
|
|
301
308
|
choice: 'test choice',
|
|
302
309
|
rationale: 'test',
|
|
303
310
|
revisable: 'No',
|
|
311
|
+
made_by: 'agent',
|
|
304
312
|
superseded_by: null,
|
|
305
313
|
});
|
|
306
314
|
|
|
@@ -520,6 +528,7 @@ console.log('\nāā Full DB round-trip: decisions āā');
|
|
|
520
528
|
choice: d.choice,
|
|
521
529
|
rationale: d.rationale,
|
|
522
530
|
revisable: d.revisable,
|
|
531
|
+
made_by: d.made_by,
|
|
523
532
|
superseded_by: d.superseded_by,
|
|
524
533
|
});
|
|
525
534
|
}
|
|
@@ -536,6 +545,7 @@ console.log('\nāā Full DB round-trip: decisions āā');
|
|
|
536
545
|
choice: row['choice'] as string,
|
|
537
546
|
rationale: row['rationale'] as string,
|
|
538
547
|
revisable: row['revisable'] as string,
|
|
548
|
+
made_by: (row['made_by'] as string as import('../types.js').DecisionMadeBy) ?? 'agent',
|
|
539
549
|
superseded_by: (row['superseded_by'] as string) ?? null,
|
|
540
550
|
}));
|
|
541
551
|
|