@opengsd/gsd-pi 1.10.0 → 1.11.0
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 +10 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -3
- package/dist/resources/extensions/gsd/db/engine.js +8 -2
- package/dist/resources/extensions/gsd/db-canonical-foundation-schema.js +120 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +16 -4
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -3
- package/dist/resources/extensions/gsd/model-router.js +10 -5
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +12 -4
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +41 -6
- package/dist/resources/extensions/gsd/preferences.js +7 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- package/dist/resources/extensions/subagent/index.js +1 -1
- package/dist/startup-model-validation.d.ts +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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 +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- 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/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +7 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -1
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/rpc.test.js +1 -1
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- 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/cli/args.js +2 -2
- package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +12 -2
- package/packages/gsd-cloud/dist/background-cli.test.js +157 -80
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -1
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +36 -12
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +6 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +106 -24
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts +5 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.js +429 -61
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.test.js +493 -47
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +2 -2
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +113 -2
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +84 -9
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js +18 -6
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +9 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +1 -0
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +4 -3
- package/src/resources/extensions/gsd/db/engine.ts +9 -1
- package/src/resources/extensions/gsd/db-canonical-foundation-schema.ts +129 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +15 -4
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -3
- package/src/resources/extensions/gsd/model-router.ts +10 -5
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +18 -4
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +10 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +49 -6
- package/src/resources/extensions/gsd/preferences.ts +13 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/src/resources/extensions/gsd/tests/db-canonical-foundation.test.ts +459 -0
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +22 -7
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +71 -4
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +1 -1
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
closeDatabase,
|
|
7
|
+
insertMilestone,
|
|
8
|
+
insertSlice,
|
|
9
|
+
insertTask,
|
|
10
|
+
openDatabase,
|
|
11
|
+
transaction,
|
|
12
|
+
} from "../gsd-db.ts";
|
|
13
|
+
import { saveDecisionToDb, saveRequirementToDb } from "../db-writer.ts";
|
|
14
|
+
import { invalidateStateCache } from "../state.ts";
|
|
15
|
+
|
|
16
|
+
export interface WorkflowAuthorityFixture {
|
|
17
|
+
root: string;
|
|
18
|
+
dbPath: string;
|
|
19
|
+
ids: {
|
|
20
|
+
milestone: string;
|
|
21
|
+
completedSlice: string;
|
|
22
|
+
readySlice: string;
|
|
23
|
+
completedTask: string;
|
|
24
|
+
readyTask: string;
|
|
25
|
+
requirement: string;
|
|
26
|
+
decision: string;
|
|
27
|
+
};
|
|
28
|
+
reopen(): void;
|
|
29
|
+
cleanup(): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function openFixtureDatabase(dbPath: string): void {
|
|
33
|
+
if (!openDatabase(dbPath)) {
|
|
34
|
+
throw new Error(`Could not open workflow authority fixture database: ${dbPath}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function createWorkflowAuthorityFixture(): Promise<WorkflowAuthorityFixture> {
|
|
39
|
+
const root = realpathSync(mkdtempSync(join(tmpdir(), "gsd-workflow-authority-")));
|
|
40
|
+
const dbPath = join(root, ".gsd", "gsd.db");
|
|
41
|
+
let cleanedUp = false;
|
|
42
|
+
|
|
43
|
+
mkdirSync(join(root, ".gsd"), { recursive: true });
|
|
44
|
+
openFixtureDatabase(dbPath);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
transaction(() => {
|
|
48
|
+
insertMilestone({ id: "M001", title: "Authority Fixture", status: "active" });
|
|
49
|
+
insertSlice({
|
|
50
|
+
id: "S01",
|
|
51
|
+
milestoneId: "M001",
|
|
52
|
+
title: "Completed prerequisite",
|
|
53
|
+
status: "complete",
|
|
54
|
+
risk: "low",
|
|
55
|
+
depends: [],
|
|
56
|
+
sequence: 1,
|
|
57
|
+
});
|
|
58
|
+
insertSlice({
|
|
59
|
+
id: "S02",
|
|
60
|
+
milestoneId: "M001",
|
|
61
|
+
title: "Ready dependent slice",
|
|
62
|
+
status: "pending",
|
|
63
|
+
risk: "medium",
|
|
64
|
+
depends: ["S01"],
|
|
65
|
+
sequence: 2,
|
|
66
|
+
});
|
|
67
|
+
insertTask({
|
|
68
|
+
id: "T01",
|
|
69
|
+
milestoneId: "M001",
|
|
70
|
+
sliceId: "S01",
|
|
71
|
+
title: "Completed task",
|
|
72
|
+
status: "complete",
|
|
73
|
+
sequence: 1,
|
|
74
|
+
});
|
|
75
|
+
insertTask({
|
|
76
|
+
id: "T01",
|
|
77
|
+
milestoneId: "M001",
|
|
78
|
+
sliceId: "S02",
|
|
79
|
+
title: "Ready task",
|
|
80
|
+
status: "pending",
|
|
81
|
+
sequence: 1,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const requirement = await saveRequirementToDb(
|
|
86
|
+
{
|
|
87
|
+
class: "core-capability",
|
|
88
|
+
status: "active",
|
|
89
|
+
description: "SQLite is authoritative",
|
|
90
|
+
why: "Readable projections must not control workflow state.",
|
|
91
|
+
source: "workflow-authority-fixture",
|
|
92
|
+
primary_owner: "M001/S02",
|
|
93
|
+
validation: "DB-derived state remains canonical",
|
|
94
|
+
},
|
|
95
|
+
root,
|
|
96
|
+
);
|
|
97
|
+
const decision = await saveDecisionToDb(
|
|
98
|
+
{
|
|
99
|
+
when_context: "M001/S02",
|
|
100
|
+
scope: "architecture",
|
|
101
|
+
decision: "Choose the workflow authority",
|
|
102
|
+
choice: "SQLite is authoritative",
|
|
103
|
+
rationale: "Projections may lag without losing saved intent.",
|
|
104
|
+
revisable: "No",
|
|
105
|
+
made_by: "human",
|
|
106
|
+
source: "discussion",
|
|
107
|
+
},
|
|
108
|
+
root,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
root,
|
|
113
|
+
dbPath,
|
|
114
|
+
ids: {
|
|
115
|
+
milestone: "M001",
|
|
116
|
+
completedSlice: "S01",
|
|
117
|
+
readySlice: "S02",
|
|
118
|
+
completedTask: "T01",
|
|
119
|
+
readyTask: "T01",
|
|
120
|
+
requirement: requirement.id,
|
|
121
|
+
decision: decision.id,
|
|
122
|
+
},
|
|
123
|
+
reopen() {
|
|
124
|
+
closeDatabase();
|
|
125
|
+
openFixtureDatabase(dbPath);
|
|
126
|
+
invalidateStateCache();
|
|
127
|
+
},
|
|
128
|
+
cleanup() {
|
|
129
|
+
if (cleanedUp) return;
|
|
130
|
+
cleanedUp = true;
|
|
131
|
+
closeDatabase();
|
|
132
|
+
invalidateStateCache();
|
|
133
|
+
rmSync(root, { recursive: true, force: true });
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
} catch (error) {
|
|
137
|
+
closeDatabase();
|
|
138
|
+
rmSync(root, { recursive: true, force: true });
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { getMilestoneSlices, getSliceTasks } from "../gsd-db.ts";
|
|
7
|
+
import { queryDecisionsFromMemories, queryRequirements } from "../context-store.ts";
|
|
8
|
+
import { deriveStateFromDb } from "../state.ts";
|
|
9
|
+
import {
|
|
10
|
+
createWorkflowAuthorityFixture,
|
|
11
|
+
type WorkflowAuthorityFixture,
|
|
12
|
+
} from "./workflow-authority-fixture.ts";
|
|
13
|
+
|
|
14
|
+
function writeProjection(root: string, path: string, content: string): void {
|
|
15
|
+
const fullPath = join(root, ".gsd", path);
|
|
16
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
17
|
+
writeFileSync(fullPath, content, "utf8");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function writeContradictoryProjections(root: string): void {
|
|
21
|
+
writeProjection(
|
|
22
|
+
root,
|
|
23
|
+
"STATE.md",
|
|
24
|
+
[
|
|
25
|
+
"# GSD State",
|
|
26
|
+
"",
|
|
27
|
+
"**Active Milestone:** M999",
|
|
28
|
+
"**Active Slice:** S99",
|
|
29
|
+
"**Phase:** complete",
|
|
30
|
+
"**Requirements Status:** 0 active · 1 validated",
|
|
31
|
+
].join("\n"),
|
|
32
|
+
);
|
|
33
|
+
writeProjection(
|
|
34
|
+
root,
|
|
35
|
+
"PROJECT.md",
|
|
36
|
+
[
|
|
37
|
+
"# Projection-only project",
|
|
38
|
+
"",
|
|
39
|
+
"## Milestone Sequence",
|
|
40
|
+
"- [x] M001: Falsely complete",
|
|
41
|
+
"- [ ] M999: Projection-only active milestone",
|
|
42
|
+
].join("\n"),
|
|
43
|
+
);
|
|
44
|
+
writeProjection(
|
|
45
|
+
root,
|
|
46
|
+
"REQUIREMENTS.md",
|
|
47
|
+
[
|
|
48
|
+
"# Requirements",
|
|
49
|
+
"",
|
|
50
|
+
"## Validated",
|
|
51
|
+
"### R999 — Markdown controls workflow state",
|
|
52
|
+
"- Status: validated",
|
|
53
|
+
"- Primary owning slice: M999/S99",
|
|
54
|
+
].join("\n"),
|
|
55
|
+
);
|
|
56
|
+
writeProjection(
|
|
57
|
+
root,
|
|
58
|
+
"DECISIONS.md",
|
|
59
|
+
[
|
|
60
|
+
"# Decisions Register",
|
|
61
|
+
"",
|
|
62
|
+
"| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |",
|
|
63
|
+
"|---|------|-------|----------|--------|-----------|------------|---------|",
|
|
64
|
+
"| D999 | M999/S99 | architecture | Choose authority | Markdown is authoritative | projection conflict | No | human |",
|
|
65
|
+
].join("\n"),
|
|
66
|
+
);
|
|
67
|
+
writeProjection(
|
|
68
|
+
root,
|
|
69
|
+
"milestones/M001/M001-ROADMAP.md",
|
|
70
|
+
[
|
|
71
|
+
"# M001: Falsely complete",
|
|
72
|
+
"",
|
|
73
|
+
"## Slices",
|
|
74
|
+
"- [ ] **S01: Falsely reopened** `risk:low` `depends:[]`",
|
|
75
|
+
"- [x] **S02: Falsely complete** `risk:low` `depends:[]`",
|
|
76
|
+
].join("\n"),
|
|
77
|
+
);
|
|
78
|
+
writeProjection(
|
|
79
|
+
root,
|
|
80
|
+
"milestones/M001/slices/S02/S02-PLAN.md",
|
|
81
|
+
[
|
|
82
|
+
"# S02: Falsely complete",
|
|
83
|
+
"",
|
|
84
|
+
"## Tasks",
|
|
85
|
+
"- [x] **T99: Projection-only task** `est:1m`",
|
|
86
|
+
].join("\n"),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function readDirectDbAuthoritySnapshot(fixture: WorkflowAuthorityFixture) {
|
|
91
|
+
const state = await deriveStateFromDb(fixture.root);
|
|
92
|
+
return {
|
|
93
|
+
state: {
|
|
94
|
+
phase: state.phase,
|
|
95
|
+
milestone: state.activeMilestone?.id ?? null,
|
|
96
|
+
slice: state.activeSlice?.id ?? null,
|
|
97
|
+
task: state.activeTask?.id ?? null,
|
|
98
|
+
requirements: state.requirements,
|
|
99
|
+
},
|
|
100
|
+
registry: state.registry.map((milestone) => ({
|
|
101
|
+
id: milestone.id,
|
|
102
|
+
status: milestone.status,
|
|
103
|
+
})),
|
|
104
|
+
slices: getMilestoneSlices(fixture.ids.milestone).map((slice) => ({
|
|
105
|
+
id: slice.id,
|
|
106
|
+
status: slice.status,
|
|
107
|
+
depends: slice.depends,
|
|
108
|
+
})),
|
|
109
|
+
tasks: {
|
|
110
|
+
completed: getSliceTasks(fixture.ids.milestone, fixture.ids.completedSlice).map((task) => ({
|
|
111
|
+
id: task.id,
|
|
112
|
+
status: task.status,
|
|
113
|
+
})),
|
|
114
|
+
ready: getSliceTasks(fixture.ids.milestone, fixture.ids.readySlice).map((task) => ({
|
|
115
|
+
id: task.id,
|
|
116
|
+
status: task.status,
|
|
117
|
+
})),
|
|
118
|
+
},
|
|
119
|
+
requirements: queryRequirements({
|
|
120
|
+
milestoneId: fixture.ids.milestone,
|
|
121
|
+
sliceId: fixture.ids.readySlice,
|
|
122
|
+
}).map((requirement) => ({
|
|
123
|
+
id: requirement.id,
|
|
124
|
+
status: requirement.status,
|
|
125
|
+
owner: requirement.primary_owner,
|
|
126
|
+
})),
|
|
127
|
+
decisions: queryDecisionsFromMemories().map((decision) => ({
|
|
128
|
+
id: decision.id,
|
|
129
|
+
choice: decision.choice,
|
|
130
|
+
})),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
test("direct DB authority queries ignore contradictory Markdown projections", async (t) => {
|
|
135
|
+
const fixture = await createWorkflowAuthorityFixture();
|
|
136
|
+
t.after(() => fixture.cleanup());
|
|
137
|
+
fixture.reopen();
|
|
138
|
+
const before = await readDirectDbAuthoritySnapshot(fixture);
|
|
139
|
+
|
|
140
|
+
assert.deepEqual(before, {
|
|
141
|
+
state: {
|
|
142
|
+
phase: "executing",
|
|
143
|
+
milestone: fixture.ids.milestone,
|
|
144
|
+
slice: fixture.ids.readySlice,
|
|
145
|
+
task: fixture.ids.readyTask,
|
|
146
|
+
requirements: {
|
|
147
|
+
active: 1,
|
|
148
|
+
validated: 0,
|
|
149
|
+
deferred: 0,
|
|
150
|
+
outOfScope: 0,
|
|
151
|
+
blocked: 0,
|
|
152
|
+
total: 1,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
registry: [{ id: fixture.ids.milestone, status: "active" }],
|
|
156
|
+
slices: [
|
|
157
|
+
{ id: fixture.ids.completedSlice, status: "complete", depends: [] },
|
|
158
|
+
{ id: fixture.ids.readySlice, status: "pending", depends: [fixture.ids.completedSlice] },
|
|
159
|
+
],
|
|
160
|
+
tasks: {
|
|
161
|
+
completed: [{ id: fixture.ids.completedTask, status: "complete" }],
|
|
162
|
+
ready: [{ id: fixture.ids.readyTask, status: "pending" }],
|
|
163
|
+
},
|
|
164
|
+
requirements: [
|
|
165
|
+
{ id: fixture.ids.requirement, status: "active", owner: "M001/S02" },
|
|
166
|
+
],
|
|
167
|
+
decisions: [
|
|
168
|
+
{ id: fixture.ids.decision, choice: "SQLite is authoritative" },
|
|
169
|
+
],
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
writeContradictoryProjections(fixture.root);
|
|
173
|
+
fixture.reopen();
|
|
174
|
+
|
|
175
|
+
const after = await readDirectDbAuthoritySnapshot(fixture);
|
|
176
|
+
assert.deepEqual(after, before);
|
|
177
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createWorkflowFaultHarness,
|
|
6
|
+
type WorkflowFaultPoint,
|
|
7
|
+
} from "./workflow-fault-harness.js";
|
|
8
|
+
|
|
9
|
+
test("fault harness throws once at the armed named boundary", () => {
|
|
10
|
+
const harness = createWorkflowFaultHarness("after-db-commit-before-render");
|
|
11
|
+
|
|
12
|
+
harness.hit("before-transaction-commit", "complete-task");
|
|
13
|
+
assert.throws(
|
|
14
|
+
() => harness.hit("after-db-commit-before-render", "complete-task"),
|
|
15
|
+
/complete-task.*after-db-commit-before-render.*hit 1/,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
assert.equal(harness.count("before-transaction-commit"), 1);
|
|
19
|
+
assert.equal(harness.count("after-db-commit-before-render"), 1);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("fault harness automatically disarms after its first matching hit", () => {
|
|
23
|
+
const point: WorkflowFaultPoint = "during-projection-write";
|
|
24
|
+
const harness = createWorkflowFaultHarness(point);
|
|
25
|
+
|
|
26
|
+
assert.throws(() => harness.hit(point, "complete-slice"));
|
|
27
|
+
assert.doesNotThrow(() => harness.hit(point, "complete-slice"));
|
|
28
|
+
assert.equal(harness.count(point), 2);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("fault harness instances never share armed state or counts", () => {
|
|
32
|
+
const first = createWorkflowFaultHarness("before-independent-reopen");
|
|
33
|
+
const second = createWorkflowFaultHarness("before-independent-reopen");
|
|
34
|
+
|
|
35
|
+
assert.throws(() => first.hit("before-independent-reopen", "resume"));
|
|
36
|
+
assert.equal(first.count("before-independent-reopen"), 1);
|
|
37
|
+
assert.equal(second.count("before-independent-reopen"), 0);
|
|
38
|
+
assert.throws(() => second.hit("before-independent-reopen", "resume"));
|
|
39
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { getDb } from "../gsd-db.js";
|
|
4
|
+
|
|
5
|
+
export type WorkflowFaultPoint =
|
|
6
|
+
| "before-transaction-commit"
|
|
7
|
+
| "after-db-commit-before-render"
|
|
8
|
+
| "during-projection-write"
|
|
9
|
+
| "before-independent-reopen"
|
|
10
|
+
| "after-independent-reopen";
|
|
11
|
+
|
|
12
|
+
export interface WorkflowFaultHarness {
|
|
13
|
+
hit(point: WorkflowFaultPoint, operation?: string): void;
|
|
14
|
+
count(point: WorkflowFaultPoint): number;
|
|
15
|
+
armDatabaseAbort(
|
|
16
|
+
column: "status" | "full_summary_md",
|
|
17
|
+
predicate:
|
|
18
|
+
| "NEW.status = 'complete' AND OLD.status <> 'complete'"
|
|
19
|
+
| "NEW.full_summary_md IS NOT OLD.full_summary_md",
|
|
20
|
+
): void;
|
|
21
|
+
obstructProjection(path: string): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class WorkflowFaultError extends Error {
|
|
25
|
+
readonly point: WorkflowFaultPoint;
|
|
26
|
+
readonly operation: string;
|
|
27
|
+
readonly hitCount: number;
|
|
28
|
+
|
|
29
|
+
constructor(point: WorkflowFaultPoint, operation: string, hitCount: number) {
|
|
30
|
+
super(`${operation} fault at ${point} (hit ${hitCount})`);
|
|
31
|
+
this.name = "WorkflowFaultError";
|
|
32
|
+
this.point = point;
|
|
33
|
+
this.operation = operation;
|
|
34
|
+
this.hitCount = hitCount;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createWorkflowFaultHarness(
|
|
39
|
+
armedPoint: WorkflowFaultPoint,
|
|
40
|
+
): WorkflowFaultHarness {
|
|
41
|
+
const counts = new Map<WorkflowFaultPoint, number>();
|
|
42
|
+
let armed = true;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
hit(point, operation = "workflow-operation") {
|
|
46
|
+
const hitCount = (counts.get(point) ?? 0) + 1;
|
|
47
|
+
counts.set(point, hitCount);
|
|
48
|
+
if (armed && point === armedPoint) {
|
|
49
|
+
armed = false;
|
|
50
|
+
throw new WorkflowFaultError(point, operation, hitCount);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
count(point) {
|
|
54
|
+
return counts.get(point) ?? 0;
|
|
55
|
+
},
|
|
56
|
+
armDatabaseAbort(column, predicate) {
|
|
57
|
+
const triggerName = `workflow_fault_${armedPoint.replaceAll("-", "_")}`;
|
|
58
|
+
const message = `complete-dependent-slice fault at ${armedPoint}`;
|
|
59
|
+
getDb().exec(`
|
|
60
|
+
CREATE TEMP TRIGGER ${triggerName}
|
|
61
|
+
BEFORE UPDATE OF ${column} ON slices
|
|
62
|
+
WHEN ${predicate}
|
|
63
|
+
BEGIN
|
|
64
|
+
SELECT RAISE(ABORT, '${message}');
|
|
65
|
+
END
|
|
66
|
+
`);
|
|
67
|
+
},
|
|
68
|
+
obstructProjection(path) {
|
|
69
|
+
mkdirSync(path, { recursive: true });
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
import test from 'node:test';
|
|
9
9
|
import assert from 'node:assert/strict';
|
|
10
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
10
12
|
import { join, sep } from 'node:path';
|
|
11
13
|
|
|
12
14
|
import { GSD_PHASE_SCOPE_DISPLAY_REASON, GSD_SECTION_CLOSE_GATE_DISPLAY_REASON } from '../auto-unit-tool-scope.ts';
|
|
13
15
|
import { ALLOWED_PLANNING_DISPATCH_AGENTS, shouldBlockPlanningUnit } from '../bootstrap/write-gate.ts';
|
|
14
16
|
import { extractSubagentAgentClasses } from '../bootstrap/subagent-input.ts';
|
|
15
17
|
import { isDeterministicPolicyError } from '../auto-tool-tracking.ts';
|
|
18
|
+
import { clearGSDPreferencesCache, getProjectGSDPreferencesPath, loadEffectiveGSDPreferences } from '../preferences.ts';
|
|
16
19
|
import { applyPlanningSubagentPreferences } from '../planning-subagent-policy.ts';
|
|
17
20
|
import type { ToolsPolicy } from '../unit-context-manifest.ts';
|
|
18
21
|
|
|
@@ -369,6 +372,43 @@ test('planning_subagents: widens plan-slice manifest allowlist without allowing
|
|
|
369
372
|
assert.match(unsafe.reason!, /read-only specialists/);
|
|
370
373
|
});
|
|
371
374
|
|
|
375
|
+
test('planning_subagents: registered custom planning agents pass runtime read-only registry', (t) => {
|
|
376
|
+
const tempProject = mkdtempSync(join(tmpdir(), 'gsd-custom-planning-agent-'));
|
|
377
|
+
|
|
378
|
+
t.after(() => {
|
|
379
|
+
clearGSDPreferencesCache();
|
|
380
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
mkdirSync(join(tempProject, '.gsd'), { recursive: true });
|
|
384
|
+
writeFileSync(
|
|
385
|
+
getProjectGSDPreferencesPath(tempProject),
|
|
386
|
+
[
|
|
387
|
+
'---',
|
|
388
|
+
'version: 1',
|
|
389
|
+
'planning_subagent_registry:',
|
|
390
|
+
' my-custom-planner:',
|
|
391
|
+
' read_only_specialist: true',
|
|
392
|
+
'planning_subagents:',
|
|
393
|
+
' plan-slice:',
|
|
394
|
+
' allowed: [my-custom-planner]',
|
|
395
|
+
'---',
|
|
396
|
+
'',
|
|
397
|
+
].join('\n'),
|
|
398
|
+
'utf-8',
|
|
399
|
+
);
|
|
400
|
+
clearGSDPreferencesCache();
|
|
401
|
+
|
|
402
|
+
const preferences = loadEffectiveGSDPreferences(tempProject)?.preferences;
|
|
403
|
+
const policy = applyPlanningSubagentPreferences('plan-slice', PLANNING_DISPATCH, preferences);
|
|
404
|
+
const custom = shouldBlockPlanningUnit('subagent', '', tempProject, 'plan-slice', policy, ['my-custom-planner']);
|
|
405
|
+
assert.strictEqual(custom.block, false, custom.reason);
|
|
406
|
+
|
|
407
|
+
const unregistered = shouldBlockPlanningUnit('subagent', '', tempProject, 'plan-slice', policy, ['other-planner']);
|
|
408
|
+
assert.strictEqual(unregistered.block, true);
|
|
409
|
+
assert.match(unregistered.reason!, /read-only specialists/);
|
|
410
|
+
});
|
|
411
|
+
|
|
372
412
|
// ─── planning mode: pass-through tools ────────────────────────────────────
|
|
373
413
|
|
|
374
414
|
test('planning-unit: allows read tool', () => {
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "../gsd-db.js";
|
|
21
21
|
import type { GateEvaluationConfig, GateId } from "../types.js";
|
|
22
22
|
import { invalidateStateCache } from "../state.js";
|
|
23
|
-
import { renderPlanFromDb } from "../markdown-renderer.js";
|
|
23
|
+
import { renderPlanCheckboxes, renderPlanFromDb } from "../markdown-renderer.js";
|
|
24
24
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
25
|
import { appendEvent } from "../workflow-events.js";
|
|
26
26
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -469,9 +469,13 @@ export async function handlePlanSlice(
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
const sliceTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
472
|
+
const hasClosedTasks = sliceTasks.some((task) => isClosedStatus(task.status));
|
|
472
473
|
const renderResult = sliceTasks.length === 0
|
|
473
474
|
? { planPath: "", taskPlanPaths: [] as string[] }
|
|
474
475
|
: await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
476
|
+
if (sliceTasks.length > 0 && hasClosedTasks) {
|
|
477
|
+
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
478
|
+
}
|
|
475
479
|
if (sliceTasks.length > 0) {
|
|
476
480
|
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
477
481
|
}
|
|
@@ -98,8 +98,9 @@ export interface EvidenceJSON {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Write a T##-VERIFY.json artifact to the
|
|
101
|
+
* Write a T##-VERIFY.json artifact to the evidence directory.
|
|
102
102
|
* Creates the directory with mkdirSync({ recursive: true }) if it doesn't exist.
|
|
103
|
+
* Flat-phase callers can pass sliceId to write S##-T##-VERIFY.json.
|
|
103
104
|
*
|
|
104
105
|
* stdout/stderr are excluded from the JSON — the full output lives in VerificationResult
|
|
105
106
|
* in memory and is logged to stderr during the gate run.
|
|
@@ -111,6 +112,7 @@ export function writeVerificationJSON(
|
|
|
111
112
|
unitId?: string,
|
|
112
113
|
retryAttempt?: number,
|
|
113
114
|
maxRetries?: number,
|
|
115
|
+
sliceId?: string,
|
|
114
116
|
): void {
|
|
115
117
|
mkdirSync(tasksDir, { recursive: true });
|
|
116
118
|
|
|
@@ -150,7 +152,8 @@ export function writeVerificationJSON(
|
|
|
150
152
|
}));
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
const
|
|
155
|
+
const fileName = sliceId ? `${sliceId}-${taskId}-VERIFY.json` : `${taskId}-VERIFY.json`;
|
|
156
|
+
const filePath = join(tasksDir, fileName);
|
|
154
157
|
writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
155
158
|
}
|
|
156
159
|
|
|
@@ -207,7 +207,7 @@ export function streamOllamaChat(
|
|
|
207
207
|
* - `"low" | "medium" | "high"` are passed through as strings; gpt-oss honors
|
|
208
208
|
* them as strength levels, other thinking models treat any present value
|
|
209
209
|
* as "thinking enabled".
|
|
210
|
-
* - `"xhigh"`
|
|
210
|
+
* - `"xhigh"` and `"max"` are collapsed to `"high"` (ollama caps strength at high).
|
|
211
211
|
*/
|
|
212
212
|
export function buildThinkParam(
|
|
213
213
|
model: Model<Api>,
|
|
@@ -217,7 +217,7 @@ export function buildThinkParam(
|
|
|
217
217
|
const level: ThinkingLevel | undefined = options?.reasoning;
|
|
218
218
|
if (level === undefined) return undefined;
|
|
219
219
|
if (level === "minimal") return false;
|
|
220
|
-
if (level === "xhigh") return "high";
|
|
220
|
+
if (level === "xhigh" || level === "max") return "high";
|
|
221
221
|
return level;
|
|
222
222
|
}
|
|
223
223
|
|
|
@@ -55,6 +55,10 @@ describe("buildThinkParam — ThinkingLevel mapping", () => {
|
|
|
55
55
|
it("collapses 'xhigh' to 'high' (ollama caps at high)", () => {
|
|
56
56
|
assert.equal(buildThinkParam(m, { reasoning: "xhigh" }), "high");
|
|
57
57
|
});
|
|
58
|
+
|
|
59
|
+
it("collapses 'max' to 'high' (ollama caps at high)", () => {
|
|
60
|
+
assert.equal(buildThinkParam(m, { reasoning: "max" }), "high");
|
|
61
|
+
});
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
describe("buildRequest — wire-level think field", () => {
|
|
@@ -735,7 +735,7 @@ async function runSingleAgentInCmuxSplit(
|
|
|
735
735
|
}
|
|
736
736
|
}
|
|
737
737
|
|
|
738
|
-
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"] as const, {
|
|
738
|
+
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const, {
|
|
739
739
|
description:
|
|
740
740
|
"Reasoning effort override for the subagent (forwarded as --thinking). " +
|
|
741
741
|
"Independent of model choice; unsupported levels are clamped to the model at dispatch.",
|
|
File without changes
|
|
File without changes
|