gsd-pi 2.41.0-dev.cac69f9 → 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 +23 -0
- package/dist/cli.js +18 -3
- package/dist/loader.js +3 -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 +80 -0
- package/dist/resources/extensions/gsd/auto/phases.js +3 -5
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -16
- package/dist/resources/extensions/gsd/auto-start.js +8 -11
- package/dist/resources/extensions/gsd/auto.js +28 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -5
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +32 -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/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/definition-loader.js +352 -0
- package/dist/resources/extensions/gsd/detection.js +19 -0
- 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/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/forensics.js +84 -0
- package/dist/resources/extensions/gsd/git-constants.js +1 -0
- package/dist/resources/extensions/gsd/git-service.js +1 -1
- package/dist/resources/extensions/gsd/graph.js +225 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +1 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences.js +59 -8
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/repo-identity.js +46 -5
- package/dist/resources/extensions/gsd/run-manager.js +134 -0
- package/dist/resources/extensions/gsd/service-tier.js +13 -4
- package/dist/resources/extensions/gsd/session-lock.js +2 -2
- package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +2 -2
- 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/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 +15 -15
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/git/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 +15 -15
- package/dist/web/standalone/.next/server/chunks/229.js +2 -2
- 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-mode.d.ts +2 -0
- package/dist/web-mode.js +40 -4
- package/package.json +1 -1
- 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/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/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +30 -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/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/interactive-mode.ts +31 -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 +0 -1
- package/src/resources/extensions/gsd/auto/loop.ts +91 -0
- package/src/resources/extensions/gsd/auto/phases.ts +3 -5
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -18
- package/src/resources/extensions/gsd/auto-start.ts +7 -10
- package/src/resources/extensions/gsd/auto.ts +31 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -5
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +32 -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/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/definition-loader.ts +462 -0
- package/src/resources/extensions/gsd/detection.ts +19 -0
- 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/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/forensics.ts +92 -0
- package/src/resources/extensions/gsd/git-constants.ts +1 -0
- package/src/resources/extensions/gsd/git-service.ts +0 -1
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/graph.ts +312 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +1 -0
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences.ts +62 -6
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/repo-identity.ts +48 -5
- package/src/resources/extensions/gsd/run-manager.ts +180 -0
- package/src/resources/extensions/gsd/service-tier.ts +17 -4
- package/src/resources/extensions/gsd/session-lock.ts +2 -2
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
- package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
- 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/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/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/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/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/iterate-engine-integration.test.ts +429 -0
- package/src/resources/extensions/gsd/tests/journal.test.ts +82 -127
- package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
- package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +56 -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/verification-gate.test.ts +156 -263
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -78
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +81 -74
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +1 -2
- package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +2 -3
- 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/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/{EnGUNqHeGbE0tuuUkTJVA → qw8qDHXOTLUXBq1vEknSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EnGUNqHeGbE0tuuUkTJVA → qw8qDHXOTLUXBq1vEknSz}/_ssgManifest.js +0 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* rather than hard-coding package.json / src/ only.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import test from "node:test";
|
|
10
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
12
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
@@ -67,112 +67,69 @@ test("PROJECT_FILES is exported and contains expected multi-ecosystem entries",
|
|
|
67
67
|
assert.ok(PROJECT_FILES.includes("Package.swift"), "includes Swift marker");
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
describe("health check with git repo", () => {
|
|
71
|
+
let dir: string;
|
|
72
|
+
beforeEach(() => { dir = createGitRepo(); });
|
|
73
|
+
afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
|
|
74
|
+
|
|
75
|
+
test("health check passes for Rust project (Cargo.toml, no package.json)", () => {
|
|
73
76
|
writeFileSync(join(dir, "Cargo.toml"), "[package]\nname = \"test\"\n");
|
|
74
77
|
mkdirSync(join(dir, "crates"), { recursive: true });
|
|
75
78
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Rust project should pass health check");
|
|
76
|
-
}
|
|
77
|
-
rmSync(dir, { recursive: true, force: true });
|
|
78
|
-
}
|
|
79
|
-
});
|
|
79
|
+
});
|
|
80
80
|
|
|
81
|
-
test("health check passes for Go project (go.mod, no package.json)", () => {
|
|
82
|
-
const dir = createGitRepo();
|
|
83
|
-
try {
|
|
81
|
+
test("health check passes for Go project (go.mod, no package.json)", () => {
|
|
84
82
|
writeFileSync(join(dir, "go.mod"), "module example.com/test\n\ngo 1.21\n");
|
|
85
83
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Go project should pass health check");
|
|
86
|
-
}
|
|
87
|
-
rmSync(dir, { recursive: true, force: true });
|
|
88
|
-
}
|
|
89
|
-
});
|
|
84
|
+
});
|
|
90
85
|
|
|
91
|
-
test("health check passes for Python project (pyproject.toml, no package.json)", () => {
|
|
92
|
-
const dir = createGitRepo();
|
|
93
|
-
try {
|
|
86
|
+
test("health check passes for Python project (pyproject.toml, no package.json)", () => {
|
|
94
87
|
writeFileSync(join(dir, "pyproject.toml"), "[project]\nname = \"test\"\n");
|
|
95
88
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Python project should pass health check");
|
|
96
|
-
}
|
|
97
|
-
rmSync(dir, { recursive: true, force: true });
|
|
98
|
-
}
|
|
99
|
-
});
|
|
89
|
+
});
|
|
100
90
|
|
|
101
|
-
test("health check passes for Java project (pom.xml, no package.json)", () => {
|
|
102
|
-
const dir = createGitRepo();
|
|
103
|
-
try {
|
|
91
|
+
test("health check passes for Java project (pom.xml, no package.json)", () => {
|
|
104
92
|
writeFileSync(join(dir, "pom.xml"), "<project></project>\n");
|
|
105
93
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Java project should pass health check");
|
|
106
|
-
}
|
|
107
|
-
rmSync(dir, { recursive: true, force: true });
|
|
108
|
-
}
|
|
109
|
-
});
|
|
94
|
+
});
|
|
110
95
|
|
|
111
|
-
test("health check passes for Swift project (Package.swift, no package.json)", () => {
|
|
112
|
-
const dir = createGitRepo();
|
|
113
|
-
try {
|
|
96
|
+
test("health check passes for Swift project (Package.swift, no package.json)", () => {
|
|
114
97
|
writeFileSync(join(dir, "Package.swift"), "// swift-tools-version:5.7\n");
|
|
115
98
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Swift project should pass health check");
|
|
116
|
-
}
|
|
117
|
-
rmSync(dir, { recursive: true, force: true });
|
|
118
|
-
}
|
|
119
|
-
});
|
|
99
|
+
});
|
|
120
100
|
|
|
121
|
-
test("health check passes for C/C++ project (CMakeLists.txt, no package.json)", () => {
|
|
122
|
-
const dir = createGitRepo();
|
|
123
|
-
try {
|
|
101
|
+
test("health check passes for C/C++ project (CMakeLists.txt, no package.json)", () => {
|
|
124
102
|
writeFileSync(join(dir, "CMakeLists.txt"), "cmake_minimum_required(VERSION 3.20)\n");
|
|
125
103
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "C/C++ project should pass health check");
|
|
126
|
-
}
|
|
127
|
-
rmSync(dir, { recursive: true, force: true });
|
|
128
|
-
}
|
|
129
|
-
});
|
|
104
|
+
});
|
|
130
105
|
|
|
131
|
-
test("health check passes for Elixir project (mix.exs, no package.json)", () => {
|
|
132
|
-
const dir = createGitRepo();
|
|
133
|
-
try {
|
|
106
|
+
test("health check passes for Elixir project (mix.exs, no package.json)", () => {
|
|
134
107
|
writeFileSync(join(dir, "mix.exs"), "defmodule Test.MixProject do\nend\n");
|
|
135
108
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "Elixir project should pass health check");
|
|
136
|
-
}
|
|
137
|
-
rmSync(dir, { recursive: true, force: true });
|
|
138
|
-
}
|
|
139
|
-
});
|
|
109
|
+
});
|
|
140
110
|
|
|
141
|
-
test("health check passes for JS project (package.json, backward compat)", () => {
|
|
142
|
-
const dir = createGitRepo();
|
|
143
|
-
try {
|
|
111
|
+
test("health check passes for JS project (package.json, backward compat)", () => {
|
|
144
112
|
writeFileSync(join(dir, "package.json"), '{"name":"test"}\n');
|
|
145
113
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "JS project should pass health check");
|
|
146
|
-
}
|
|
147
|
-
rmSync(dir, { recursive: true, force: true });
|
|
148
|
-
}
|
|
149
|
-
});
|
|
114
|
+
});
|
|
150
115
|
|
|
151
|
-
test("health check passes for src/-only project (backward compat)", () => {
|
|
152
|
-
const dir = createGitRepo();
|
|
153
|
-
try {
|
|
116
|
+
test("health check passes for src/-only project (backward compat)", () => {
|
|
154
117
|
mkdirSync(join(dir, "src"), { recursive: true });
|
|
155
118
|
assert.ok(wouldPassHealthCheck(dir, existsSync), "src/-only project should pass health check");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("health check fails for empty git repo with no project files", () => {
|
|
122
|
+
assert.ok(!wouldPassHealthCheck(dir, existsSync), "empty git repo should fail health check");
|
|
123
|
+
});
|
|
159
124
|
});
|
|
160
125
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
126
|
+
describe("health check without git repo", () => {
|
|
127
|
+
let dir: string;
|
|
128
|
+
beforeEach(() => { dir = mkdtempSync(join(tmpdir(), "wt-dispatch-test-nogit-")); });
|
|
129
|
+
afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
|
|
130
|
+
|
|
131
|
+
test("health check fails for directory with no .git", () => {
|
|
164
132
|
writeFileSync(join(dir, "Cargo.toml"), "[package]\nname = \"test\"\n");
|
|
165
133
|
assert.ok(!wouldPassHealthCheck(dir, existsSync), "no-git directory should fail health check");
|
|
166
|
-
}
|
|
167
|
-
rmSync(dir, { recursive: true, force: true });
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("health check fails for empty git repo with no project files", () => {
|
|
172
|
-
const dir = createGitRepo();
|
|
173
|
-
try {
|
|
174
|
-
assert.ok(!wouldPassHealthCheck(dir, existsSync), "empty git repo should fail health check");
|
|
175
|
-
} finally {
|
|
176
|
-
rmSync(dir, { recursive: true, force: true });
|
|
177
|
-
}
|
|
134
|
+
});
|
|
178
135
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import test from "node:test";
|
|
1
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -73,9 +73,12 @@ test("worktreeBranchName formats branch name", () => {
|
|
|
73
73
|
|
|
74
74
|
// ─── createWorktree ───────────────────────────────────────────────────────────
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
describe("createWorktree", () => {
|
|
77
|
+
let base: string;
|
|
78
|
+
beforeEach(() => { base = makeBaseRepo(); });
|
|
79
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
80
|
+
|
|
81
|
+
test("creates worktree with correct metadata", () => {
|
|
79
82
|
const info = createWorktree(base, "feature-x");
|
|
80
83
|
assert.strictEqual(info.name, "feature-x", "name should match");
|
|
81
84
|
assert.strictEqual(info.branch, "worktree/feature-x", "branch should be prefixed");
|
|
@@ -88,80 +91,82 @@ test("createWorktree creates worktree with correct metadata", () => {
|
|
|
88
91
|
);
|
|
89
92
|
const branches = run("git branch", base);
|
|
90
93
|
assert.ok(branches.includes("worktree/feature-x"), "branch should be created in base repo");
|
|
91
|
-
}
|
|
92
|
-
rmSync(base, { recursive: true, force: true });
|
|
93
|
-
}
|
|
94
|
-
});
|
|
94
|
+
});
|
|
95
95
|
|
|
96
|
-
test("
|
|
97
|
-
const { base } = makeRepoWithWorktree("feature-x");
|
|
98
|
-
try {
|
|
96
|
+
test("rejects invalid name", () => {
|
|
99
97
|
assert.throws(
|
|
100
|
-
() => createWorktree(base, "
|
|
98
|
+
() => createWorktree(base, "bad name!"),
|
|
101
99
|
(err: Error) => {
|
|
102
100
|
assert.ok(
|
|
103
|
-
err.message.includes("
|
|
104
|
-
`expected "
|
|
101
|
+
err.message.includes("Invalid worktree name"),
|
|
102
|
+
`expected "Invalid worktree name" in error, got: ${err.message}`,
|
|
105
103
|
);
|
|
106
104
|
return true;
|
|
107
105
|
},
|
|
108
|
-
"should throw on
|
|
106
|
+
"should throw on invalid worktree name",
|
|
109
107
|
);
|
|
110
|
-
}
|
|
111
|
-
rmSync(base, { recursive: true, force: true });
|
|
112
|
-
}
|
|
108
|
+
});
|
|
113
109
|
});
|
|
114
110
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
describe("createWorktree — duplicate rejection", () => {
|
|
112
|
+
let base: string;
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
const repo = makeRepoWithWorktree("feature-x");
|
|
115
|
+
base = repo.base;
|
|
116
|
+
});
|
|
117
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
118
|
+
|
|
119
|
+
test("rejects duplicate name", () => {
|
|
118
120
|
assert.throws(
|
|
119
|
-
() => createWorktree(base, "
|
|
121
|
+
() => createWorktree(base, "feature-x"),
|
|
120
122
|
(err: Error) => {
|
|
121
123
|
assert.ok(
|
|
122
|
-
err.message.includes("
|
|
123
|
-
`expected "
|
|
124
|
+
err.message.includes("already exists"),
|
|
125
|
+
`expected "already exists" in error, got: ${err.message}`,
|
|
124
126
|
);
|
|
125
127
|
return true;
|
|
126
128
|
},
|
|
127
|
-
"should throw on
|
|
129
|
+
"should throw on duplicate worktree name",
|
|
128
130
|
);
|
|
129
|
-
}
|
|
130
|
-
rmSync(base, { recursive: true, force: true });
|
|
131
|
-
}
|
|
131
|
+
});
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
// ─── listWorktrees ────────────────────────────────────────────────────────────
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
describe("listWorktrees", () => {
|
|
137
|
+
let base: string;
|
|
138
|
+
beforeEach(() => {
|
|
139
|
+
const repo = makeRepoWithWorktree("feature-x");
|
|
140
|
+
base = repo.base;
|
|
141
|
+
});
|
|
142
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
143
|
+
|
|
144
|
+
test("returns active worktrees", () => {
|
|
139
145
|
const list = listWorktrees(base);
|
|
140
146
|
assert.strictEqual(list.length, 1, "should list exactly one worktree");
|
|
141
147
|
assert.strictEqual(list[0]!.name, "feature-x", "name should match");
|
|
142
148
|
assert.strictEqual(list[0]!.branch, "worktree/feature-x", "branch should match");
|
|
143
149
|
assert.ok(list[0]!.exists, "exists flag should be true");
|
|
144
|
-
}
|
|
145
|
-
rmSync(base, { recursive: true, force: true });
|
|
146
|
-
}
|
|
147
|
-
});
|
|
150
|
+
});
|
|
148
151
|
|
|
149
|
-
test("
|
|
150
|
-
const { base } = makeRepoWithWorktree("feature-x");
|
|
151
|
-
try {
|
|
152
|
+
test("returns empty after removal", () => {
|
|
152
153
|
removeWorktree(base, "feature-x");
|
|
153
154
|
const list = listWorktrees(base);
|
|
154
155
|
assert.strictEqual(list.length, 0, "should have no worktrees after removal");
|
|
155
|
-
}
|
|
156
|
-
rmSync(base, { recursive: true, force: true });
|
|
157
|
-
}
|
|
156
|
+
});
|
|
158
157
|
});
|
|
159
158
|
|
|
160
159
|
// ─── diffWorktreeGSD ─────────────────────────────────────────────────────────
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
describe("diffWorktreeGSD and getWorktreeGSDDiff", () => {
|
|
162
|
+
let base: string;
|
|
163
|
+
beforeEach(() => {
|
|
164
|
+
const repo = makeRepoWithChanges("feature-x");
|
|
165
|
+
base = repo.base;
|
|
166
|
+
});
|
|
167
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
168
|
+
|
|
169
|
+
test("detects added and modified GSD files", () => {
|
|
165
170
|
const diff = diffWorktreeGSD(base, "feature-x");
|
|
166
171
|
assert.ok(diff.added.length > 0, "should have added files");
|
|
167
172
|
assert.ok(
|
|
@@ -174,58 +179,60 @@ test("diffWorktreeGSD detects added and modified GSD files", () => {
|
|
|
174
179
|
"M001 roadmap should be in modified files",
|
|
175
180
|
);
|
|
176
181
|
assert.strictEqual(diff.removed.length, 0, "should have no removed files");
|
|
177
|
-
}
|
|
178
|
-
rmSync(base, { recursive: true, force: true });
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// ─── getWorktreeGSDDiff ───────────────────────────────────────────────────────
|
|
182
|
+
});
|
|
183
183
|
|
|
184
|
-
test("
|
|
185
|
-
const { base } = makeRepoWithChanges("feature-x");
|
|
186
|
-
try {
|
|
184
|
+
test("returns patch content", () => {
|
|
187
185
|
const fullDiff = getWorktreeGSDDiff(base, "feature-x");
|
|
188
186
|
assert.ok(fullDiff.includes("M002"), "diff should mention M002");
|
|
189
187
|
assert.ok(fullDiff.includes("updated"), "diff should mention the update");
|
|
190
|
-
}
|
|
191
|
-
rmSync(base, { recursive: true, force: true });
|
|
192
|
-
}
|
|
188
|
+
});
|
|
193
189
|
});
|
|
194
190
|
|
|
195
191
|
// ─── getWorktreeLog ───────────────────────────────────────────────────────────
|
|
196
192
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
describe("getWorktreeLog", () => {
|
|
194
|
+
let base: string;
|
|
195
|
+
beforeEach(() => {
|
|
196
|
+
const repo = makeRepoWithChanges("feature-x");
|
|
197
|
+
base = repo.base;
|
|
198
|
+
});
|
|
199
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
200
|
+
|
|
201
|
+
test("shows commits", () => {
|
|
200
202
|
const log = getWorktreeLog(base, "feature-x");
|
|
201
203
|
assert.ok(log.includes("add M002"), "log should include the commit message");
|
|
202
|
-
}
|
|
203
|
-
rmSync(base, { recursive: true, force: true });
|
|
204
|
-
}
|
|
204
|
+
});
|
|
205
205
|
});
|
|
206
206
|
|
|
207
207
|
// ─── removeWorktree ───────────────────────────────────────────────────────────
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
describe("removeWorktree", () => {
|
|
210
|
+
let base: string;
|
|
211
|
+
let wtPath: string;
|
|
212
|
+
beforeEach(() => {
|
|
213
|
+
const repo = makeRepoWithWorktree("feature-x");
|
|
214
|
+
base = repo.base;
|
|
215
|
+
wtPath = repo.wtPath;
|
|
216
|
+
});
|
|
217
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
218
|
+
|
|
219
|
+
test("removes directory and branch", () => {
|
|
212
220
|
removeWorktree(base, "feature-x", { deleteBranch: true });
|
|
213
221
|
assert.ok(!existsSync(wtPath), "worktree directory should be gone");
|
|
214
222
|
const branches = run("git branch", base);
|
|
215
223
|
assert.ok(!branches.includes("worktree/feature-x"), "branch should be deleted");
|
|
216
|
-
}
|
|
217
|
-
rmSync(base, { recursive: true, force: true });
|
|
218
|
-
}
|
|
224
|
+
});
|
|
219
225
|
});
|
|
220
226
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
227
|
+
describe("removeWorktree — missing worktree", () => {
|
|
228
|
+
let base: string;
|
|
229
|
+
beforeEach(() => { base = makeBaseRepo(); });
|
|
230
|
+
afterEach(() => { rmSync(base, { recursive: true, force: true }); });
|
|
231
|
+
|
|
232
|
+
test("on missing worktree does not throw", () => {
|
|
224
233
|
assert.doesNotThrow(
|
|
225
234
|
() => removeWorktree(base, "nonexistent"),
|
|
226
235
|
"should not throw when worktree does not exist",
|
|
227
236
|
);
|
|
228
|
-
}
|
|
229
|
-
rmSync(base, { recursive: true, force: true });
|
|
230
|
-
}
|
|
237
|
+
});
|
|
231
238
|
});
|
|
@@ -139,11 +139,10 @@ function makeDeps(
|
|
|
139
139
|
captureIntegrationBranch: (
|
|
140
140
|
basePath: string,
|
|
141
141
|
mid: string | undefined,
|
|
142
|
-
opts?: { commitDocs?: boolean },
|
|
143
142
|
) => {
|
|
144
143
|
calls.push({
|
|
145
144
|
fn: "captureIntegrationBranch",
|
|
146
|
-
args: [basePath, mid
|
|
145
|
+
args: [basePath, mid],
|
|
147
146
|
});
|
|
148
147
|
},
|
|
149
148
|
...overrides,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workflow-engine.ts — WorkflowEngine interface.
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract every engine implementation must satisfy.
|
|
5
|
+
* Imports only from the leaf-node engine-types.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
EngineState,
|
|
10
|
+
EngineDispatchAction,
|
|
11
|
+
CompletedStep,
|
|
12
|
+
ReconcileResult,
|
|
13
|
+
DisplayMetadata,
|
|
14
|
+
} from "./engine-types.js";
|
|
15
|
+
|
|
16
|
+
/** A pluggable workflow engine that drives the auto-loop. */
|
|
17
|
+
export interface WorkflowEngine {
|
|
18
|
+
/** Unique identifier for this engine (e.g. "dev", "custom"). */
|
|
19
|
+
readonly engineId: string;
|
|
20
|
+
|
|
21
|
+
/** Derive the current engine state from the project on disk. */
|
|
22
|
+
deriveState(basePath: string): Promise<EngineState>;
|
|
23
|
+
|
|
24
|
+
/** Decide what the loop should do next given current state. */
|
|
25
|
+
resolveDispatch(
|
|
26
|
+
state: EngineState,
|
|
27
|
+
context: { basePath: string },
|
|
28
|
+
): Promise<EngineDispatchAction>;
|
|
29
|
+
|
|
30
|
+
/** Reconcile state after a step has been executed. */
|
|
31
|
+
reconcile(
|
|
32
|
+
state: EngineState,
|
|
33
|
+
completedStep: CompletedStep,
|
|
34
|
+
): Promise<ReconcileResult>;
|
|
35
|
+
|
|
36
|
+
/** Return UI-facing metadata for progress display. */
|
|
37
|
+
getDisplayMetadata(state: EngineState): DisplayMetadata;
|
|
38
|
+
}
|
|
@@ -63,7 +63,6 @@ export interface WorktreeResolverDeps {
|
|
|
63
63
|
captureIntegrationBranch: (
|
|
64
64
|
basePath: string,
|
|
65
65
|
mid: string,
|
|
66
|
-
opts?: { commitDocs?: boolean },
|
|
67
66
|
) => void;
|
|
68
67
|
}
|
|
69
68
|
|
|
@@ -410,10 +409,10 @@ export class WorktreeResolver {
|
|
|
410
409
|
});
|
|
411
410
|
// Surface a clear, actionable error. The worktree and milestone branch are
|
|
412
411
|
// intentionally preserved — nothing has been deleted. The user can retry
|
|
413
|
-
// /complete-milestone or merge manually once the underlying issue is fixed
|
|
412
|
+
// /gsd dispatch complete-milestone or merge manually once the underlying issue is fixed
|
|
414
413
|
// (e.g. checkout to wrong branch, unresolved conflicts). (#1668)
|
|
415
414
|
ctx.notify(
|
|
416
|
-
`Milestone merge failed: ${msg}. Your worktree and milestone branch are preserved — retry /complete-milestone or merge manually.`,
|
|
415
|
+
`Milestone merge failed: ${msg}. Your worktree and milestone branch are preserved — retry /gsd dispatch complete-milestone or merge manually.`,
|
|
417
416
|
"warning",
|
|
418
417
|
);
|
|
419
418
|
|
|
@@ -57,13 +57,13 @@ export function setActiveMilestoneId(basePath: string, milestoneId: string | nul
|
|
|
57
57
|
* record when the user starts from a different branch (#300). Always a no-op
|
|
58
58
|
* if on a GSD slice branch.
|
|
59
59
|
*/
|
|
60
|
-
export function captureIntegrationBranch(basePath: string, milestoneId: string
|
|
60
|
+
export function captureIntegrationBranch(basePath: string, milestoneId: string): void {
|
|
61
61
|
// In a worktree, the base branch is implicit (worktree/<name>).
|
|
62
62
|
// Writing it to META.json would leave stale metadata after merge back to main.
|
|
63
63
|
if (detectWorktreeName(basePath)) return;
|
|
64
64
|
const svc = getService(basePath);
|
|
65
65
|
const current = svc.getCurrentBranch();
|
|
66
|
-
writeIntegrationBranch(basePath, milestoneId, current
|
|
66
|
+
writeIntegrationBranch(basePath, milestoneId, current);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// ─── Pure Utility Functions (unchanged) ────────────────────────────────────
|
|
@@ -149,7 +149,11 @@ async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client>
|
|
|
149
149
|
stderr: "pipe",
|
|
150
150
|
});
|
|
151
151
|
} else if (config.transport === "http" && config.url) {
|
|
152
|
-
|
|
152
|
+
const resolvedUrl = config.url.replace(
|
|
153
|
+
/\$\{([^}]+)\}/g,
|
|
154
|
+
(_, name) => process.env[name] ?? "",
|
|
155
|
+
);
|
|
156
|
+
transport = new StreamableHTTPClientTransport(new URL(resolvedUrl));
|
|
153
157
|
} else {
|
|
154
158
|
throw new Error(`Server "${name}" has unsupported transport: ${config.transport}`);
|
|
155
159
|
}
|
|
@@ -398,16 +398,16 @@ export function registerSearchTool(pi: ExtensionAPI) {
|
|
|
398
398
|
// with brief interruptions every MAX_CONSECUTIVE_DUPES+1 calls.
|
|
399
399
|
if (cacheKey === lastSearchKey) {
|
|
400
400
|
consecutiveDupeCount++;
|
|
401
|
-
if (consecutiveDupeCount
|
|
401
|
+
if (consecutiveDupeCount > MAX_CONSECUTIVE_DUPES) {
|
|
402
402
|
return {
|
|
403
|
-
content: [{ type: "text" as const, text: `⚠️ Search loop detected: the query "${params.query}" has been searched ${consecutiveDupeCount
|
|
403
|
+
content: [{ type: "text" as const, text: `⚠️ Search loop detected: the query "${params.query}" has been searched ${consecutiveDupeCount} times consecutively with identical results. The information you need is already in the previous search results above. Stop searching and use those results to proceed with your task.` }],
|
|
404
404
|
isError: true,
|
|
405
405
|
details: { errorKind: "search_loop", error: "Consecutive duplicate search detected" } satisfies Partial<SearchDetails>,
|
|
406
406
|
};
|
|
407
407
|
}
|
|
408
408
|
} else {
|
|
409
409
|
lastSearchKey = cacheKey;
|
|
410
|
-
consecutiveDupeCount =
|
|
410
|
+
consecutiveDupeCount = 1;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
const cached = searchCache.get(cacheKey);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-workflow
|
|
3
|
+
description: Conversational guide for creating valid YAML workflow definitions. Use when asked to "create a workflow", "new workflow definition", "build a workflow", "workflow YAML", "define workflow steps", or "workflow from template".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<essential_principles>
|
|
7
|
+
You are a workflow definition author. You help users create valid V1 YAML workflow definitions that the GSD workflow engine can execute.
|
|
8
|
+
|
|
9
|
+
**V1 Schema Basics:**
|
|
10
|
+
|
|
11
|
+
- Every definition requires `version: 1`, a non-empty `name`, and at least one step in `steps[]`.
|
|
12
|
+
- Optional top-level fields: `description` (string), `params` (key-value defaults for `{{ key }}` substitution).
|
|
13
|
+
- Each step requires: `id` (unique string), `name` (non-empty string), `prompt` (non-empty string).
|
|
14
|
+
- Each step optionally has: `requires` or `depends_on` (array of step IDs), `produces` (array of artifact paths), `context_from` (array of step IDs), `verify` (verification policy object), `iterate` (fan-out config object).
|
|
15
|
+
- YAML uses **snake_case** keys: `depends_on`, `context_from`. The engine converts to camelCase internally.
|
|
16
|
+
|
|
17
|
+
**Validation Rules:**
|
|
18
|
+
|
|
19
|
+
- Step IDs must be unique across the workflow.
|
|
20
|
+
- Dependencies (`requires`/`depends_on`) must reference existing step IDs — no dangling refs.
|
|
21
|
+
- A step cannot depend on itself.
|
|
22
|
+
- The dependency graph must be acyclic (no circular dependencies).
|
|
23
|
+
- `produces` paths must not contain `..` (path traversal rejected).
|
|
24
|
+
- `iterate.source` must not contain `..` (path traversal rejected).
|
|
25
|
+
- `iterate.pattern` must be a valid regex with at least one capture group.
|
|
26
|
+
|
|
27
|
+
**Four Verification Policies:**
|
|
28
|
+
|
|
29
|
+
1. `content-heuristic` — Checks artifact content. Optional: `minSize` (number), `pattern` (string).
|
|
30
|
+
2. `shell-command` — Runs a shell command. Required: `command` (non-empty string).
|
|
31
|
+
3. `prompt-verify` — Asks an LLM to verify. Required: `prompt` (non-empty string).
|
|
32
|
+
4. `human-review` — Pauses for human approval. No extra fields required.
|
|
33
|
+
|
|
34
|
+
**Parameter Substitution:**
|
|
35
|
+
|
|
36
|
+
- Define defaults in top-level `params: { key: "default_value" }`.
|
|
37
|
+
- Use `{{ key }}` placeholders in step prompts — the engine replaces them at runtime.
|
|
38
|
+
- CLI overrides take precedence over definition defaults.
|
|
39
|
+
- Parameter values must not contain `..` (path traversal guard).
|
|
40
|
+
- Any unresolved `{{ key }}` after substitution causes an error.
|
|
41
|
+
|
|
42
|
+
**Path Traversal Guard:**
|
|
43
|
+
|
|
44
|
+
- The engine rejects any `produces` path or `iterate.source` containing `..`.
|
|
45
|
+
- Parameter values are also checked for `..` during substitution.
|
|
46
|
+
|
|
47
|
+
**Output Location:**
|
|
48
|
+
|
|
49
|
+
- Finished definitions go in `.gsd/workflow-defs/<name>.yaml`.
|
|
50
|
+
- After writing, tell the user to validate with `/gsd workflow validate <name>`.
|
|
51
|
+
</essential_principles>
|
|
52
|
+
|
|
53
|
+
<routing>
|
|
54
|
+
Determine the user's intent and route to the appropriate workflow:
|
|
55
|
+
|
|
56
|
+
**"I want to create a workflow from scratch" / "new workflow" / "build a workflow":**
|
|
57
|
+
→ Read `workflows/create-from-scratch.md` and follow it.
|
|
58
|
+
|
|
59
|
+
**"I want to start from a template" / "from an example" / "customize a template":**
|
|
60
|
+
→ Read `workflows/create-from-template.md` and follow it.
|
|
61
|
+
|
|
62
|
+
**"Help me understand the schema" / "what fields are available?":**
|
|
63
|
+
→ Read `references/yaml-schema-v1.md` and explain the relevant parts.
|
|
64
|
+
|
|
65
|
+
**"How does verification work?" / "verify policies":**
|
|
66
|
+
→ Read `references/verification-policies.md` and explain.
|
|
67
|
+
|
|
68
|
+
**"How do I use context_from / iterate / params?":**
|
|
69
|
+
→ Read `references/feature-patterns.md` and explain the relevant feature.
|
|
70
|
+
|
|
71
|
+
**If intent is unclear, ask one clarifying question:**
|
|
72
|
+
- "Do you want to create a workflow from scratch, or start from an existing template?"
|
|
73
|
+
- Then route based on the answer.
|
|
74
|
+
</routing>
|
|
75
|
+
|
|
76
|
+
<reference_index>
|
|
77
|
+
Read these files when you need detailed schema knowledge during workflow authoring:
|
|
78
|
+
|
|
79
|
+
- `references/yaml-schema-v1.md` — Complete field-by-field V1 schema reference. Read when you need to explain any field's type, constraints, or defaults.
|
|
80
|
+
- `references/verification-policies.md` — All four verify policies with complete YAML examples. Read when helping the user choose or configure verification for a step.
|
|
81
|
+
- `references/feature-patterns.md` — Usage patterns for `context_from`, `iterate`, and `params` with complete YAML examples. Read when the user wants context chaining, fan-out iteration, or parameterized workflows.
|
|
82
|
+
</reference_index>
|
|
83
|
+
|
|
84
|
+
<templates_index>
|
|
85
|
+
Available templates in `templates/`:
|
|
86
|
+
|
|
87
|
+
- `workflow-definition.yaml` — Blank scaffold with all fields shown as comments. Copy and fill for a quick start.
|
|
88
|
+
- `blog-post-pipeline.yaml` — Linear chain with params and content-heuristic verification.
|
|
89
|
+
- `code-audit.yaml` — Iterate-based fan-out with shell-command verification.
|
|
90
|
+
- `release-checklist.yaml` — Diamond dependency graph with human-review verification.
|
|
91
|
+
</templates_index>
|
|
92
|
+
|
|
93
|
+
<output_conventions>
|
|
94
|
+
When assembling the final YAML:
|
|
95
|
+
|
|
96
|
+
1. Use 2-space indentation consistently.
|
|
97
|
+
2. Quote string values that contain special YAML characters (`:`, `{`, `}`, `[`, `]`, `#`).
|
|
98
|
+
3. Always include `version: 1` as the first field.
|
|
99
|
+
4. Order top-level fields: `version`, `name`, `description`, `params`, `steps`.
|
|
100
|
+
5. Order step fields: `id`, `name`, `prompt`, `requires`, `produces`, `context_from`, `verify`, `iterate`.
|
|
101
|
+
6. Write the file to `.gsd/workflow-defs/<name>.yaml`.
|
|
102
|
+
7. After writing, tell the user: "Run `/gsd workflow validate <name>` to check the definition."
|
|
103
|
+
</output_conventions>
|