@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262
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/dist/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/index.js +39 -22
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +43 -10
- package/dist/resources/extensions/gsd/auto/session.js +20 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
- package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +14 -11
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +110 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- 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 +1 -1
- 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/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 +8 -8
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +23 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +25 -24
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +39 -22
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +42 -10
- package/src/resources/extensions/gsd/auto/session.ts +22 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +112 -43
- package/src/resources/extensions/gsd/preferences-types.ts +39 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +28 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
openDatabase,
|
|
25
25
|
closeDatabase,
|
|
26
26
|
_getAdapter,
|
|
27
|
+
SCHEMA_VERSION,
|
|
27
28
|
} from '../gsd-db.ts';
|
|
28
29
|
|
|
29
30
|
const _require = createRequire(import.meta.url);
|
|
@@ -403,9 +404,10 @@ test('schema v21 migration: upgrading from v20 lands on current SCHEMA_VERSION',
|
|
|
403
404
|
// The DB must reach the current SCHEMA_VERSION. If the v21 block was
|
|
404
405
|
// skipped (as it would be when SCHEMA_VERSION was still 20), this
|
|
405
406
|
// assertion catches it.
|
|
406
|
-
assert.
|
|
407
|
-
maxVersion
|
|
408
|
-
|
|
407
|
+
assert.equal(
|
|
408
|
+
maxVersion,
|
|
409
|
+
SCHEMA_VERSION,
|
|
410
|
+
`DB upgraded from v20 must reach schema version ${SCHEMA_VERSION}; got ${maxVersion}`,
|
|
409
411
|
);
|
|
410
412
|
} finally {
|
|
411
413
|
cleanup(base);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
// gsd-pi / V27 + V28 schema migration regression tests
|
|
1
|
+
// gsd-pi / V27 + V28 + V29 schema migration regression tests
|
|
2
2
|
//
|
|
3
3
|
// Same bug class as #4591 (schema-v21-sequence): a migration block can be
|
|
4
4
|
// added but the SCHEMA_VERSION constant left unchanged, causing fresh-install
|
|
5
|
-
// + upgrade paths to silently skip the column add. This file pins
|
|
6
|
-
// (artifacts.content_hash)
|
|
7
|
-
// write-path level
|
|
5
|
+
// + upgrade paths to silently skip the column add. This file pins V27
|
|
6
|
+
// (artifacts.content_hash), V28 (memories.last_hit_at), and V29
|
|
7
|
+
// (target_repositories) at the schema/write-path level.
|
|
8
8
|
|
|
9
9
|
import test from "node:test";
|
|
10
10
|
import assert from "node:assert/strict";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import * as os from "node:os";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
14
15
|
|
|
15
16
|
import {
|
|
16
17
|
openDatabase,
|
|
@@ -22,8 +23,10 @@ import {
|
|
|
22
23
|
SCHEMA_VERSION,
|
|
23
24
|
} from "../gsd-db.ts";
|
|
24
25
|
|
|
26
|
+
const _require = createRequire(import.meta.url);
|
|
27
|
+
|
|
25
28
|
function makeTmp(): string {
|
|
26
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), "gsd-
|
|
29
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "gsd-v27v29-"));
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
function cleanup(base: string): void {
|
|
@@ -31,10 +34,114 @@ function cleanup(base: string): void {
|
|
|
31
34
|
try { fs.rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
function columnNames(table: string): Set<string> {
|
|
38
|
+
const db = _getAdapter()!;
|
|
39
|
+
const cols = db.prepare(`PRAGMA table_info(${table})`).all() as Array<Record<string, unknown>>;
|
|
40
|
+
return new Set(cols.map((c) => c["name"] as string));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createV28Db(dbPath: string): void {
|
|
44
|
+
const sqlite = _require("node:sqlite") as {
|
|
45
|
+
DatabaseSync: new (p: string) => {
|
|
46
|
+
exec(sql: string): void;
|
|
47
|
+
close(): void;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const db = new sqlite.DatabaseSync(dbPath);
|
|
51
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
52
|
+
db.exec(`
|
|
53
|
+
CREATE TABLE schema_version (
|
|
54
|
+
version INTEGER NOT NULL,
|
|
55
|
+
applied_at TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
INSERT INTO schema_version (version, applied_at) VALUES (28, '2026-01-01T00:00:00.000Z');
|
|
58
|
+
|
|
59
|
+
CREATE TABLE milestones (
|
|
60
|
+
id TEXT PRIMARY KEY,
|
|
61
|
+
title TEXT NOT NULL DEFAULT '',
|
|
62
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
63
|
+
depends_on TEXT NOT NULL DEFAULT '[]',
|
|
64
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
65
|
+
completed_at TEXT DEFAULT NULL,
|
|
66
|
+
vision TEXT NOT NULL DEFAULT '',
|
|
67
|
+
success_criteria TEXT NOT NULL DEFAULT '[]',
|
|
68
|
+
key_risks TEXT NOT NULL DEFAULT '[]',
|
|
69
|
+
proof_strategy TEXT NOT NULL DEFAULT '[]',
|
|
70
|
+
verification_contract TEXT NOT NULL DEFAULT '',
|
|
71
|
+
verification_integration TEXT NOT NULL DEFAULT '',
|
|
72
|
+
verification_operational TEXT NOT NULL DEFAULT '',
|
|
73
|
+
verification_uat TEXT NOT NULL DEFAULT '',
|
|
74
|
+
definition_of_done TEXT NOT NULL DEFAULT '[]',
|
|
75
|
+
requirement_coverage TEXT NOT NULL DEFAULT '',
|
|
76
|
+
boundary_map_markdown TEXT NOT NULL DEFAULT '',
|
|
77
|
+
sequence INTEGER DEFAULT 0
|
|
78
|
+
);
|
|
79
|
+
CREATE TABLE slices (
|
|
80
|
+
milestone_id TEXT NOT NULL,
|
|
81
|
+
id TEXT NOT NULL,
|
|
82
|
+
title TEXT NOT NULL DEFAULT '',
|
|
83
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
84
|
+
risk TEXT NOT NULL DEFAULT 'medium',
|
|
85
|
+
depends TEXT NOT NULL DEFAULT '[]',
|
|
86
|
+
demo TEXT NOT NULL DEFAULT '',
|
|
87
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
88
|
+
completed_at TEXT DEFAULT NULL,
|
|
89
|
+
full_summary_md TEXT NOT NULL DEFAULT '',
|
|
90
|
+
full_uat_md TEXT NOT NULL DEFAULT '',
|
|
91
|
+
goal TEXT NOT NULL DEFAULT '',
|
|
92
|
+
success_criteria TEXT NOT NULL DEFAULT '',
|
|
93
|
+
proof_level TEXT NOT NULL DEFAULT '',
|
|
94
|
+
integration_closure TEXT NOT NULL DEFAULT '',
|
|
95
|
+
observability_impact TEXT NOT NULL DEFAULT '',
|
|
96
|
+
sequence INTEGER DEFAULT 0,
|
|
97
|
+
replan_triggered_at TEXT DEFAULT NULL,
|
|
98
|
+
is_sketch INTEGER NOT NULL DEFAULT 0,
|
|
99
|
+
sketch_scope TEXT NOT NULL DEFAULT '',
|
|
100
|
+
PRIMARY KEY (milestone_id, id),
|
|
101
|
+
FOREIGN KEY (milestone_id) REFERENCES milestones(id)
|
|
102
|
+
);
|
|
103
|
+
CREATE TABLE tasks (
|
|
104
|
+
milestone_id TEXT NOT NULL,
|
|
105
|
+
slice_id TEXT NOT NULL,
|
|
106
|
+
id TEXT NOT NULL,
|
|
107
|
+
title TEXT NOT NULL DEFAULT '',
|
|
108
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
109
|
+
one_liner TEXT NOT NULL DEFAULT '',
|
|
110
|
+
narrative TEXT NOT NULL DEFAULT '',
|
|
111
|
+
verification_result TEXT NOT NULL DEFAULT '',
|
|
112
|
+
duration TEXT NOT NULL DEFAULT '',
|
|
113
|
+
completed_at TEXT DEFAULT NULL,
|
|
114
|
+
blocker_discovered INTEGER DEFAULT 0,
|
|
115
|
+
blocker_source TEXT NOT NULL DEFAULT '',
|
|
116
|
+
escalation_pending INTEGER NOT NULL DEFAULT 0,
|
|
117
|
+
escalation_awaiting_review INTEGER NOT NULL DEFAULT 0,
|
|
118
|
+
escalation_artifact_path TEXT DEFAULT NULL,
|
|
119
|
+
escalation_override_applied_at TEXT DEFAULT NULL,
|
|
120
|
+
deviations TEXT NOT NULL DEFAULT '',
|
|
121
|
+
known_issues TEXT NOT NULL DEFAULT '',
|
|
122
|
+
key_files TEXT NOT NULL DEFAULT '[]',
|
|
123
|
+
key_decisions TEXT NOT NULL DEFAULT '[]',
|
|
124
|
+
full_summary_md TEXT NOT NULL DEFAULT '',
|
|
125
|
+
description TEXT NOT NULL DEFAULT '',
|
|
126
|
+
estimate TEXT NOT NULL DEFAULT '',
|
|
127
|
+
files TEXT NOT NULL DEFAULT '[]',
|
|
128
|
+
verify TEXT NOT NULL DEFAULT '',
|
|
129
|
+
inputs TEXT NOT NULL DEFAULT '[]',
|
|
130
|
+
expected_output TEXT NOT NULL DEFAULT '[]',
|
|
131
|
+
observability_impact TEXT NOT NULL DEFAULT '',
|
|
132
|
+
full_plan_md TEXT NOT NULL DEFAULT '',
|
|
133
|
+
sequence INTEGER DEFAULT 0,
|
|
134
|
+
PRIMARY KEY (milestone_id, slice_id, id),
|
|
135
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
136
|
+
);
|
|
137
|
+
`);
|
|
138
|
+
db.close();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
test("SCHEMA_VERSION constant is at least 29 (V29 migration committed)", () => {
|
|
35
142
|
assert.ok(
|
|
36
|
-
SCHEMA_VERSION >=
|
|
37
|
-
`SCHEMA_VERSION must be ≥
|
|
143
|
+
SCHEMA_VERSION >= 29,
|
|
144
|
+
`SCHEMA_VERSION must be ≥ 29 after V29 migration; got ${SCHEMA_VERSION}`,
|
|
38
145
|
);
|
|
39
146
|
});
|
|
40
147
|
|
|
@@ -43,11 +150,8 @@ test("fresh-install DB has artifacts.content_hash column (V27)", () => {
|
|
|
43
150
|
const dbPath = path.join(base, "gsd.db");
|
|
44
151
|
try {
|
|
45
152
|
openDatabase(dbPath);
|
|
46
|
-
const db = _getAdapter()!;
|
|
47
|
-
const cols = db.prepare("PRAGMA table_info(artifacts)").all() as Array<Record<string, unknown>>;
|
|
48
|
-
const colNames = new Set(cols.map((c) => c["name"] as string));
|
|
49
153
|
assert.ok(
|
|
50
|
-
|
|
154
|
+
columnNames("artifacts").has("content_hash"),
|
|
51
155
|
"V27 must add content_hash column to artifacts on fresh install",
|
|
52
156
|
);
|
|
53
157
|
} finally {
|
|
@@ -60,11 +164,8 @@ test("fresh-install DB has memories.last_hit_at column (V28)", () => {
|
|
|
60
164
|
const dbPath = path.join(base, "gsd.db");
|
|
61
165
|
try {
|
|
62
166
|
openDatabase(dbPath);
|
|
63
|
-
const db = _getAdapter()!;
|
|
64
|
-
const cols = db.prepare("PRAGMA table_info(memories)").all() as Array<Record<string, unknown>>;
|
|
65
|
-
const colNames = new Set(cols.map((c) => c["name"] as string));
|
|
66
167
|
assert.ok(
|
|
67
|
-
|
|
168
|
+
columnNames("memories").has("last_hit_at"),
|
|
68
169
|
"V28 must add last_hit_at column to memories on fresh install",
|
|
69
170
|
);
|
|
70
171
|
} finally {
|
|
@@ -72,15 +173,58 @@ test("fresh-install DB has memories.last_hit_at column (V28)", () => {
|
|
|
72
173
|
}
|
|
73
174
|
});
|
|
74
175
|
|
|
75
|
-
test("fresh-install DB
|
|
176
|
+
test("fresh-install DB has target_repositories columns (V29)", () => {
|
|
76
177
|
const base = makeTmp();
|
|
77
178
|
const dbPath = path.join(base, "gsd.db");
|
|
78
179
|
try {
|
|
79
180
|
openDatabase(dbPath);
|
|
181
|
+
assert.ok(
|
|
182
|
+
columnNames("slices").has("target_repositories"),
|
|
183
|
+
"V29 must add target_repositories column to slices on fresh install",
|
|
184
|
+
);
|
|
185
|
+
assert.ok(
|
|
186
|
+
columnNames("tasks").has("target_repositories"),
|
|
187
|
+
"V29 must add target_repositories column to tasks on fresh install",
|
|
188
|
+
);
|
|
189
|
+
} finally {
|
|
190
|
+
cleanup(base);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("fresh-install DB stamps current SCHEMA_VERSION in schema_version table", () => {
|
|
195
|
+
const base = makeTmp();
|
|
196
|
+
const dbPath = path.join(base, "gsd.db");
|
|
197
|
+
try {
|
|
198
|
+
openDatabase(dbPath);
|
|
199
|
+
const db = _getAdapter()!;
|
|
200
|
+
const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get() as Record<string, unknown> | undefined;
|
|
201
|
+
const max = (row?.["v"] as number) ?? 0;
|
|
202
|
+
assert.equal(max, SCHEMA_VERSION, `fresh install must record schema_version ${SCHEMA_VERSION}; got ${max}`);
|
|
203
|
+
} finally {
|
|
204
|
+
cleanup(base);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("upgrading from V28 adds target_repositories and stamps V29", () => {
|
|
209
|
+
const base = makeTmp();
|
|
210
|
+
const dbPath = path.join(base, "gsd.db");
|
|
211
|
+
createV28Db(dbPath);
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
openDatabase(dbPath);
|
|
215
|
+
assert.ok(
|
|
216
|
+
columnNames("slices").has("target_repositories"),
|
|
217
|
+
"V29 migration must add target_repositories column to existing slices table",
|
|
218
|
+
);
|
|
219
|
+
assert.ok(
|
|
220
|
+
columnNames("tasks").has("target_repositories"),
|
|
221
|
+
"V29 migration must add target_repositories column to existing tasks table",
|
|
222
|
+
);
|
|
223
|
+
|
|
80
224
|
const db = _getAdapter()!;
|
|
81
225
|
const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get() as Record<string, unknown> | undefined;
|
|
82
226
|
const max = (row?.["v"] as number) ?? 0;
|
|
83
|
-
assert.
|
|
227
|
+
assert.equal(max, SCHEMA_VERSION, `V28 DB must upgrade to schema_version ${SCHEMA_VERSION}; got ${max}`);
|
|
84
228
|
} finally {
|
|
85
229
|
cleanup(base);
|
|
86
230
|
}
|
|
@@ -7,6 +7,8 @@ import { tmpdir } from "node:os";
|
|
|
7
7
|
import { DISPATCH_RULES } from "../auto-dispatch.ts";
|
|
8
8
|
import {
|
|
9
9
|
closeDatabase,
|
|
10
|
+
getArtifact,
|
|
11
|
+
getAssessment,
|
|
10
12
|
getLatestAssessmentByScope,
|
|
11
13
|
insertMilestone,
|
|
12
14
|
insertSlice,
|
|
@@ -46,6 +48,12 @@ test("skipped validation dispatch persists the validation file and DB assessment
|
|
|
46
48
|
|
|
47
49
|
assert.deepEqual(action, { action: "skip" });
|
|
48
50
|
assert.equal(existsSync(join(milestoneDir, "M001-VALIDATION.md")), true);
|
|
51
|
+
assert.equal(existsSync(join(sliceDir, "S01-ASSESSMENT.md")), true);
|
|
52
|
+
const artifactPath = "milestones/M001/slices/S01/S01-ASSESSMENT.md";
|
|
53
|
+
const assessmentPath = `.gsd/${artifactPath}`;
|
|
54
|
+
assert.equal(getArtifact(artifactPath)?.artifact_type, "ASSESSMENT");
|
|
55
|
+
assert.equal(getAssessment(assessmentPath)?.scope, "run-uat");
|
|
56
|
+
assert.equal(getAssessment(assessmentPath)?.status, "pass");
|
|
49
57
|
assert.equal(
|
|
50
58
|
getLatestAssessmentByScope("M001", "milestone-validation")?.status,
|
|
51
59
|
"pass",
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
SourceObservationStore,
|
|
9
|
+
injectSourceContextBlockIntoPayload,
|
|
10
|
+
observeSourcePath,
|
|
11
|
+
planDeclaredSourceEntries,
|
|
12
|
+
} from "../source-observations.js";
|
|
13
|
+
import { AutoSession } from "../auto/session.js";
|
|
14
|
+
import { truncateContextResultMessages, truncateResponsesInputResultItems } from "../context-masker.js";
|
|
15
|
+
import type { TaskRow } from "../db-task-slice-rows.js";
|
|
16
|
+
|
|
17
|
+
function makeTask(overrides: Partial<TaskRow> = {}): TaskRow {
|
|
18
|
+
return {
|
|
19
|
+
milestone_id: "M001",
|
|
20
|
+
slice_id: "S01",
|
|
21
|
+
id: "T01",
|
|
22
|
+
title: "Task",
|
|
23
|
+
status: "pending",
|
|
24
|
+
one_liner: "",
|
|
25
|
+
narrative: "",
|
|
26
|
+
verification_result: "",
|
|
27
|
+
duration: "",
|
|
28
|
+
completed_at: null,
|
|
29
|
+
blocker_discovered: false,
|
|
30
|
+
deviations: "",
|
|
31
|
+
known_issues: "",
|
|
32
|
+
key_files: [],
|
|
33
|
+
key_decisions: [],
|
|
34
|
+
full_summary_md: "",
|
|
35
|
+
description: "",
|
|
36
|
+
estimate: "",
|
|
37
|
+
files: [],
|
|
38
|
+
verify: "",
|
|
39
|
+
inputs: [],
|
|
40
|
+
expected_output: [],
|
|
41
|
+
observability_impact: "",
|
|
42
|
+
full_plan_md: "",
|
|
43
|
+
sequence: 1,
|
|
44
|
+
blocker_source: "",
|
|
45
|
+
escalation_pending: 0,
|
|
46
|
+
escalation_awaiting_review: 0,
|
|
47
|
+
escalation_artifact_path: null,
|
|
48
|
+
escalation_override_applied_at: null,
|
|
49
|
+
...overrides,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function tempProject(): string {
|
|
54
|
+
return mkdtempSync(join(tmpdir(), "gsd-source-observations-"));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function beginStore(basePath: string): SourceObservationStore {
|
|
58
|
+
const store = new SourceObservationStore();
|
|
59
|
+
store.beginUnit({ unitType: "execute-task", unitId: "M001/S01/T01", startedAt: 123, basePath });
|
|
60
|
+
return store;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("plan-declared source entries use task.files and concrete task.inputs, not expectedOutput", () => {
|
|
64
|
+
const task = makeTask({
|
|
65
|
+
files: ["src/app.ts"],
|
|
66
|
+
inputs: ["Current enum shape", "`src/input.ts` - existing input"],
|
|
67
|
+
expected_output: ["src/generated.ts"],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
assert.deepEqual(planDeclaredSourceEntries(task), [
|
|
71
|
+
{ path: "src/app.ts", field: "files" },
|
|
72
|
+
{ path: "src/input.ts", field: "inputs" },
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("preloaded plan observations render whole files and unavailable statuses", () => {
|
|
77
|
+
const basePath = tempProject();
|
|
78
|
+
mkdirSync(join(basePath, "src"), { recursive: true });
|
|
79
|
+
writeFileSync(join(basePath, "src", "app.ts"), "export const value = 1;\n");
|
|
80
|
+
mkdirSync(join(basePath, "src", "directory"), { recursive: true });
|
|
81
|
+
writeFileSync(join(basePath, "image.png"), Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
|
|
82
|
+
|
|
83
|
+
const store = beginStore(basePath);
|
|
84
|
+
store.observePlanTask(makeTask({
|
|
85
|
+
files: [
|
|
86
|
+
"src/app.ts",
|
|
87
|
+
"src/missing.ts",
|
|
88
|
+
"src/*.ts",
|
|
89
|
+
"src/directory/",
|
|
90
|
+
"image.png",
|
|
91
|
+
],
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
const block = store.renderActiveBlock();
|
|
95
|
+
assert.ok(block);
|
|
96
|
+
assert.match(block, /## Source Context Block/);
|
|
97
|
+
assert.match(block, /#### src\/app\.ts/);
|
|
98
|
+
assert.match(block, /export const value = 1;/);
|
|
99
|
+
assert.match(block, /src\/missing\.ts: missing/);
|
|
100
|
+
assert.match(block, /src\/\*\.ts: glob/);
|
|
101
|
+
assert.match(block, /src\/directory: directory/);
|
|
102
|
+
assert.match(block, /image\.png: binary\/image/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("narrow reads of under-threshold files auto-upgrade to whole-file observations", () => {
|
|
106
|
+
const basePath = tempProject();
|
|
107
|
+
mkdirSync(join(basePath, "src"), { recursive: true });
|
|
108
|
+
writeFileSync(join(basePath, "src", "app.ts"), ["line one", "line two", "line three"].join("\n"));
|
|
109
|
+
|
|
110
|
+
const store = beginStore(basePath);
|
|
111
|
+
store.observeRead({ path: "src/app.ts", offset: 2, limit: 1 });
|
|
112
|
+
|
|
113
|
+
const block = store.renderActiveBlock();
|
|
114
|
+
assert.ok(block);
|
|
115
|
+
assert.match(block, /line one/);
|
|
116
|
+
assert.match(block, /line two/);
|
|
117
|
+
assert.match(block, /line three/);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("successful file mutations refresh active whole-file observations", () => {
|
|
121
|
+
const basePath = tempProject();
|
|
122
|
+
writeFileSync(join(basePath, "app.ts"), "export const value = 'before';\n");
|
|
123
|
+
|
|
124
|
+
const store = beginStore(basePath);
|
|
125
|
+
store.observeRead({ path: "app.ts" });
|
|
126
|
+
|
|
127
|
+
assert.match(store.renderActiveBlock() ?? "", /before/);
|
|
128
|
+
|
|
129
|
+
writeFileSync(join(basePath, "app.ts"), "export const value = 'after';\n");
|
|
130
|
+
store.observeMutation({ path: "app.ts" });
|
|
131
|
+
|
|
132
|
+
const block = store.renderActiveBlock() ?? "";
|
|
133
|
+
assert.match(block, /after/);
|
|
134
|
+
assert.doesNotMatch(block, /before/);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("successful writes promote missing plan observations to whole files", () => {
|
|
138
|
+
const basePath = tempProject();
|
|
139
|
+
const store = beginStore(basePath);
|
|
140
|
+
store.observePlanTask(makeTask({ files: ["generated.ts"] }));
|
|
141
|
+
|
|
142
|
+
assert.match(store.renderActiveBlock() ?? "", /generated\.ts: missing/);
|
|
143
|
+
|
|
144
|
+
writeFileSync(join(basePath, "generated.ts"), "export const generated = true;\n");
|
|
145
|
+
store.observeMutation({ path: "generated.ts" });
|
|
146
|
+
|
|
147
|
+
const block = store.renderActiveBlock() ?? "";
|
|
148
|
+
assert.match(block, /#### generated\.ts/);
|
|
149
|
+
assert.match(block, /export const generated = true;/);
|
|
150
|
+
assert.doesNotMatch(block, /generated\.ts: missing/);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("over-threshold files are explicit unavailable observations", () => {
|
|
154
|
+
const basePath = tempProject();
|
|
155
|
+
writeFileSync(join(basePath, "large.txt"), "a".repeat(51 * 1024));
|
|
156
|
+
|
|
157
|
+
const observation = observeSourcePath(basePath, "large.txt", "plan");
|
|
158
|
+
|
|
159
|
+
assert.equal(observation.status, "over-threshold");
|
|
160
|
+
assert.match(observation.reason ?? "", /exceeds/);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("outside-root paths are unavailable and never inlined", () => {
|
|
164
|
+
const root = tempProject();
|
|
165
|
+
const basePath = join(root, "project");
|
|
166
|
+
const outsidePath = join(root, "outside");
|
|
167
|
+
mkdirSync(basePath, { recursive: true });
|
|
168
|
+
mkdirSync(outsidePath, { recursive: true });
|
|
169
|
+
writeFileSync(join(outsidePath, "secret.txt"), "do not inline me\n");
|
|
170
|
+
|
|
171
|
+
const absoluteObservation = observeSourcePath(basePath, join(outsidePath, "secret.txt"), "read");
|
|
172
|
+
const relativeObservation = observeSourcePath(basePath, "../outside/secret.txt", "read");
|
|
173
|
+
|
|
174
|
+
assert.equal(absoluteObservation.status, "unresolved selector");
|
|
175
|
+
assert.equal(relativeObservation.status, "unresolved selector");
|
|
176
|
+
assert.match(absoluteObservation.reason ?? "", /outside active Unit root/);
|
|
177
|
+
assert.match(relativeObservation.reason ?? "", /outside active Unit root/);
|
|
178
|
+
assert.equal(absoluteObservation.text, undefined);
|
|
179
|
+
assert.equal(relativeObservation.text, undefined);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("source observations only render for execute-task units", () => {
|
|
183
|
+
const basePath = tempProject();
|
|
184
|
+
writeFileSync(join(basePath, "plan.md"), "planning context\n");
|
|
185
|
+
|
|
186
|
+
const store = new SourceObservationStore();
|
|
187
|
+
store.beginUnit({ unitType: "plan-slice", unitId: "M001/S01", startedAt: 123, basePath });
|
|
188
|
+
store.observeRead({ path: "plan.md" });
|
|
189
|
+
|
|
190
|
+
assert.equal(store.renderActiveBlock(), null);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("source context block injection survives tool-result truncation for messages payloads", () => {
|
|
194
|
+
const payload = {
|
|
195
|
+
messages: truncateContextResultMessages([
|
|
196
|
+
{ role: "toolResult", content: [{ type: "text", text: "x".repeat(200) }], toolCallId: "read-1", toolName: "read", isError: false },
|
|
197
|
+
] as any, 10),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const injected = injectSourceContextBlockIntoPayload(payload, "## Source Context Block\n\nfull source text");
|
|
201
|
+
|
|
202
|
+
assert.match((injected.messages as any[])[0].content[0].text, /truncated/);
|
|
203
|
+
assert.equal((injected.messages as any[])[1].content[0].text, "## Source Context Block\n\nfull source text");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("source context block injection supports Responses input payloads", () => {
|
|
207
|
+
const payload = {
|
|
208
|
+
input: truncateResponsesInputResultItems([
|
|
209
|
+
{ type: "function_call_output", call_id: "read-1", output: "x".repeat(200) },
|
|
210
|
+
] as any, 10),
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const injected = injectSourceContextBlockIntoPayload(payload, "## Source Context Block\n\nfull source text");
|
|
214
|
+
|
|
215
|
+
assert.match((injected.input as any[])[0].output, /truncated/);
|
|
216
|
+
assert.equal((injected.input as any[])[1].content[0].text, "## Source Context Block\n\nfull source text");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("unit-close degradation removes active whole-file source text", () => {
|
|
220
|
+
const basePath = tempProject();
|
|
221
|
+
writeFileSync(join(basePath, "app.ts"), "export const value = 1;");
|
|
222
|
+
const store = beginStore(basePath);
|
|
223
|
+
store.observeRead({ path: "app.ts" });
|
|
224
|
+
|
|
225
|
+
assert.match(store.renderActiveBlock() ?? "", /export const value = 1/);
|
|
226
|
+
|
|
227
|
+
store.degradeUnit({ unitType: "execute-task", unitId: "M001/S01/T01", startedAt: 123 });
|
|
228
|
+
|
|
229
|
+
assert.equal(store.renderActiveBlock(), null);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("AutoSession current-unit clear removes active source observations", () => {
|
|
233
|
+
const basePath = tempProject();
|
|
234
|
+
writeFileSync(join(basePath, "app.ts"), "export const value = 1;");
|
|
235
|
+
const session = new AutoSession();
|
|
236
|
+
session.basePath = basePath;
|
|
237
|
+
session.setCurrentUnit({
|
|
238
|
+
type: "execute-task",
|
|
239
|
+
id: "M001/S01/T01",
|
|
240
|
+
startedAt: 123,
|
|
241
|
+
workspaceRoot: basePath,
|
|
242
|
+
});
|
|
243
|
+
session.sourceObservations.observeRead({ path: "app.ts" });
|
|
244
|
+
|
|
245
|
+
assert.match(session.sourceObservations.renderActiveBlock() ?? "", /export const value = 1/);
|
|
246
|
+
|
|
247
|
+
session.clearCurrentUnit();
|
|
248
|
+
|
|
249
|
+
assert.equal(session.sourceObservations.renderActiveBlock(), null);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("AutoSession clears source observations when switching to non-execute units", () => {
|
|
253
|
+
const basePath = tempProject();
|
|
254
|
+
writeFileSync(join(basePath, "app.ts"), "export const value = 1;");
|
|
255
|
+
const session = new AutoSession();
|
|
256
|
+
session.basePath = basePath;
|
|
257
|
+
session.setCurrentUnit({
|
|
258
|
+
type: "execute-task",
|
|
259
|
+
id: "M001/S01/T01",
|
|
260
|
+
startedAt: 123,
|
|
261
|
+
workspaceRoot: basePath,
|
|
262
|
+
});
|
|
263
|
+
session.sourceObservations.observeRead({ path: "app.ts" });
|
|
264
|
+
|
|
265
|
+
assert.match(session.sourceObservations.renderActiveBlock() ?? "", /export const value = 1/);
|
|
266
|
+
|
|
267
|
+
session.setCurrentUnit({
|
|
268
|
+
type: "plan-slice",
|
|
269
|
+
id: "M001/S01",
|
|
270
|
+
startedAt: 124,
|
|
271
|
+
workspaceRoot: basePath,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
assert.equal(session.sourceObservations.renderActiveBlock(), null);
|
|
275
|
+
});
|
|
@@ -100,6 +100,7 @@ describe("stale queued milestone selection (#3470)", () => {
|
|
|
100
100
|
const state = await deriveStateFromDb(base);
|
|
101
101
|
|
|
102
102
|
assert.equal(state.activeMilestone?.id, "M068", "Queued milestone with draft should become active");
|
|
103
|
+
assert.equal(state.phase, "needs-discussion", "Queued milestone with draft should resume discussion");
|
|
103
104
|
});
|
|
104
105
|
|
|
105
106
|
test("queued milestone WITH slices can still be selected as active", async () => {
|
|
@@ -144,4 +145,46 @@ describe("stale queued milestone selection (#3470)", () => {
|
|
|
144
145
|
assert.equal(entry!.status, "pending", `${id} should be pending, not active`);
|
|
145
146
|
}
|
|
146
147
|
});
|
|
148
|
+
|
|
149
|
+
test("queued milestone with stale CONTEXT-DRAFT does not block real active milestone", async () => {
|
|
150
|
+
base = createFixtureBase();
|
|
151
|
+
openDatabase(":memory:");
|
|
152
|
+
|
|
153
|
+
// M068: queued, no slices, has a CONTEXT-DRAFT (abandoned discussion)
|
|
154
|
+
insertMilestone({ id: "M068", title: "Abandoned Draft", status: "queued" });
|
|
155
|
+
writeFile(base, "milestones/M068/M068-CONTEXT-DRAFT.md", "# M068: Abandoned Draft\n\nDraft left over from an abandoned session.");
|
|
156
|
+
|
|
157
|
+
// M070: real active milestone with execution artifacts
|
|
158
|
+
insertMilestone({ id: "M070", title: "Real Active", status: "active" });
|
|
159
|
+
insertSlice({ id: "S01", milestoneId: "M070", title: "Slice One", status: "active", risk: "low", depends: [] });
|
|
160
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M070", title: "Task One", status: "pending" });
|
|
161
|
+
|
|
162
|
+
writeFile(base, "milestones/M070/M070-CONTEXT.md", "# M070: Real Active\n\nThis is the real milestone.");
|
|
163
|
+
writeFile(base, "milestones/M070/M070-ROADMAP.md", "# M070: Real Active\n\n## Slices\n\n- [ ] **S01: Slice One**");
|
|
164
|
+
writeFile(base, "milestones/M070/slices/S01/S01-PLAN.md", "# S01: Slice One\n\n## Tasks\n\n- [ ] **T01: Task One**");
|
|
165
|
+
|
|
166
|
+
invalidateStateCache();
|
|
167
|
+
const state = await deriveStateFromDb(base);
|
|
168
|
+
|
|
169
|
+
assert.equal(state.activeMilestone?.id, "M070", "Stale draft on M068 must not block real active M070");
|
|
170
|
+
|
|
171
|
+
const m068Entry = state.registry.find((e: any) => e.id === "M068");
|
|
172
|
+
assert.ok(m068Entry, "M068 should still appear in registry");
|
|
173
|
+
assert.equal(m068Entry!.status, "pending", "M068 with stale draft should be pending, not active");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("queued milestone with CONTEXT-DRAFT becomes active with needs-discussion phase when nothing else is active", async () => {
|
|
177
|
+
base = createFixtureBase();
|
|
178
|
+
openDatabase(":memory:");
|
|
179
|
+
|
|
180
|
+
// M068: queued, no slices, has a CONTEXT-DRAFT — should resume discussion
|
|
181
|
+
insertMilestone({ id: "M068", title: "Draft Only", status: "queued" });
|
|
182
|
+
writeFile(base, "milestones/M068/M068-CONTEXT-DRAFT.md", "# M068: Draft Only\n\nPartial context from first question round.");
|
|
183
|
+
|
|
184
|
+
invalidateStateCache();
|
|
185
|
+
const state = await deriveStateFromDb(base);
|
|
186
|
+
|
|
187
|
+
assert.equal(state.activeMilestone?.id, "M068", "Queued milestone with draft should become active when nothing else is");
|
|
188
|
+
assert.equal(state.phase, "needs-discussion", "Should resume discussion for queued milestone with draft");
|
|
189
|
+
});
|
|
147
190
|
});
|