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
|
@@ -2,7 +2,7 @@ import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, rmSync,
|
|
|
2
2
|
import { basename, dirname, join, sep } from "node:path";
|
|
3
3
|
|
|
4
4
|
import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
|
|
5
|
-
import { readRepoMeta, externalProjectsRoot } from "./repo-identity.js";
|
|
5
|
+
import { readRepoMeta, externalProjectsRoot, cleanNumberedGsdVariants } from "./repo-identity.js";
|
|
6
6
|
import { loadFile, parseRoadmap } from "./files.js";
|
|
7
7
|
import { resolveMilestoneFile, milestonesDir, gsdRoot, resolveGsdRootFile, relGsdRootFile } from "./paths.js";
|
|
8
8
|
import { deriveState, isMilestoneComplete } from "./state.js";
|
|
@@ -776,6 +776,37 @@ export async function checkRuntimeHealth(
|
|
|
776
776
|
// Non-fatal — external state check failed
|
|
777
777
|
}
|
|
778
778
|
|
|
779
|
+
// ── Numbered .gsd collision variants (#2205) ───────────────────────────
|
|
780
|
+
// macOS APFS can create ".gsd 2", ".gsd 3" etc. when a directory blocks
|
|
781
|
+
// symlink creation. These must be removed so the canonical .gsd is used.
|
|
782
|
+
try {
|
|
783
|
+
const variantPattern = /^\.gsd \d+$/;
|
|
784
|
+
const entries = readdirSync(basePath);
|
|
785
|
+
const variants = entries.filter(e => variantPattern.test(e));
|
|
786
|
+
if (variants.length > 0) {
|
|
787
|
+
for (const v of variants) {
|
|
788
|
+
issues.push({
|
|
789
|
+
severity: "warning",
|
|
790
|
+
code: "numbered_gsd_variant",
|
|
791
|
+
scope: "project",
|
|
792
|
+
unitId: "project",
|
|
793
|
+
message: `Found macOS collision variant "${v}" — this can cause GSD state to appear deleted.`,
|
|
794
|
+
file: v,
|
|
795
|
+
fixable: true,
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (shouldFix("numbered_gsd_variant")) {
|
|
800
|
+
const removed = cleanNumberedGsdVariants(basePath);
|
|
801
|
+
for (const name of removed) {
|
|
802
|
+
fixesApplied.push(`removed numbered .gsd variant: ${name}`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
} catch {
|
|
807
|
+
// Non-fatal — variant check failed
|
|
808
|
+
}
|
|
809
|
+
|
|
779
810
|
// ── Metrics ledger integrity ───────────────────────────────────────────
|
|
780
811
|
try {
|
|
781
812
|
const metricsPath = join(root, "metrics.json");
|
|
@@ -305,11 +305,24 @@ function checkOptionalProviders(): ProviderCheckResult[] {
|
|
|
305
305
|
const optional = ["brave", "tavily", "jina", "context7"] as const;
|
|
306
306
|
const results: ProviderCheckResult[] = [];
|
|
307
307
|
|
|
308
|
+
// Determine which search providers are configured so we can suppress
|
|
309
|
+
// "not configured" noise for alternative search providers when at least
|
|
310
|
+
// one is already active (e.g. don't warn about missing BRAVE_API_KEY
|
|
311
|
+
// when Tavily is configured).
|
|
312
|
+
const searchProviderIds = ["brave", "tavily"] as const;
|
|
313
|
+
const hasAnySearchProvider = searchProviderIds.some(id => resolveKey(id).found);
|
|
314
|
+
|
|
308
315
|
for (const providerId of optional) {
|
|
309
316
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
310
317
|
if (!info) continue;
|
|
311
318
|
|
|
312
319
|
const lookup = resolveKey(providerId);
|
|
320
|
+
|
|
321
|
+
// Skip unconfigured search providers when another search provider is active
|
|
322
|
+
if (!lookup.found && hasAnySearchProvider && info.category === "search") {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
313
326
|
results.push({
|
|
314
327
|
name: providerId,
|
|
315
328
|
label: info.label,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine-resolver.ts — Route sessions to engine/policy pairs.
|
|
3
|
+
*
|
|
4
|
+
* Routes `null` and `"dev"` engine IDs to the DevWorkflowEngine/DevExecutionPolicy
|
|
5
|
+
* pair. Any other non-null engine ID is treated as a custom workflow engine that
|
|
6
|
+
* reads its state from an `activeRunDir`. Respects `GSD_ENGINE_BYPASS=1` kill
|
|
7
|
+
* switch to skip the engine layer entirely.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { WorkflowEngine } from "./workflow-engine.js";
|
|
11
|
+
import type { ExecutionPolicy } from "./execution-policy.js";
|
|
12
|
+
import { DevWorkflowEngine } from "./dev-workflow-engine.js";
|
|
13
|
+
import { DevExecutionPolicy } from "./dev-execution-policy.js";
|
|
14
|
+
import { CustomWorkflowEngine } from "./custom-workflow-engine.js";
|
|
15
|
+
import { CustomExecutionPolicy } from "./custom-execution-policy.js";
|
|
16
|
+
|
|
17
|
+
/** A resolved engine + policy pair ready for the auto-loop. */
|
|
18
|
+
export interface ResolvedEngine {
|
|
19
|
+
engine: WorkflowEngine;
|
|
20
|
+
policy: ExecutionPolicy;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolve an engine/policy pair for the given session.
|
|
25
|
+
*
|
|
26
|
+
* - `null` or `"dev"` → DevWorkflowEngine + DevExecutionPolicy
|
|
27
|
+
* - any other non-null ID → CustomWorkflowEngine(activeRunDir) + CustomExecutionPolicy()
|
|
28
|
+
* (requires activeRunDir to be a non-empty string)
|
|
29
|
+
*
|
|
30
|
+
* Note: `GSD_ENGINE_BYPASS=1` is checked in autoLoop before calling this function.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveEngine(
|
|
33
|
+
session: { activeEngineId: string | null; activeRunDir?: string | null },
|
|
34
|
+
): ResolvedEngine {
|
|
35
|
+
const { activeEngineId, activeRunDir } = session;
|
|
36
|
+
|
|
37
|
+
if (activeEngineId === null || activeEngineId === "dev") {
|
|
38
|
+
return {
|
|
39
|
+
engine: new DevWorkflowEngine(),
|
|
40
|
+
policy: new DevExecutionPolicy(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Any non-null, non-"dev" engine ID is a custom workflow engine.
|
|
45
|
+
// activeRunDir is required — the engine reads GRAPH.yaml from it.
|
|
46
|
+
if (!activeRunDir || typeof activeRunDir !== "string") {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Custom engine "${activeEngineId}" requires activeRunDir to be a non-empty string, ` +
|
|
49
|
+
`got: ${JSON.stringify(activeRunDir)}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
engine: new CustomWorkflowEngine(activeRunDir),
|
|
55
|
+
policy: new CustomExecutionPolicy(activeRunDir),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine-types.ts — Engine-polymorphic type contracts.
|
|
3
|
+
*
|
|
4
|
+
* LEAF NODE: This file must have ZERO imports from any GSD module.
|
|
5
|
+
* Only `node:` imports are permitted. All engine/policy interfaces
|
|
6
|
+
* depend on these types; nothing here depends on GSD internals.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Snapshot of engine state at a point in time. */
|
|
10
|
+
export interface EngineState {
|
|
11
|
+
phase: string;
|
|
12
|
+
currentMilestoneId: string | null;
|
|
13
|
+
activeSliceId: string | null;
|
|
14
|
+
activeTaskId: string | null;
|
|
15
|
+
isComplete: boolean;
|
|
16
|
+
/** Opaque engine-specific state — never narrowed to a GSD-specific type. */
|
|
17
|
+
raw: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A unit of work the engine wants the agent to execute. */
|
|
21
|
+
export interface StepContract {
|
|
22
|
+
unitType: string;
|
|
23
|
+
unitId: string;
|
|
24
|
+
prompt: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** UI-facing metadata for progress display. */
|
|
28
|
+
export interface DisplayMetadata {
|
|
29
|
+
engineLabel: string;
|
|
30
|
+
currentPhase: string;
|
|
31
|
+
progressSummary: string;
|
|
32
|
+
stepCount: { completed: number; total: number } | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Discriminated union: what the engine tells the loop to do next.
|
|
37
|
+
*
|
|
38
|
+
* - `dispatch` — execute a step
|
|
39
|
+
* - `stop` — halt the loop with a reason and severity
|
|
40
|
+
* - `skip` — nothing to do right now, advance without executing
|
|
41
|
+
*/
|
|
42
|
+
export type EngineDispatchAction =
|
|
43
|
+
| { action: "dispatch"; step: StepContract }
|
|
44
|
+
| { action: "stop"; reason: string; level: "info" | "warning" | "error" }
|
|
45
|
+
| { action: "skip" };
|
|
46
|
+
|
|
47
|
+
/** Outcome of reconciling state after a step completes. */
|
|
48
|
+
export interface ReconcileResult {
|
|
49
|
+
outcome: "continue" | "milestone-complete" | "pause" | "stop";
|
|
50
|
+
reason?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Recovery strategy when a step fails. */
|
|
54
|
+
export interface RecoveryAction {
|
|
55
|
+
outcome: "retry" | "skip" | "stop" | "pause";
|
|
56
|
+
reason?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Result of closing out a completed unit. */
|
|
60
|
+
export interface CloseoutResult {
|
|
61
|
+
committed: boolean;
|
|
62
|
+
artifacts: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Record of a completed execution step. */
|
|
66
|
+
export interface CompletedStep {
|
|
67
|
+
unitType: string;
|
|
68
|
+
unitId: string;
|
|
69
|
+
startedAt: number;
|
|
70
|
+
finishedAt: number;
|
|
71
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* execution-policy.ts — ExecutionPolicy interface.
|
|
3
|
+
*
|
|
4
|
+
* Defines the policy layer that governs model selection, verification,
|
|
5
|
+
* recovery, and closeout for each execution step. Imports only from
|
|
6
|
+
* the leaf-node engine-types.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { RecoveryAction, CloseoutResult } from "./engine-types.js";
|
|
10
|
+
|
|
11
|
+
/** Policy governing how each step is executed, verified, and closed out. */
|
|
12
|
+
export interface ExecutionPolicy {
|
|
13
|
+
/** Prepare the workspace before a milestone begins (e.g. worktree setup). */
|
|
14
|
+
prepareWorkspace(basePath: string, milestoneId: string): Promise<void>;
|
|
15
|
+
|
|
16
|
+
/** Select the model tier for a given unit. Returns null to use defaults. */
|
|
17
|
+
selectModel(
|
|
18
|
+
unitType: string,
|
|
19
|
+
unitId: string,
|
|
20
|
+
context: { basePath: string },
|
|
21
|
+
): Promise<{ tier: string; modelDowngraded: boolean } | null>;
|
|
22
|
+
|
|
23
|
+
/** Verify unit output. Returns disposition for the loop. */
|
|
24
|
+
verify(
|
|
25
|
+
unitType: string,
|
|
26
|
+
unitId: string,
|
|
27
|
+
context: { basePath: string },
|
|
28
|
+
): Promise<"continue" | "retry" | "pause">;
|
|
29
|
+
|
|
30
|
+
/** Determine recovery action when a unit fails. */
|
|
31
|
+
recover(
|
|
32
|
+
unitType: string,
|
|
33
|
+
unitId: string,
|
|
34
|
+
context: { basePath: string },
|
|
35
|
+
): Promise<RecoveryAction>;
|
|
36
|
+
|
|
37
|
+
/** Close out a completed unit (commit, snapshot, artifact capture). */
|
|
38
|
+
closeout(
|
|
39
|
+
unitType: string,
|
|
40
|
+
unitId: string,
|
|
41
|
+
context: { basePath: string; startedAt: number },
|
|
42
|
+
): Promise<CloseoutResult>;
|
|
43
|
+
}
|
|
@@ -30,6 +30,9 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
30
30
|
import { gsdRoot } from "./paths.js";
|
|
31
31
|
import { formatDuration } from "../shared/format-utils.js";
|
|
32
32
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
33
|
+
import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
34
|
+
import { showNextAction } from "../shared/tui.js";
|
|
35
|
+
import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
|
|
33
36
|
|
|
34
37
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
35
38
|
|
|
@@ -67,6 +70,71 @@ interface ForensicReport {
|
|
|
67
70
|
recentUnits: { type: string; id: string; cost: number; duration: number; model: string; finishedAt: number }[];
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
// ─── Duplicate Detection ──────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
const DEDUP_PROMPT_SECTION = `
|
|
76
|
+
## Duplicate Detection (REQUIRED before issue creation)
|
|
77
|
+
|
|
78
|
+
Before offering to create a GitHub issue, you MUST search for existing issues and PRs that may already address this bug. This step uses the user's AI tokens for analysis.
|
|
79
|
+
|
|
80
|
+
### Search Steps
|
|
81
|
+
|
|
82
|
+
1. **Search closed issues** for similar keywords from your diagnosis:
|
|
83
|
+
\`\`\`
|
|
84
|
+
gh issue list --repo gsd-build/gsd-2 --state closed --search "<keywords from root cause>" --limit 20
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
2. **Search open PRs** that might contain the fix:
|
|
88
|
+
\`\`\`
|
|
89
|
+
gh pr list --repo gsd-build/gsd-2 --state open --search "<keywords>" --limit 10
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
3. **Search merged PRs** that may have already fixed this:
|
|
93
|
+
\`\`\`
|
|
94
|
+
gh pr list --repo gsd-build/gsd-2 --state merged --search "<keywords>" --limit 10
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
### Analysis
|
|
98
|
+
|
|
99
|
+
For each result, compare it against your root-cause diagnosis:
|
|
100
|
+
- Does the issue describe the same code path or file?
|
|
101
|
+
- Does the PR modify the same file:line you identified?
|
|
102
|
+
- Is the symptom description semantically similar even if keywords differ?
|
|
103
|
+
|
|
104
|
+
### Present Findings
|
|
105
|
+
|
|
106
|
+
If you find potential matches, present them to the user:
|
|
107
|
+
|
|
108
|
+
1. **"Already fixed by PR #X — skip issue creation"** — when a merged PR or closed issue clearly addresses the same root cause. Explain why you believe it matches.
|
|
109
|
+
2. **"Add my findings to existing issue #Y"** — when an open issue exists for the same bug. Use \`gh issue comment #Y --repo gsd-build/gsd-2\` to add forensic evidence.
|
|
110
|
+
3. **"Create new issue anyway"** — when existing results do not cover this specific failure.
|
|
111
|
+
|
|
112
|
+
Only proceed to issue creation if no matches were found OR the user explicitly chooses "Create new issue anyway".
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
async function writeForensicsDedupPref(ctx: ExtensionCommandContext, enabled: boolean): Promise<void> {
|
|
116
|
+
const prefsPath = getGlobalGSDPreferencesPath();
|
|
117
|
+
await ensurePreferencesFile(prefsPath, ctx, "global");
|
|
118
|
+
const existing = loadGlobalGSDPreferences();
|
|
119
|
+
const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
|
|
120
|
+
prefs.version = prefs.version || 1;
|
|
121
|
+
prefs.forensics_dedup = enabled;
|
|
122
|
+
|
|
123
|
+
const frontmatter = serializePreferencesToFrontmatter(prefs);
|
|
124
|
+
const raw = existsSync(prefsPath) ? readFileSync(prefsPath, "utf-8") : "";
|
|
125
|
+
let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
|
|
126
|
+
const start = raw.startsWith("---\n") ? 4 : raw.startsWith("---\r\n") ? 5 : -1;
|
|
127
|
+
if (start !== -1) {
|
|
128
|
+
const closingIdx = raw.indexOf("\n---", start);
|
|
129
|
+
if (closingIdx !== -1) {
|
|
130
|
+
const after = raw.slice(closingIdx + 4);
|
|
131
|
+
if (after.trim()) body = after;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
writeFileSync(prefsPath, `---\n${frontmatter}---${body}`, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
|
|
70
138
|
// ─── Entry Point ──────────────────────────────────────────────────────────────
|
|
71
139
|
|
|
72
140
|
export async function handleForensics(
|
|
@@ -98,6 +166,29 @@ export async function handleForensics(
|
|
|
98
166
|
return;
|
|
99
167
|
}
|
|
100
168
|
|
|
169
|
+
// ─── Duplicate detection opt-in ─────────────────────────────────────────────
|
|
170
|
+
const effectivePrefs = loadEffectiveGSDPreferences()?.preferences;
|
|
171
|
+
let dedupEnabled = effectivePrefs?.forensics_dedup === true;
|
|
172
|
+
|
|
173
|
+
if (effectivePrefs?.forensics_dedup === undefined) {
|
|
174
|
+
const choice = await showNextAction(ctx, {
|
|
175
|
+
title: "Duplicate detection available",
|
|
176
|
+
summary: ["Before filing a GitHub issue, forensics can search existing issues and PRs to avoid duplicates.", "This uses additional AI tokens for analysis."],
|
|
177
|
+
actions: [
|
|
178
|
+
{ id: "enable", label: "Enable duplicate detection", description: "Search issues/PRs before filing (recommended)", recommended: true },
|
|
179
|
+
{ id: "skip", label: "Skip for now", description: "File without checking for duplicates" },
|
|
180
|
+
],
|
|
181
|
+
notYetMessage: "You can enable this later via preferences (forensics_dedup: true).",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (choice === "enable") {
|
|
185
|
+
await writeForensicsDedupPref(ctx, true);
|
|
186
|
+
dedupEnabled = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const dedupSection = dedupEnabled ? DEDUP_PROMPT_SECTION : "";
|
|
191
|
+
|
|
101
192
|
ctx.ui.notify("Building forensic report...", "info");
|
|
102
193
|
|
|
103
194
|
const report = await buildForensicReport(basePath);
|
|
@@ -117,6 +208,7 @@ export async function handleForensics(
|
|
|
117
208
|
problemDescription,
|
|
118
209
|
forensicData,
|
|
119
210
|
gsdSourceDir,
|
|
211
|
+
dedupSection,
|
|
120
212
|
});
|
|
121
213
|
|
|
122
214
|
ctx.ui.notify(`Forensic report saved: ${relative(basePath, savedPath)}`, "info");
|
|
@@ -245,7 +245,6 @@ export function writeIntegrationBranch(
|
|
|
245
245
|
basePath: string,
|
|
246
246
|
milestoneId: string,
|
|
247
247
|
branch: string,
|
|
248
|
-
_options?: { commitDocs?: boolean },
|
|
249
248
|
): void {
|
|
250
249
|
// Don't record slice branches as the integration target
|
|
251
250
|
if (SLICE_BRANCH_RE.test(branch)) return;
|
|
@@ -137,7 +137,7 @@ export function hasGitTrackedGsdFiles(basePath: string): boolean {
|
|
|
137
137
|
*/
|
|
138
138
|
export function ensureGitignore(
|
|
139
139
|
basePath: string,
|
|
140
|
-
options?: { manageGitignore?: boolean
|
|
140
|
+
options?: { manageGitignore?: boolean },
|
|
141
141
|
): boolean {
|
|
142
142
|
// If manage_gitignore is explicitly false, do not touch .gitignore at all
|
|
143
143
|
if (options?.manageGitignore === false) return false;
|