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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
@@ -59,7 +59,9 @@ describe("ModelDiscoveryCache — basic operations", () => {
|
|
|
59
59
|
|
|
60
60
|
cache.clear("openai");
|
|
61
61
|
assert.equal(cache.get("openai"), undefined);
|
|
62
|
-
|
|
62
|
+
const googleEntry = cache.get("google");
|
|
63
|
+
assert.ok(googleEntry);
|
|
64
|
+
assert.equal(googleEntry.models[0].id, "gemini-pro");
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
it("clear without provider removes all entries", () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// GSD Login Dialog Component — OAuth login flow UI
|
|
2
2
|
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
3
3
|
import { getOAuthProviders } from "@gsd/pi-ai/oauth";
|
|
4
|
-
import { Container, type Focusable, getEditorKeybindings, Input, Spacer, Text, type TUI } from "@gsd/pi-tui";
|
|
4
|
+
import { Container, type Focusable, getEditorKeybindings, Input, Spacer, Text, truncateToWidth, type TUI } from "@gsd/pi-tui";
|
|
5
5
|
import { execFile } from "child_process";
|
|
6
6
|
import { theme } from "../theme/theme.js";
|
|
7
7
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
@@ -121,21 +121,25 @@ export class LoginDialogComponent extends Container implements Focusable {
|
|
|
121
121
|
showAuth(url: string, instructions?: string): void {
|
|
122
122
|
this.contentContainer.clear();
|
|
123
123
|
this.contentContainer.addChild(new Spacer(1));
|
|
124
|
-
|
|
124
|
+
|
|
125
|
+
// Truncate the visible URL text so it never wraps (which would break
|
|
126
|
+
// the OSC 8 hyperlink). The full URL is still the link target.
|
|
127
|
+
const maxUrlWidth = Math.max(20, this.tui.terminal.columns - 4);
|
|
128
|
+
const displayUrl = truncateToWidth(url, maxUrlWidth);
|
|
129
|
+
const urlLink = `\x1b]8;;${url}\x07${theme.fg("accent", displayUrl)}\x1b]8;;\x07`;
|
|
130
|
+
this.contentContainer.addChild(new Text(urlLink, 1, 0));
|
|
125
131
|
|
|
126
132
|
const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
|
|
127
|
-
|
|
128
|
-
this.contentContainer.addChild(new Text(theme.fg("dim", hyperlink), 1, 0));
|
|
133
|
+
this.contentContainer.addChild(new Text(theme.fg("dim", clickHint), 1, 0));
|
|
129
134
|
|
|
130
135
|
if (instructions) {
|
|
131
136
|
this.contentContainer.addChild(new Spacer(1));
|
|
132
137
|
this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));
|
|
133
138
|
}
|
|
134
139
|
|
|
135
|
-
//
|
|
136
|
-
// so it treats the URL as a target, not a window title
|
|
140
|
+
// PowerShell's Start-Process handles URLs with '&' safely; cmd /c start does not.
|
|
137
141
|
if (process.platform === "win32") {
|
|
138
|
-
execFile("
|
|
142
|
+
execFile("powershell", ["-c", `Start-Process '${url.replace(/'/g, "''")}'`], () => {});
|
|
139
143
|
} else {
|
|
140
144
|
const openCmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
141
145
|
execFile(openCmd, [url], () => {});
|
|
@@ -2321,6 +2321,11 @@ export class InteractiveMode {
|
|
|
2321
2321
|
}
|
|
2322
2322
|
|
|
2323
2323
|
private handleCtrlZ(): void {
|
|
2324
|
+
// On Windows, SIGTSTP doesn't exist - Ctrl+Z is not supported
|
|
2325
|
+
if (process.platform === "win32") {
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2324
2329
|
// Ignore SIGINT while suspended so Ctrl+C in the terminal does not
|
|
2325
2330
|
// kill the backgrounded process. The handler is removed on resume.
|
|
2326
2331
|
const ignoreSigint = () => {};
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
import type { DispatchAction } from "../auto-dispatch.js";
|
|
20
20
|
import type { WorktreeResolver } from "../worktree-resolver.js";
|
|
21
21
|
import type { CmuxLogLevel } from "../../cmux/index.js";
|
|
22
|
+
import type { JournalEntry } from "../journal.js";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Dependencies injected by the caller (auto.ts startAuto) so autoLoop
|
|
@@ -102,7 +103,7 @@ export interface LoopDeps {
|
|
|
102
103
|
basePath: string,
|
|
103
104
|
milestoneId: string,
|
|
104
105
|
roadmapContent: string,
|
|
105
|
-
) => { pushed: boolean };
|
|
106
|
+
) => { pushed: boolean; codeFilesChanged: boolean };
|
|
106
107
|
teardownAutoWorktree: (basePath: string, milestoneId: string) => void;
|
|
107
108
|
createAutoWorktree: (basePath: string, milestoneId: string) => string;
|
|
108
109
|
captureIntegrationBranch: (
|
|
@@ -285,4 +286,7 @@ export interface LoopDeps {
|
|
|
285
286
|
|
|
286
287
|
// Session manager
|
|
287
288
|
getSessionFile: (ctx: ExtensionContext) => string;
|
|
289
|
+
|
|
290
|
+
// Journal
|
|
291
|
+
emitJournalEvent: (entry: JournalEntry) => void;
|
|
288
292
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
11
11
|
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
12
13
|
import type { AutoSession, SidecarItem } from "./session.js";
|
|
13
14
|
import type { LoopDeps } from "./loop-deps.js";
|
|
14
15
|
import {
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
} from "./phases.js";
|
|
28
29
|
import { debugLog } from "../debug-logger.js";
|
|
29
30
|
import { isInfrastructureError } from "./infra-errors.js";
|
|
31
|
+
import { resolveEngine } from "../engine-resolver.js";
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Main auto-mode execution loop. Iterates: derive → dispatch → guards →
|
|
@@ -51,6 +53,11 @@ export async function autoLoop(
|
|
|
51
53
|
iteration++;
|
|
52
54
|
debugLog("autoLoop", { phase: "loop-top", iteration });
|
|
53
55
|
|
|
56
|
+
// ── Journal: per-iteration flow grouping ──
|
|
57
|
+
const flowId = randomUUID();
|
|
58
|
+
let seqCounter = 0;
|
|
59
|
+
const nextSeq = () => ++seqCounter;
|
|
60
|
+
|
|
54
61
|
if (iteration > MAX_LOOP_ITERATIONS) {
|
|
55
62
|
debugLog("autoLoop", {
|
|
56
63
|
phase: "exit",
|
|
@@ -84,6 +91,7 @@ export async function autoLoop(
|
|
|
84
91
|
unitType: sidecarItem.unitType,
|
|
85
92
|
unitId: sidecarItem.unitId,
|
|
86
93
|
});
|
|
94
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "sidecar-dequeue", data: { kind: sidecarItem.kind, unitType: sidecarItem.unitType, unitId: sidecarItem.unitId } });
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
const sessionLockBase = deps.lockBase();
|
|
@@ -106,9 +114,100 @@ export async function autoLoop(
|
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
|
|
109
|
-
const ic: IterationContext = { ctx, pi, s, deps, prefs, iteration };
|
|
117
|
+
const ic: IterationContext = { ctx, pi, s, deps, prefs, iteration, flowId, nextSeq };
|
|
118
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-start", data: { iteration } });
|
|
110
119
|
let iterData: IterationData;
|
|
111
120
|
|
|
121
|
+
// ── Custom engine path ──────────────────────────────────────────────
|
|
122
|
+
// When activeEngineId is a non-dev value, bypass runPreDispatch and
|
|
123
|
+
// runDispatch entirely — the custom engine drives its own state via
|
|
124
|
+
// GRAPH.yaml. Shares runGuards and runUnitPhase with the dev path.
|
|
125
|
+
// After unit execution, verifies then reconciles via the engine layer.
|
|
126
|
+
//
|
|
127
|
+
// GSD_ENGINE_BYPASS=1 skips the engine layer entirely — falls through
|
|
128
|
+
// to the dev path below.
|
|
129
|
+
if (s.activeEngineId != null && s.activeEngineId !== "dev" && !sidecarItem && process.env.GSD_ENGINE_BYPASS !== "1") {
|
|
130
|
+
debugLog("autoLoop", { phase: "custom-engine-derive", iteration, engineId: s.activeEngineId });
|
|
131
|
+
|
|
132
|
+
const { engine, policy } = resolveEngine({
|
|
133
|
+
activeEngineId: s.activeEngineId,
|
|
134
|
+
activeRunDir: s.activeRunDir,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const engineState = await engine.deriveState(s.basePath);
|
|
138
|
+
if (engineState.isComplete) {
|
|
139
|
+
await deps.stopAuto(ctx, pi, "Workflow complete");
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
debugLog("autoLoop", { phase: "custom-engine-dispatch", iteration });
|
|
144
|
+
const dispatch = await engine.resolveDispatch(engineState, { basePath: s.basePath });
|
|
145
|
+
|
|
146
|
+
if (dispatch.action === "stop") {
|
|
147
|
+
await deps.stopAuto(ctx, pi, dispatch.reason ?? "Engine stopped");
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
if (dispatch.action === "skip") {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// dispatch.action === "dispatch"
|
|
155
|
+
const step = dispatch.step!;
|
|
156
|
+
const gsdState = await deps.deriveState(s.basePath);
|
|
157
|
+
|
|
158
|
+
iterData = {
|
|
159
|
+
unitType: step.unitType,
|
|
160
|
+
unitId: step.unitId,
|
|
161
|
+
prompt: step.prompt,
|
|
162
|
+
finalPrompt: step.prompt,
|
|
163
|
+
pauseAfterUatDispatch: false,
|
|
164
|
+
observabilityIssues: [],
|
|
165
|
+
state: gsdState,
|
|
166
|
+
mid: s.currentMilestoneId ?? "workflow",
|
|
167
|
+
midTitle: "Workflow",
|
|
168
|
+
isRetry: false,
|
|
169
|
+
previousTier: undefined,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// ── Progress widget (mirrors dev path in runDispatch) ──
|
|
173
|
+
deps.updateProgressWidget(ctx, iterData.unitType, iterData.unitId, iterData.state);
|
|
174
|
+
|
|
175
|
+
// ── Guards (shared with dev path) ──
|
|
176
|
+
const guardsResult = await runGuards(ic, s.currentMilestoneId ?? "workflow");
|
|
177
|
+
if (guardsResult.action === "break") break;
|
|
178
|
+
|
|
179
|
+
// ── Unit execution (shared with dev path) ──
|
|
180
|
+
const unitPhaseResult = await runUnitPhase(ic, iterData, loopState);
|
|
181
|
+
if (unitPhaseResult.action === "break") break;
|
|
182
|
+
|
|
183
|
+
// ── Verify first, then reconcile (only mark complete on pass) ──
|
|
184
|
+
debugLog("autoLoop", { phase: "custom-engine-verify", iteration, unitId: iterData.unitId });
|
|
185
|
+
const verifyResult = await policy.verify(iterData.unitType, iterData.unitId, { basePath: s.basePath });
|
|
186
|
+
if (verifyResult === "pause") {
|
|
187
|
+
await deps.pauseAuto(ctx, pi);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
if (verifyResult === "retry") {
|
|
191
|
+
debugLog("autoLoop", { phase: "custom-engine-verify-retry", iteration, unitId: iterData.unitId });
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Verification passed — mark step complete
|
|
196
|
+
debugLog("autoLoop", { phase: "custom-engine-reconcile", iteration, unitId: iterData.unitId });
|
|
197
|
+
await engine.reconcile(engineState, {
|
|
198
|
+
unitType: iterData.unitType,
|
|
199
|
+
unitId: iterData.unitId,
|
|
200
|
+
startedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
201
|
+
finishedAt: Date.now(),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
deps.clearUnitTimeout();
|
|
205
|
+
consecutiveErrors = 0;
|
|
206
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
207
|
+
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
112
211
|
if (!sidecarItem) {
|
|
113
212
|
// ── Phase 1: Pre-dispatch ─────────────────────────────────────────
|
|
114
213
|
const preDispatchResult = await runPreDispatch(ic, loopState);
|
|
@@ -153,6 +252,7 @@ export async function autoLoop(
|
|
|
153
252
|
if (finalizeResult.action === "continue") continue;
|
|
154
253
|
|
|
155
254
|
consecutiveErrors = 0; // Iteration completed successfully
|
|
255
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
156
256
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
157
257
|
} catch (loopErr) {
|
|
158
258
|
// ── Blanket catch: absorb unexpected exceptions, apply graduated recovery ──
|
|
@@ -26,6 +26,7 @@ import { runUnit } from "./run-unit.js";
|
|
|
26
26
|
import { debugLog } from "../debug-logger.js";
|
|
27
27
|
import { gsdRoot } from "../paths.js";
|
|
28
28
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
29
|
+
import { PROJECT_FILES } from "../detection.js";
|
|
29
30
|
import { join } from "node:path";
|
|
30
31
|
|
|
31
32
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
@@ -192,6 +193,7 @@ export async function runPreDispatch(
|
|
|
192
193
|
|
|
193
194
|
// ── Milestone transition ────────────────────────────────────────────
|
|
194
195
|
if (mid && s.currentMilestoneId && mid !== s.currentMilestoneId) {
|
|
196
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "milestone-transition", data: { from: s.currentMilestoneId, to: mid } });
|
|
195
197
|
ctx.ui.notify(
|
|
196
198
|
`Milestone ${s.currentMilestoneId} complete. Advancing to ${mid}: ${midTitle}.`,
|
|
197
199
|
"info",
|
|
@@ -386,6 +388,7 @@ export async function runPreDispatch(
|
|
|
386
388
|
);
|
|
387
389
|
}
|
|
388
390
|
debugLog("autoLoop", { phase: "exit", reason: "no-active-milestone" });
|
|
391
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "no-active-milestone" } });
|
|
389
392
|
return { action: "break", reason: "no-active-milestone" };
|
|
390
393
|
}
|
|
391
394
|
|
|
@@ -454,6 +457,7 @@ export async function runPreDispatch(
|
|
|
454
457
|
);
|
|
455
458
|
await closeoutAndStop(ctx, pi, s, deps, `Milestone ${mid} complete`);
|
|
456
459
|
debugLog("autoLoop", { phase: "exit", reason: "milestone-complete" });
|
|
460
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
|
|
457
461
|
return { action: "break", reason: "milestone-complete" };
|
|
458
462
|
}
|
|
459
463
|
|
|
@@ -465,6 +469,7 @@ export async function runPreDispatch(
|
|
|
465
469
|
deps.sendDesktopNotification("GSD", blockerMsg, "error", "attention");
|
|
466
470
|
deps.logCmuxEvent(prefs, blockerMsg, "error");
|
|
467
471
|
debugLog("autoLoop", { phase: "exit", reason: "blocked" });
|
|
472
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "blocked", blockers: state.blockers } });
|
|
468
473
|
return { action: "break", reason: "blocked" };
|
|
469
474
|
}
|
|
470
475
|
|
|
@@ -497,6 +502,7 @@ export async function runDispatch(
|
|
|
497
502
|
});
|
|
498
503
|
|
|
499
504
|
if (dispatchResult.action === "stop") {
|
|
505
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "dispatch-stop", rule: dispatchResult.matchedRule, data: { reason: dispatchResult.reason } });
|
|
500
506
|
await closeoutAndStop(ctx, pi, s, deps, dispatchResult.reason);
|
|
501
507
|
debugLog("autoLoop", { phase: "exit", reason: "dispatch-stop" });
|
|
502
508
|
return { action: "break", reason: "dispatch-stop" };
|
|
@@ -508,6 +514,8 @@ export async function runDispatch(
|
|
|
508
514
|
return { action: "continue" };
|
|
509
515
|
}
|
|
510
516
|
|
|
517
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "dispatch-match", rule: dispatchResult.matchedRule, data: { unitType: dispatchResult.unitType, unitId: dispatchResult.unitId } });
|
|
518
|
+
|
|
511
519
|
let unitType = dispatchResult.unitType;
|
|
512
520
|
let unitId = dispatchResult.unitId;
|
|
513
521
|
let prompt = dispatchResult.prompt;
|
|
@@ -600,6 +608,7 @@ export async function runDispatch(
|
|
|
600
608
|
`Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`,
|
|
601
609
|
"info",
|
|
602
610
|
);
|
|
611
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
|
|
603
612
|
}
|
|
604
613
|
if (preDispatchResult.action === "skip") {
|
|
605
614
|
ctx.ui.notify(
|
|
@@ -809,25 +818,27 @@ export async function runUnitPhase(
|
|
|
809
818
|
unitId,
|
|
810
819
|
});
|
|
811
820
|
|
|
812
|
-
// ── Worktree health check (#1833)
|
|
821
|
+
// ── Worktree health check (#1833, #1843) ────────────────────────────
|
|
813
822
|
// Verify the working directory is a valid git checkout with project
|
|
814
823
|
// files before dispatching work. A broken worktree causes agents to
|
|
815
824
|
// hallucinate summaries since they cannot read or write any files.
|
|
825
|
+
// Uses the shared PROJECT_FILES list from detection.ts to support all
|
|
826
|
+
// ecosystems (Rust, Go, Python, Java, etc.), not just JS.
|
|
816
827
|
if (s.basePath && unitType === "execute-task") {
|
|
817
828
|
const gitMarker = join(s.basePath, ".git");
|
|
818
829
|
const hasGit = deps.existsSync(gitMarker);
|
|
819
|
-
const hasPackageJson = deps.existsSync(join(s.basePath, "package.json"));
|
|
820
|
-
const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
|
|
821
830
|
if (!hasGit) {
|
|
822
831
|
const msg = `Worktree health check failed: ${s.basePath} has no .git — refusing to dispatch ${unitType} ${unitId}`;
|
|
823
|
-
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasGit
|
|
832
|
+
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasGit });
|
|
824
833
|
ctx.ui.notify(msg, "error");
|
|
825
834
|
await deps.stopAuto(ctx, pi, msg);
|
|
826
835
|
return { action: "break", reason: "worktree-invalid" };
|
|
827
836
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
837
|
+
const hasProjectFile = PROJECT_FILES.some((f) => deps.existsSync(join(s.basePath, f)));
|
|
838
|
+
const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
|
|
839
|
+
if (!hasProjectFile && !hasSrcDir) {
|
|
840
|
+
const msg = `Worktree health check failed: ${s.basePath} has no recognized project files — refusing to dispatch ${unitType} ${unitId}`;
|
|
841
|
+
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasProjectFile, hasSrcDir });
|
|
831
842
|
ctx.ui.notify(msg, "error");
|
|
832
843
|
await deps.stopAuto(ctx, pi, msg);
|
|
833
844
|
return { action: "break", reason: "worktree-invalid" };
|
|
@@ -843,6 +854,8 @@ export async function runUnitPhase(
|
|
|
843
854
|
const previousTier = s.currentUnitRouting?.tier;
|
|
844
855
|
|
|
845
856
|
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
857
|
+
const unitStartSeq = ic.nextSeq();
|
|
858
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
846
859
|
deps.captureAvailableSkills();
|
|
847
860
|
deps.writeUnitRuntimeRecord(
|
|
848
861
|
s.basePath,
|
|
@@ -988,7 +1001,12 @@ export async function runUnitPhase(
|
|
|
988
1001
|
unitId,
|
|
989
1002
|
prefs,
|
|
990
1003
|
buildSnapshotOpts: () => deps.buildSnapshotOpts(unitType, unitId),
|
|
991
|
-
buildRecoveryContext: () => ({
|
|
1004
|
+
buildRecoveryContext: () => ({
|
|
1005
|
+
basePath: s.basePath,
|
|
1006
|
+
verbose: s.verbose,
|
|
1007
|
+
currentUnitStartedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
1008
|
+
unitRecoveryCount: s.unitRecoveryCount,
|
|
1009
|
+
}),
|
|
992
1010
|
pauseAuto: deps.pauseAuto,
|
|
993
1011
|
});
|
|
994
1012
|
|
|
@@ -1115,9 +1133,9 @@ export async function runUnitPhase(
|
|
|
1115
1133
|
);
|
|
1116
1134
|
}
|
|
1117
1135
|
|
|
1118
|
-
const
|
|
1136
|
+
const skipArtifactVerification = unitType.startsWith("hook/") || unitType === "custom-step";
|
|
1119
1137
|
const artifactVerified =
|
|
1120
|
-
|
|
1138
|
+
skipArtifactVerification ||
|
|
1121
1139
|
deps.verifyExpectedArtifact(unitType, unitId, s.basePath);
|
|
1122
1140
|
if (artifactVerified) {
|
|
1123
1141
|
s.completedUnits.push({
|
|
@@ -1141,6 +1159,8 @@ export async function runUnitPhase(
|
|
|
1141
1159
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
1142
1160
|
}
|
|
1143
1161
|
|
|
1162
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
1163
|
+
|
|
1144
1164
|
return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
|
|
1145
1165
|
}
|
|
1146
1166
|
|
|
@@ -83,6 +83,8 @@ export class AutoSession {
|
|
|
83
83
|
paused = false;
|
|
84
84
|
stepMode = false;
|
|
85
85
|
verbose = false;
|
|
86
|
+
activeEngineId: string | null = null;
|
|
87
|
+
activeRunDir: string | null = null;
|
|
86
88
|
cmdCtx: ExtensionCommandContext | null = null;
|
|
87
89
|
|
|
88
90
|
// ── Paths ────────────────────────────────────────────────────────────────
|
|
@@ -174,6 +176,8 @@ export class AutoSession {
|
|
|
174
176
|
this.paused = false;
|
|
175
177
|
this.stepMode = false;
|
|
176
178
|
this.verbose = false;
|
|
179
|
+
this.activeEngineId = null;
|
|
180
|
+
this.activeRunDir = null;
|
|
177
181
|
this.cmdCtx = null;
|
|
178
182
|
|
|
179
183
|
// Paths
|
|
@@ -226,6 +230,8 @@ export class AutoSession {
|
|
|
226
230
|
paused: this.paused,
|
|
227
231
|
stepMode: this.stepMode,
|
|
228
232
|
basePath: this.basePath,
|
|
233
|
+
activeEngineId: this.activeEngineId,
|
|
234
|
+
activeRunDir: this.activeRunDir,
|
|
229
235
|
currentMilestoneId: this.currentMilestoneId,
|
|
230
236
|
currentUnit: this.currentUnit,
|
|
231
237
|
completedUnits: this.completedUnits.length,
|
|
@@ -69,6 +69,10 @@ export interface IterationContext {
|
|
|
69
69
|
deps: LoopDeps;
|
|
70
70
|
prefs: GSDPreferences | undefined;
|
|
71
71
|
iteration: number;
|
|
72
|
+
/** UUID grouping all journal events for this iteration. */
|
|
73
|
+
flowId: string;
|
|
74
|
+
/** Returns the next monotonically increasing sequence number (1-based, reset per iteration). */
|
|
75
|
+
nextSeq: () => number;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
export interface LoopState {
|
|
@@ -24,6 +24,7 @@ import { GLYPH, INDENT } from "../shared/mod.js";
|
|
|
24
24
|
import { computeProgressScore } from "./progress-score.js";
|
|
25
25
|
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
26
26
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
27
|
+
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
27
28
|
|
|
28
29
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
29
30
|
|
|
@@ -78,6 +79,7 @@ export function unitVerb(unitType: string): string {
|
|
|
78
79
|
case "rewrite-docs": return "rewriting";
|
|
79
80
|
case "reassess-roadmap": return "reassessing";
|
|
80
81
|
case "run-uat": return "running UAT";
|
|
82
|
+
case "custom-step": return "executing workflow step";
|
|
81
83
|
default: return unitType;
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -96,6 +98,7 @@ export function unitPhaseLabel(unitType: string): string {
|
|
|
96
98
|
case "rewrite-docs": return "REWRITE";
|
|
97
99
|
case "reassess-roadmap": return "REASSESS";
|
|
98
100
|
case "run-uat": return "UAT";
|
|
101
|
+
case "custom-step": return "WORKFLOW";
|
|
99
102
|
default: return unitType.toUpperCase();
|
|
100
103
|
}
|
|
101
104
|
}
|
|
@@ -460,6 +463,9 @@ export function updateProgressWidget(
|
|
|
460
463
|
// Pre-fetch last commit for display
|
|
461
464
|
refreshLastCommit(accessors.getBasePath());
|
|
462
465
|
|
|
466
|
+
// Cache the effective service tier at widget creation time (reads preferences)
|
|
467
|
+
const effectiveServiceTier = getEffectiveServiceTier();
|
|
468
|
+
|
|
463
469
|
ctx.ui.setWidget("gsd-progress", (tui, theme) => {
|
|
464
470
|
let pulseBright = true;
|
|
465
471
|
let cachedLines: string[] | undefined;
|
|
@@ -572,9 +578,10 @@ export function updateProgressWidget(
|
|
|
572
578
|
// Model display — shown in context section, not stats
|
|
573
579
|
const modelId = cmdCtx?.model?.id ?? "";
|
|
574
580
|
const modelProvider = cmdCtx?.model?.provider ?? "";
|
|
575
|
-
const
|
|
581
|
+
const tierIcon = resolveServiceTierIcon(effectiveServiceTier, modelId);
|
|
582
|
+
const modelDisplay = (modelProvider && modelId
|
|
576
583
|
? `${modelProvider}/${modelId}`
|
|
577
|
-
: modelId;
|
|
584
|
+
: modelId) + (tierIcon ? ` ${tierIcon}` : "");
|
|
578
585
|
|
|
579
586
|
// ── Mode: off — return empty ──────────────────────────────────
|
|
580
587
|
if (widgetMode === "off") {
|
|
@@ -54,9 +54,11 @@ export type DispatchAction =
|
|
|
54
54
|
unitId: string;
|
|
55
55
|
prompt: string;
|
|
56
56
|
pauseAfterDispatch?: boolean;
|
|
57
|
+
/** Name of the matched dispatch rule from the unified registry (journal provenance). */
|
|
58
|
+
matchedRule?: string;
|
|
57
59
|
}
|
|
58
|
-
| { action: "stop"; reason: string; level: "info" | "warning" | "error" }
|
|
59
|
-
| { action: "skip" };
|
|
60
|
+
| { action: "stop"; reason: string; level: "info" | "warning" | "error"; matchedRule?: string }
|
|
61
|
+
| { action: "skip"; matchedRule?: string };
|
|
60
62
|
|
|
61
63
|
export interface DispatchContext {
|
|
62
64
|
basePath: string;
|
|
@@ -67,7 +69,7 @@ export interface DispatchContext {
|
|
|
67
69
|
session?: import("./auto/session.js").AutoSession;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
interface DispatchRule {
|
|
72
|
+
export interface DispatchRule {
|
|
71
73
|
/** Human-readable name for debugging and test identification */
|
|
72
74
|
name: string;
|
|
73
75
|
/** Return a DispatchAction if this rule matches, null to fall through */
|
|
@@ -88,7 +90,7 @@ const MAX_REWRITE_ATTEMPTS = 3;
|
|
|
88
90
|
|
|
89
91
|
// ─── Rules ────────────────────────────────────────────────────────────────
|
|
90
92
|
|
|
91
|
-
const DISPATCH_RULES: DispatchRule[] = [
|
|
93
|
+
export const DISPATCH_RULES: DispatchRule[] = [
|
|
92
94
|
{
|
|
93
95
|
name: "rewrite-docs (override gate)",
|
|
94
96
|
match: async ({ mid, midTitle, state, basePath, session }) => {
|
|
@@ -608,18 +610,35 @@ const DISPATCH_RULES: DispatchRule[] = [
|
|
|
608
610
|
},
|
|
609
611
|
];
|
|
610
612
|
|
|
613
|
+
import { getRegistry } from "./rule-registry.js";
|
|
614
|
+
|
|
611
615
|
// ─── Resolver ─────────────────────────────────────────────────────────────
|
|
612
616
|
|
|
613
617
|
/**
|
|
614
618
|
* Evaluate dispatch rules in order. Returns the first matching action,
|
|
615
619
|
* or a "stop" action if no rule matches (unhandled phase).
|
|
620
|
+
*
|
|
621
|
+
* Delegates to the RuleRegistry when initialized; falls back to inline
|
|
622
|
+
* loop over DISPATCH_RULES for backward compatibility (tests that import
|
|
623
|
+
* resolveDispatch directly without registry initialization).
|
|
616
624
|
*/
|
|
617
625
|
export async function resolveDispatch(
|
|
618
626
|
ctx: DispatchContext,
|
|
619
627
|
): Promise<DispatchAction> {
|
|
628
|
+
// Delegate to registry when available
|
|
629
|
+
try {
|
|
630
|
+
const registry = getRegistry();
|
|
631
|
+
return await registry.evaluateDispatch(ctx);
|
|
632
|
+
} catch {
|
|
633
|
+
// Registry not initialized — fall back to inline loop
|
|
634
|
+
}
|
|
635
|
+
|
|
620
636
|
for (const rule of DISPATCH_RULES) {
|
|
621
637
|
const result = await rule.match(ctx);
|
|
622
|
-
if (result)
|
|
638
|
+
if (result) {
|
|
639
|
+
if (result.action !== "skip") result.matchedRule = rule.name;
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
623
642
|
}
|
|
624
643
|
|
|
625
644
|
// No rule matched — unhandled phase
|
|
@@ -627,6 +646,7 @@ export async function resolveDispatch(
|
|
|
627
646
|
action: "stop",
|
|
628
647
|
reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
|
|
629
648
|
level: "info",
|
|
649
|
+
matchedRule: "<no-match>",
|
|
630
650
|
};
|
|
631
651
|
}
|
|
632
652
|
|
|
@@ -59,6 +59,7 @@ import { existsSync, unlinkSync } from "node:fs";
|
|
|
59
59
|
import { join } from "node:path";
|
|
60
60
|
import { uncheckTaskInPlan } from "./undo.js";
|
|
61
61
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
62
|
+
import { _resetHasChangesCache } from "./native-git-bridge.js";
|
|
62
63
|
|
|
63
64
|
/** Throttle STATE.md rebuilds — at most once per 30 seconds */
|
|
64
65
|
const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
@@ -156,6 +157,13 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
// Invalidate the nativeHasChanges cache before auto-commit (#1853).
|
|
161
|
+
// The cache has a 10-second TTL and is keyed by basePath. A stale
|
|
162
|
+
// `false` result causes autoCommit to skip staging entirely, leaving
|
|
163
|
+
// code files only in the working tree where they are destroyed by
|
|
164
|
+
// `git worktree remove --force` during teardown.
|
|
165
|
+
_resetHasChangesCache();
|
|
166
|
+
|
|
159
167
|
const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
|
|
160
168
|
if (commitMsg) {
|
|
161
169
|
ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
|
|
@@ -319,10 +319,15 @@ export function verifyExpectedArtifact(
|
|
|
319
319
|
// plan has no tasks, creating an infinite skip loop (#699).
|
|
320
320
|
if (unitType === "plan-slice") {
|
|
321
321
|
const planContent = readFileSync(absPath, "utf-8");
|
|
322
|
-
|
|
322
|
+
// Accept checkbox-style (- [x] **T01: ...) or heading-style (### T01 -- / ### T01: / ### T01 —)
|
|
323
|
+
const hasCheckboxTask = /^- \[[xX ]\] \*\*T\d+:/m.test(planContent);
|
|
324
|
+
const hasHeadingTask = /^#{2,4}\s+T\d+\s*(?:--|—|:)/m.test(planContent);
|
|
325
|
+
if (!hasCheckboxTask && !hasHeadingTask) return false;
|
|
323
326
|
}
|
|
324
327
|
|
|
325
|
-
// execute-task must also have its checkbox marked [x] in the slice plan
|
|
328
|
+
// execute-task must also have its checkbox marked [x] in the slice plan.
|
|
329
|
+
// Heading-style plans (### T01 -- Title) have no checkbox — the task summary
|
|
330
|
+
// file existence (checked above via resolveExpectedArtifactPath) is sufficient.
|
|
326
331
|
if (unitType === "execute-task") {
|
|
327
332
|
const parts = unitId.split("/");
|
|
328
333
|
const mid = parts[0];
|
|
@@ -333,8 +338,11 @@ export function verifyExpectedArtifact(
|
|
|
333
338
|
if (planAbs && existsSync(planAbs)) {
|
|
334
339
|
const planContent = readFileSync(planAbs, "utf-8");
|
|
335
340
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
336
|
-
const
|
|
337
|
-
|
|
341
|
+
const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
|
|
342
|
+
const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
|
|
343
|
+
// Heading-style entries count as verified (no checkbox to toggle);
|
|
344
|
+
// checkbox-style entries require [x].
|
|
345
|
+
if (!cbRe.test(planContent) && !hdRe.test(planContent)) return false;
|
|
338
346
|
}
|
|
339
347
|
}
|
|
340
348
|
}
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveSkillDiscoveryMode,
|
|
21
21
|
getIsolationMode,
|
|
22
22
|
} from "./preferences.js";
|
|
23
|
-
import { ensureGsdSymlink, validateProjectId } from "./repo-identity.js";
|
|
23
|
+
import { ensureGsdSymlink, isInheritedRepo, validateProjectId } from "./repo-identity.js";
|
|
24
24
|
import { migrateToExternalState, recoverFailedMigration } from "./migrate-external.js";
|
|
25
25
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
26
26
|
import { gsdRoot, resolveMilestoneFile, milestonesDir } from "./paths.js";
|
|
@@ -140,8 +140,13 @@ export async function bootstrapAutoSession(
|
|
|
140
140
|
return releaseLockAndReturn();
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
// Ensure git repo exists
|
|
144
|
-
if
|
|
143
|
+
// Ensure git repo exists.
|
|
144
|
+
// Guard against inherited repos: if `base` is a subdirectory of another
|
|
145
|
+
// git repo that has no .gsd (i.e. the parent project was never initialised
|
|
146
|
+
// with GSD), create a fresh git repo at `base` so it gets its own identity
|
|
147
|
+
// hash. Without this, repoIdentity() resolves to the parent repo's hash
|
|
148
|
+
// and loads milestones from an unrelated project (#1639).
|
|
149
|
+
if (!nativeIsRepo(base) || isInheritedRepo(base)) {
|
|
145
150
|
const mainBranch =
|
|
146
151
|
loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
147
152
|
nativeInit(base, mainBranch);
|