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
|
@@ -569,6 +569,208 @@ async function main(): Promise<void> {
|
|
|
569
569
|
assertTrue(existsSync(join(repo, "landed.ts")), "landed.ts present on main");
|
|
570
570
|
}
|
|
571
571
|
|
|
572
|
+
// ─── Test 14: Stale branch ref — worktree HEAD ahead of branch (#1846) ─
|
|
573
|
+
console.log("\n=== stale branch ref — fast-forward before squash merge (#1846) ===");
|
|
574
|
+
{
|
|
575
|
+
const repo = freshRepo();
|
|
576
|
+
const wtPath = createAutoWorktree(repo, "M140");
|
|
577
|
+
|
|
578
|
+
// Add a first slice normally — this advances both the branch ref and HEAD
|
|
579
|
+
addSliceToMilestone(repo, wtPath, "M140", "S01", "Initial work", [
|
|
580
|
+
{ file: "initial.ts", content: "export const initial = true;\n", message: "add initial" },
|
|
581
|
+
]);
|
|
582
|
+
|
|
583
|
+
// Now simulate the bug: detach HEAD in the worktree, then make commits
|
|
584
|
+
// that advance HEAD but leave the milestone/M140 branch ref behind.
|
|
585
|
+
const branchRefBefore = run("git rev-parse milestone/M140", wtPath);
|
|
586
|
+
run("git checkout --detach HEAD", wtPath);
|
|
587
|
+
|
|
588
|
+
// Add multiple commits on the detached HEAD (simulates agent work)
|
|
589
|
+
writeFileSync(join(wtPath, "feature-a.ts"), "export const featureA = true;\n");
|
|
590
|
+
run("git add .", wtPath);
|
|
591
|
+
run('git commit -m "add feature-a"', wtPath);
|
|
592
|
+
|
|
593
|
+
writeFileSync(join(wtPath, "feature-b.ts"), "export const featureB = true;\n");
|
|
594
|
+
run("git add .", wtPath);
|
|
595
|
+
run('git commit -m "add feature-b"', wtPath);
|
|
596
|
+
|
|
597
|
+
writeFileSync(join(wtPath, "feature-c.ts"), "export const featureC = true;\n");
|
|
598
|
+
run("git add .", wtPath);
|
|
599
|
+
run('git commit -m "add feature-c"', wtPath);
|
|
600
|
+
|
|
601
|
+
// Verify: branch ref is stale, HEAD is ahead
|
|
602
|
+
const branchRefAfter = run("git rev-parse milestone/M140", wtPath);
|
|
603
|
+
const worktreeHead = run("git rev-parse HEAD", wtPath);
|
|
604
|
+
assertEq(branchRefBefore, branchRefAfter, "branch ref unchanged (stale)");
|
|
605
|
+
assertTrue(worktreeHead !== branchRefAfter, "worktree HEAD ahead of branch ref");
|
|
606
|
+
|
|
607
|
+
const roadmap = makeRoadmap("M140", "Stale ref milestone", [
|
|
608
|
+
{ id: "S01", title: "Initial work" },
|
|
609
|
+
]);
|
|
610
|
+
|
|
611
|
+
// The fix should fast-forward the branch ref to worktree HEAD before
|
|
612
|
+
// squash-merging, so ALL commits are captured.
|
|
613
|
+
let threw = false;
|
|
614
|
+
let errMsg = "";
|
|
615
|
+
try {
|
|
616
|
+
const result = mergeMilestoneToMain(repo, "M140", roadmap);
|
|
617
|
+
assertTrue(result.commitMessage.includes("feat(M140)"), "merge commit created");
|
|
618
|
+
} catch (err) {
|
|
619
|
+
threw = true;
|
|
620
|
+
errMsg = err instanceof Error ? err.message : String(err);
|
|
621
|
+
}
|
|
622
|
+
assertTrue(!threw, `should not throw with stale branch ref (got: ${errMsg})`);
|
|
623
|
+
|
|
624
|
+
// ALL files from detached HEAD commits must be on main — not just
|
|
625
|
+
// the ones from the stale branch ref
|
|
626
|
+
assertTrue(existsSync(join(repo, "initial.ts")), "initial.ts on main");
|
|
627
|
+
assertTrue(existsSync(join(repo, "feature-a.ts")), "feature-a.ts on main (#1846)");
|
|
628
|
+
assertTrue(existsSync(join(repo, "feature-b.ts")), "feature-b.ts on main (#1846)");
|
|
629
|
+
assertTrue(existsSync(join(repo, "feature-c.ts")), "feature-c.ts on main (#1846)");
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ─── Test 15: Diverged worktree HEAD — throws instead of losing data (#1846) ─
|
|
633
|
+
console.log("\n=== diverged worktree HEAD — throws on divergence (#1846) ===");
|
|
634
|
+
{
|
|
635
|
+
const repo = freshRepo();
|
|
636
|
+
const wtPath = createAutoWorktree(repo, "M150");
|
|
637
|
+
|
|
638
|
+
addSliceToMilestone(repo, wtPath, "M150", "S01", "Base work", [
|
|
639
|
+
{ file: "base.ts", content: "export const base = true;\n", message: "add base" },
|
|
640
|
+
]);
|
|
641
|
+
|
|
642
|
+
run("git checkout --detach HEAD", wtPath);
|
|
643
|
+
writeFileSync(join(wtPath, "detached-work.ts"), "export const detached = true;\n");
|
|
644
|
+
run("git add .", wtPath);
|
|
645
|
+
run('git commit -m "detached work"', wtPath);
|
|
646
|
+
|
|
647
|
+
run("git checkout milestone/M150", repo);
|
|
648
|
+
writeFileSync(join(repo, "diverged-work.ts"), "export const diverged = true;\n");
|
|
649
|
+
run("git add .", repo);
|
|
650
|
+
run('git commit -m "diverged work on branch"', repo);
|
|
651
|
+
run("git checkout main", repo);
|
|
652
|
+
|
|
653
|
+
process.chdir(wtPath);
|
|
654
|
+
|
|
655
|
+
const roadmap = makeRoadmap("M150", "Diverged milestone", [
|
|
656
|
+
{ id: "S01", title: "Base work" },
|
|
657
|
+
]);
|
|
658
|
+
|
|
659
|
+
let threw = false;
|
|
660
|
+
let errMsg = "";
|
|
661
|
+
try {
|
|
662
|
+
mergeMilestoneToMain(repo, "M150", roadmap);
|
|
663
|
+
} catch (err) {
|
|
664
|
+
threw = true;
|
|
665
|
+
errMsg = err instanceof Error ? err.message : String(err);
|
|
666
|
+
}
|
|
667
|
+
assertTrue(threw, "throws when worktree HEAD diverged from branch ref (#1846)");
|
|
668
|
+
assertTrue(errMsg.includes("diverged"), "error message mentions divergence (#1846)");
|
|
669
|
+
|
|
670
|
+
const branches = run("git branch", repo);
|
|
671
|
+
assertTrue(branches.includes("milestone/M150"), "milestone branch preserved on divergence (#1846)");
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ─── Test 16: #1853 Bug 1 — SQUASH_MSG cleaned up after squash-merge ──
|
|
675
|
+
console.log("\n=== #1853 bug 1: SQUASH_MSG cleaned up after successful squash-merge ===");
|
|
676
|
+
{
|
|
677
|
+
const repo = freshRepo();
|
|
678
|
+
const wtPath = createAutoWorktree(repo, "M160");
|
|
679
|
+
|
|
680
|
+
addSliceToMilestone(repo, wtPath, "M160", "S01", "SQUASH_MSG cleanup test", [
|
|
681
|
+
{ file: "squash-cleanup.ts", content: "export const cleanup = true;\n", message: "add squash-cleanup" },
|
|
682
|
+
]);
|
|
683
|
+
|
|
684
|
+
const roadmap = makeRoadmap("M160", "SQUASH_MSG cleanup", [
|
|
685
|
+
{ id: "S01", title: "SQUASH_MSG cleanup test" },
|
|
686
|
+
]);
|
|
687
|
+
|
|
688
|
+
const squashMsgPath = join(repo, ".git", "SQUASH_MSG");
|
|
689
|
+
writeFileSync(squashMsgPath, "leftover squash message\n");
|
|
690
|
+
assertTrue(existsSync(squashMsgPath), "SQUASH_MSG planted before merge");
|
|
691
|
+
|
|
692
|
+
const result = mergeMilestoneToMain(repo, "M160", roadmap);
|
|
693
|
+
assertTrue(result.commitMessage.includes("feat(M160)"), "merge commit created");
|
|
694
|
+
|
|
695
|
+
assertTrue(
|
|
696
|
+
!existsSync(squashMsgPath),
|
|
697
|
+
"#1853: SQUASH_MSG must not persist after successful squash-merge",
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// ─── Test 17: #1853 Bug 2 — uncommitted worktree code survives teardown ──
|
|
702
|
+
console.log("\n=== #1853 bug 2: uncommitted worktree changes committed before teardown ===");
|
|
703
|
+
{
|
|
704
|
+
const repo = freshRepo();
|
|
705
|
+
const wtPath = createAutoWorktree(repo, "M170");
|
|
706
|
+
|
|
707
|
+
addSliceToMilestone(repo, wtPath, "M170", "S01", "Teardown safety test", [
|
|
708
|
+
{ file: "safe-file.ts", content: "export const safe = true;\n", message: "add safe file" },
|
|
709
|
+
]);
|
|
710
|
+
|
|
711
|
+
writeFileSync(join(wtPath, "uncommitted-agent-code.ts"), "export const lost = true;\n");
|
|
712
|
+
|
|
713
|
+
const roadmap = makeRoadmap("M170", "Teardown safety", [
|
|
714
|
+
{ id: "S01", title: "Teardown safety test" },
|
|
715
|
+
]);
|
|
716
|
+
|
|
717
|
+
const result = mergeMilestoneToMain(repo, "M170", roadmap);
|
|
718
|
+
assertTrue(result.commitMessage.includes("feat(M170)"), "merge commit created");
|
|
719
|
+
|
|
720
|
+
assertTrue(
|
|
721
|
+
existsSync(join(repo, "uncommitted-agent-code.ts")),
|
|
722
|
+
"#1853: uncommitted worktree code must survive teardown",
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// ─── Test 18: #1906 — codeFilesChanged false when only .gsd/ metadata merged ──
|
|
727
|
+
console.log("\n=== #1906: codeFilesChanged=false when only .gsd/ metadata merged ===");
|
|
728
|
+
{
|
|
729
|
+
const repo = freshRepo();
|
|
730
|
+
const wtPath = createAutoWorktree(repo, "M180");
|
|
731
|
+
|
|
732
|
+
// Only add .gsd/ metadata files — no actual code
|
|
733
|
+
mkdirSync(join(wtPath, ".gsd", "milestones", "M180"), { recursive: true });
|
|
734
|
+
writeFileSync(
|
|
735
|
+
join(wtPath, ".gsd", "milestones", "M180", "SUMMARY.md"),
|
|
736
|
+
"# M180 Summary\n\nThis milestone was planned but not implemented.\n",
|
|
737
|
+
);
|
|
738
|
+
run("git add .", wtPath);
|
|
739
|
+
run('git commit -m "chore: add milestone summary"', wtPath);
|
|
740
|
+
|
|
741
|
+
const roadmap = makeRoadmap("M180", "Metadata-only milestone", []);
|
|
742
|
+
|
|
743
|
+
const result = mergeMilestoneToMain(repo, "M180", roadmap);
|
|
744
|
+
assertEq(
|
|
745
|
+
result.codeFilesChanged,
|
|
746
|
+
false,
|
|
747
|
+
"#1906: codeFilesChanged must be false when only .gsd/ files were merged",
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// ─── Test 19: #1906 — codeFilesChanged true when real code is merged ──
|
|
752
|
+
console.log("\n=== #1906: codeFilesChanged=true when real code is merged ===");
|
|
753
|
+
{
|
|
754
|
+
const repo = freshRepo();
|
|
755
|
+
const wtPath = createAutoWorktree(repo, "M190");
|
|
756
|
+
|
|
757
|
+
addSliceToMilestone(repo, wtPath, "M190", "S01", "Real code", [
|
|
758
|
+
{ file: "real-code.ts", content: "export const real = true;\n", message: "add real code" },
|
|
759
|
+
]);
|
|
760
|
+
|
|
761
|
+
const roadmap = makeRoadmap("M190", "Code milestone", [
|
|
762
|
+
{ id: "S01", title: "Real code" },
|
|
763
|
+
]);
|
|
764
|
+
|
|
765
|
+
const result = mergeMilestoneToMain(repo, "M190", roadmap);
|
|
766
|
+
assertEq(
|
|
767
|
+
result.codeFilesChanged,
|
|
768
|
+
true,
|
|
769
|
+
"#1906: codeFilesChanged must be true when real code files were merged",
|
|
770
|
+
);
|
|
771
|
+
assertTrue(existsSync(join(repo, "real-code.ts")), "real-code.ts merged to main");
|
|
772
|
+
}
|
|
773
|
+
|
|
572
774
|
} finally {
|
|
573
775
|
process.chdir(savedCwd);
|
|
574
776
|
for (const d of tempDirs) {
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled workflow definition validation tests.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that every example YAML in src/resources/skills/create-workflow/templates/
|
|
5
|
+
* passes validateDefinition() from definition-loader.ts with { valid: true, errors: [] }.
|
|
6
|
+
*
|
|
7
|
+
* Also validates scaffold template and structural properties of each example
|
|
8
|
+
* (step counts, feature usage) to guard against accidental regressions.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { join, dirname } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { parse } from "yaml";
|
|
17
|
+
|
|
18
|
+
import { validateDefinition } from "../definition-loader.ts";
|
|
19
|
+
|
|
20
|
+
// ─── Path resolution ─────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
// Navigate from tests/ → extensions/gsd/ → extensions/ → resources/ → skills/create-workflow/templates/
|
|
24
|
+
const templatesDir = join(
|
|
25
|
+
__dirname,
|
|
26
|
+
"..",
|
|
27
|
+
"..",
|
|
28
|
+
"..",
|
|
29
|
+
"skills",
|
|
30
|
+
"create-workflow",
|
|
31
|
+
"templates",
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
function loadYaml(filename: string): unknown {
|
|
35
|
+
const raw = readFileSync(join(templatesDir, filename), "utf-8");
|
|
36
|
+
return parse(raw);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Scaffold template ──────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
test("scaffold template (workflow-definition.yaml) passes validation", () => {
|
|
42
|
+
const parsed = loadYaml("workflow-definition.yaml");
|
|
43
|
+
const result = validateDefinition(parsed);
|
|
44
|
+
assert.equal(result.valid, true, `Scaffold invalid: ${result.errors.join("; ")}`);
|
|
45
|
+
assert.equal(result.errors.length, 0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// ─── blog-post-pipeline.yaml ────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
test("blog-post-pipeline.yaml passes validation", () => {
|
|
51
|
+
const parsed = loadYaml("blog-post-pipeline.yaml");
|
|
52
|
+
const result = validateDefinition(parsed);
|
|
53
|
+
assert.equal(result.valid, true, `Invalid: ${result.errors.join("; ")}`);
|
|
54
|
+
assert.equal(result.errors.length, 0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("blog-post-pipeline.yaml: 3 steps, context_from, params, content-heuristic", () => {
|
|
58
|
+
const parsed = loadYaml("blog-post-pipeline.yaml") as Record<string, unknown>;
|
|
59
|
+
const steps = parsed.steps as Array<Record<string, unknown>>;
|
|
60
|
+
|
|
61
|
+
// 3 steps
|
|
62
|
+
assert.equal(steps.length, 3, "Expected 3 steps");
|
|
63
|
+
|
|
64
|
+
// params defined
|
|
65
|
+
assert.ok(parsed.params, "Expected params to be defined");
|
|
66
|
+
const params = parsed.params as Record<string, string>;
|
|
67
|
+
assert.ok("topic" in params, "Expected 'topic' param");
|
|
68
|
+
assert.ok("audience" in params, "Expected 'audience' param");
|
|
69
|
+
|
|
70
|
+
// At least one step uses context_from
|
|
71
|
+
const hasContextFrom = steps.some(
|
|
72
|
+
(s) => Array.isArray(s.context_from) && s.context_from.length > 0,
|
|
73
|
+
);
|
|
74
|
+
assert.ok(hasContextFrom, "Expected at least one step with context_from");
|
|
75
|
+
|
|
76
|
+
// All steps use content-heuristic verify
|
|
77
|
+
for (const step of steps) {
|
|
78
|
+
const verify = step.verify as Record<string, unknown> | undefined;
|
|
79
|
+
assert.ok(verify, `Step "${step.id}" missing verify`);
|
|
80
|
+
assert.equal(verify.policy, "content-heuristic", `Step "${step.id}" should use content-heuristic`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ─── code-audit.yaml ────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
test("code-audit.yaml passes validation", () => {
|
|
87
|
+
const parsed = loadYaml("code-audit.yaml");
|
|
88
|
+
const result = validateDefinition(parsed);
|
|
89
|
+
assert.equal(result.valid, true, `Invalid: ${result.errors.join("; ")}`);
|
|
90
|
+
assert.equal(result.errors.length, 0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("code-audit.yaml: iterate with capture group and shell-command verify", () => {
|
|
94
|
+
const parsed = loadYaml("code-audit.yaml") as Record<string, unknown>;
|
|
95
|
+
const steps = parsed.steps as Array<Record<string, unknown>>;
|
|
96
|
+
|
|
97
|
+
// Find step with iterate
|
|
98
|
+
const iterateStep = steps.find((s) => s.iterate != null);
|
|
99
|
+
assert.ok(iterateStep, "Expected a step with iterate config");
|
|
100
|
+
|
|
101
|
+
const iterate = iterateStep.iterate as Record<string, unknown>;
|
|
102
|
+
assert.equal(typeof iterate.source, "string", "iterate.source must be a string");
|
|
103
|
+
assert.equal(typeof iterate.pattern, "string", "iterate.pattern must be a string");
|
|
104
|
+
|
|
105
|
+
// Pattern has a capture group
|
|
106
|
+
const pattern = iterate.pattern as string;
|
|
107
|
+
assert.ok(/\((?!\?)/.test(pattern), "iterate.pattern must contain a capture group");
|
|
108
|
+
|
|
109
|
+
// Pattern is valid regex
|
|
110
|
+
assert.doesNotThrow(() => new RegExp(pattern), "iterate.pattern must be valid regex");
|
|
111
|
+
|
|
112
|
+
// Has shell-command verify
|
|
113
|
+
const verify = iterateStep.verify as Record<string, unknown>;
|
|
114
|
+
assert.equal(verify.policy, "shell-command");
|
|
115
|
+
assert.equal(typeof verify.command, "string");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ─── release-checklist.yaml ─────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
test("release-checklist.yaml passes validation", () => {
|
|
121
|
+
const parsed = loadYaml("release-checklist.yaml");
|
|
122
|
+
const result = validateDefinition(parsed);
|
|
123
|
+
assert.equal(result.valid, true, `Invalid: ${result.errors.join("; ")}`);
|
|
124
|
+
assert.equal(result.errors.length, 0);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("release-checklist.yaml: diamond dependencies and human-review", () => {
|
|
128
|
+
const parsed = loadYaml("release-checklist.yaml") as Record<string, unknown>;
|
|
129
|
+
const steps = parsed.steps as Array<Record<string, unknown>>;
|
|
130
|
+
|
|
131
|
+
// 4 steps
|
|
132
|
+
assert.equal(steps.length, 4, "Expected 4 steps");
|
|
133
|
+
|
|
134
|
+
// Diamond pattern: two steps depend on the same parent
|
|
135
|
+
const changelog = steps.find((s) => s.id === "changelog");
|
|
136
|
+
const versionBump = steps.find((s) => s.id === "version-bump");
|
|
137
|
+
const testSuite = steps.find((s) => s.id === "test-suite");
|
|
138
|
+
const publish = steps.find((s) => s.id === "publish");
|
|
139
|
+
|
|
140
|
+
assert.ok(changelog, "Expected 'changelog' step");
|
|
141
|
+
assert.ok(versionBump, "Expected 'version-bump' step");
|
|
142
|
+
assert.ok(testSuite, "Expected 'test-suite' step");
|
|
143
|
+
assert.ok(publish, "Expected 'publish' step");
|
|
144
|
+
|
|
145
|
+
// Both version-bump and test-suite depend on changelog
|
|
146
|
+
const vbReqs = versionBump.requires as string[];
|
|
147
|
+
const tsReqs = testSuite.requires as string[];
|
|
148
|
+
assert.ok(vbReqs.includes("changelog"), "version-bump should require changelog");
|
|
149
|
+
assert.ok(tsReqs.includes("changelog"), "test-suite should require changelog");
|
|
150
|
+
|
|
151
|
+
// publish depends on both (diamond join)
|
|
152
|
+
const pubReqs = publish.requires as string[];
|
|
153
|
+
assert.ok(pubReqs.includes("version-bump"), "publish should require version-bump");
|
|
154
|
+
assert.ok(pubReqs.includes("test-suite"), "publish should require test-suite");
|
|
155
|
+
|
|
156
|
+
// publish uses human-review
|
|
157
|
+
const verify = publish.verify as Record<string, unknown>;
|
|
158
|
+
assert.equal(verify.policy, "human-review");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// ─── Cross-cutting: no path traversal in produces ───────────────────────
|
|
162
|
+
|
|
163
|
+
test("no produces path contains '..'", () => {
|
|
164
|
+
const files = [
|
|
165
|
+
"blog-post-pipeline.yaml",
|
|
166
|
+
"code-audit.yaml",
|
|
167
|
+
"release-checklist.yaml",
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
for (const file of files) {
|
|
171
|
+
const parsed = loadYaml(file) as Record<string, unknown>;
|
|
172
|
+
const steps = parsed.steps as Array<Record<string, unknown>>;
|
|
173
|
+
for (const step of steps) {
|
|
174
|
+
const produces = (step.produces as string[]) ?? [];
|
|
175
|
+
for (const p of produces) {
|
|
176
|
+
assert.ok(!p.includes(".."), `${file} step "${step.id}" produces path contains '..': ${p}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
@@ -119,12 +119,23 @@ test("captures: loadPendingCaptures filters resolved entries", () => {
|
|
|
119
119
|
const id1 = appendCapture(tmp, "pending one");
|
|
120
120
|
appendCapture(tmp, "pending two");
|
|
121
121
|
|
|
122
|
-
// Resolve the first one
|
|
123
122
|
markCaptureResolved(tmp, id1, "note", "acknowledged", "just a note");
|
|
124
123
|
|
|
125
124
|
const pending = loadPendingCaptures(tmp);
|
|
126
125
|
assert.strictEqual(pending.length, 1, "should have 1 pending");
|
|
127
126
|
assert.strictEqual(pending[0].text, "pending two");
|
|
127
|
+
} finally {
|
|
128
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("captures: loadAllCaptures preserves resolved entries", () => {
|
|
133
|
+
const tmp = makeTempDir("cap-all-resolved");
|
|
134
|
+
try {
|
|
135
|
+
const id1 = appendCapture(tmp, "pending one");
|
|
136
|
+
appendCapture(tmp, "pending two");
|
|
137
|
+
|
|
138
|
+
markCaptureResolved(tmp, id1, "note", "acknowledged", "just a note");
|
|
128
139
|
|
|
129
140
|
const all = loadAllCaptures(tmp);
|
|
130
141
|
assert.strictEqual(all.length, 2, "all should still have 2");
|