@undeemed/get-shit-done-codex 1.24.1 β 1.24.2
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 -3
- package/get-shit-done/bin/gsd-tools.cjs +293 -124
- package/get-shit-done/bin/lib/core.cjs +16 -16
- package/get-shit-done/references/model-profile-resolution.md +2 -2
- package/get-shit-done/references/model-profiles.md +29 -29
- package/get-shit-done/workflows/help.md +3 -3
- package/get-shit-done/workflows/new-project.md +6 -6
- package/get-shit-done/workflows/set-profile.md +3 -3
- package/get-shit-done/workflows/settings.md +3 -3
- package/package.json +3 -2
- package/scripts/run-tests.cjs +38 -24
package/README.md
CHANGED
|
@@ -268,9 +268,9 @@ All agents use **gpt-5.3-codex** with role-based thinking levels:
|
|
|
268
268
|
|
|
269
269
|
| Profile | Planner/Debugger | Executor/Verifier | Researchers/Mapper |
|
|
270
270
|
| ---------- | ---------------- | ----------------- | ------------------ |
|
|
271
|
-
| `quality` | π’ high
|
|
272
|
-
| `balanced` | π’ high
|
|
273
|
-
| `budget` |
|
|
271
|
+
| `quality` | π΄ xhigh | π’ high | π’ high/π‘ medium |
|
|
272
|
+
| `balanced` | π΄ xhigh | π’ high | π‘ medium |
|
|
273
|
+
| `budget` | π’ high | π‘ medium | π‘ medium |
|
|
274
274
|
|
|
275
275
|
Switch profiles: `$gsd-set-profile budget`
|
|
276
276
|
|
|
@@ -311,6 +311,13 @@ npx @undeemed/get-shit-done-codex@latest
|
|
|
311
311
|
- In-Codex update checks are available via `$gsd-update`.
|
|
312
312
|
- For release notifications outside the CLI, enable GitHub release watching on this repo.
|
|
313
313
|
|
|
314
|
+
**`gsd-tools` scripting tips**
|
|
315
|
+
|
|
316
|
+
- Use `--cwd <path>` (or `--cwd=<path>`) to target a specific project directory from automation scripts.
|
|
317
|
+
- Use `state json` for machine-readable state; use `state-snapshot` for structured markdown-field extraction.
|
|
318
|
+
- Use `requirements mark-complete REQ-01 REQ-02` to update both requirement checkboxes and traceability rows.
|
|
319
|
+
- If `commit` appears to skip unexpectedly, check `.planning/config.json` for `commit_docs: false` and also check user defaults in `~/.gsd/defaults.json`.
|
|
320
|
+
|
|
314
321
|
## More Documentation
|
|
315
322
|
|
|
316
323
|
For deeper guides, detailed workflows, and comprehensive documentation, see the [original get-shit-done README](https://github.com/taches/get-shit-done/blob/main/README.md).
|
|
@@ -122,25 +122,35 @@
|
|
|
122
122
|
const fs = require('fs');
|
|
123
123
|
const path = require('path');
|
|
124
124
|
const { execSync } = require('child_process');
|
|
125
|
+
const stateLib = require('./lib/state.cjs');
|
|
126
|
+
const phaseLib = require('./lib/phase.cjs');
|
|
127
|
+
const milestoneLib = require('./lib/milestone.cjs');
|
|
128
|
+
const initLib = require('./lib/init.cjs');
|
|
129
|
+
const commandsLib = require('./lib/commands.cjs');
|
|
130
|
+
const configLib = require('./lib/config.cjs');
|
|
131
|
+
const roadmapLib = require('./lib/roadmap.cjs');
|
|
132
|
+
const templateLib = require('./lib/template.cjs');
|
|
133
|
+
const frontmatterLib = require('./lib/frontmatter.cjs');
|
|
134
|
+
const verifyLib = require('./lib/verify.cjs');
|
|
125
135
|
|
|
126
136
|
// βββ Model Profile Table βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
127
137
|
|
|
128
138
|
const MODEL_PROFILES = {
|
|
129
|
-
// quality
|
|
130
|
-
'gsd-planner': { quality: { m: 'gpt-5.3-codex', t: '
|
|
131
|
-
'gsd-roadmapper': { quality: { m: 'gpt-5.3-codex', t: '
|
|
132
|
-
'gsd-executor': { quality: { m: 'gpt-5.3-codex', t: '
|
|
133
|
-
'gsd-phase-researcher': { quality: { m: 'gpt-5.3-codex', t: '
|
|
134
|
-
'gsd-project-researcher': { quality: { m: 'gpt-5.3-codex', t: '
|
|
135
|
-
'gsd-research-synthesizer': { quality: { m: 'gpt-5.3-codex', t: '
|
|
136
|
-
'gsd-debugger': { quality: { m: 'gpt-5.3-codex', t: '
|
|
137
|
-
'gsd-codebase-mapper': { quality: { m: 'gpt-5.3-codex', t: '
|
|
138
|
-
'gsd-verifier': { quality: { m: 'gpt-5.3-codex', t: '
|
|
139
|
-
'gsd-plan-checker': { quality: { m: 'gpt-5.3-codex', t: '
|
|
140
|
-
'gsd-integration-checker': { quality: { m: 'gpt-5.3-codex', t: '
|
|
139
|
+
// quality balanced budget
|
|
140
|
+
'gsd-planner': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'xhigh' }, budget: { m: 'gpt-5.3-codex', t: 'high' } },
|
|
141
|
+
'gsd-roadmapper': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
142
|
+
'gsd-executor': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
143
|
+
'gsd-phase-researcher': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
144
|
+
'gsd-project-researcher': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
145
|
+
'gsd-research-synthesizer': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
146
|
+
'gsd-debugger': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'xhigh' }, budget: { m: 'gpt-5.3-codex', t: 'high' } },
|
|
147
|
+
'gsd-codebase-mapper': { quality: { m: 'gpt-5.3-codex', t: 'medium' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
148
|
+
'gsd-verifier': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
149
|
+
'gsd-plan-checker': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
150
|
+
'gsd-integration-checker': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
141
151
|
};
|
|
142
152
|
|
|
143
|
-
const DEFAULT_ENTRY = { m: 'gpt-5.3-codex', t: '
|
|
153
|
+
const DEFAULT_ENTRY = { m: 'gpt-5.3-codex', t: 'high' };
|
|
144
154
|
|
|
145
155
|
// βββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
146
156
|
|
|
@@ -247,12 +257,80 @@ function execGit(cwd, args) {
|
|
|
247
257
|
}
|
|
248
258
|
|
|
249
259
|
function normalizePhaseName(phase) {
|
|
250
|
-
const match = phase.match(/^(\d+(?:\.\d+)
|
|
260
|
+
const match = String(phase).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
251
261
|
if (!match) return phase;
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
return
|
|
262
|
+
const padded = match[1].padStart(2, '0');
|
|
263
|
+
const letter = match[2] ? match[2].toUpperCase() : '';
|
|
264
|
+
const decimal = match[3] || '';
|
|
265
|
+
return padded + letter + decimal;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function escapeRegex(value) {
|
|
269
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function comparePhaseNum(a, b) {
|
|
273
|
+
const pa = String(a).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
274
|
+
const pb = String(b).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
275
|
+
if (!pa || !pb) return String(a).localeCompare(String(b));
|
|
276
|
+
|
|
277
|
+
const intDiff = parseInt(pa[1], 10) - parseInt(pb[1], 10);
|
|
278
|
+
if (intDiff !== 0) return intDiff;
|
|
279
|
+
|
|
280
|
+
const la = (pa[2] || '').toUpperCase();
|
|
281
|
+
const lb = (pb[2] || '').toUpperCase();
|
|
282
|
+
if (la !== lb) {
|
|
283
|
+
if (!la) return -1;
|
|
284
|
+
if (!lb) return 1;
|
|
285
|
+
return la < lb ? -1 : 1;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const aDecParts = pa[3] ? pa[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
|
|
289
|
+
const bDecParts = pb[3] ? pb[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
|
|
290
|
+
const maxLen = Math.max(aDecParts.length, bDecParts.length);
|
|
291
|
+
|
|
292
|
+
if (aDecParts.length === 0 && bDecParts.length > 0) return -1;
|
|
293
|
+
if (bDecParts.length === 0 && aDecParts.length > 0) return 1;
|
|
294
|
+
|
|
295
|
+
for (let i = 0; i < maxLen; i++) {
|
|
296
|
+
const av = Number.isFinite(aDecParts[i]) ? aDecParts[i] : 0;
|
|
297
|
+
const bv = Number.isFinite(bDecParts[i]) ? bDecParts[i] : 0;
|
|
298
|
+
if (av !== bv) return av - bv;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function getMilestonePhaseFilter(cwd) {
|
|
305
|
+
const milestonePhaseNums = new Set();
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
|
|
309
|
+
const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
|
|
310
|
+
let m;
|
|
311
|
+
while ((m = phasePattern.exec(roadmap)) !== null) {
|
|
312
|
+
milestonePhaseNums.add(m[1]);
|
|
313
|
+
}
|
|
314
|
+
} catch {}
|
|
315
|
+
|
|
316
|
+
if (milestonePhaseNums.size === 0) {
|
|
317
|
+
const passAll = () => true;
|
|
318
|
+
passAll.phaseCount = 0;
|
|
319
|
+
return passAll;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const normalized = new Set(
|
|
323
|
+
[...milestonePhaseNums].map(n => (n.replace(/^0+/, '') || '0').toLowerCase())
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
function isDirInMilestone(dirName) {
|
|
327
|
+
const m = dirName.match(/^0*(\d+[A-Za-z]?(?:\.\d+)*)/);
|
|
328
|
+
if (!m) return false;
|
|
329
|
+
return normalized.has(m[1].toLowerCase());
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
isDirInMilestone.phaseCount = milestonePhaseNums.size;
|
|
333
|
+
return isDirInMilestone;
|
|
256
334
|
}
|
|
257
335
|
|
|
258
336
|
function extractFrontmatter(content) {
|
|
@@ -859,12 +937,8 @@ function cmdPhasesList(cwd, options, raw) {
|
|
|
859
937
|
}
|
|
860
938
|
}
|
|
861
939
|
|
|
862
|
-
// Sort
|
|
863
|
-
dirs.sort((a, b) =>
|
|
864
|
-
const aNum = parseFloat(a.match(/^(\d+(?:\.\d+)?)/)?.[1] || '0');
|
|
865
|
-
const bNum = parseFloat(b.match(/^(\d+(?:\.\d+)?)/)?.[1] || '0');
|
|
866
|
-
return aNum - bNum;
|
|
867
|
-
});
|
|
940
|
+
// Sort by canonical phase ordering (integers, decimals, letter suffixes)
|
|
941
|
+
dirs.sort((a, b) => comparePhaseNum(a, b));
|
|
868
942
|
|
|
869
943
|
// If filtering by phase number
|
|
870
944
|
if (phase) {
|
|
@@ -899,7 +973,7 @@ function cmdPhasesList(cwd, options, raw) {
|
|
|
899
973
|
const result = {
|
|
900
974
|
files,
|
|
901
975
|
count: files.length,
|
|
902
|
-
phase_dir: phase ? dirs[0].replace(/^\d+(?:\.\d+)
|
|
976
|
+
phase_dir: phase ? dirs[0].replace(/^\d+[A-Za-z]?(?:\.\d+)*-?/, '') : null,
|
|
903
977
|
};
|
|
904
978
|
output(result, raw, files.join('\n'));
|
|
905
979
|
return;
|
|
@@ -1863,7 +1937,7 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
1863
1937
|
let phaseDirName = null;
|
|
1864
1938
|
try {
|
|
1865
1939
|
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
1866
|
-
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
|
|
1940
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => comparePhaseNum(a, b));
|
|
1867
1941
|
const match = dirs.find(d => d.startsWith(normalized));
|
|
1868
1942
|
if (match) {
|
|
1869
1943
|
phaseDir = path.join(phasesDir, match);
|
|
@@ -1899,9 +1973,10 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
1899
1973
|
const content = fs.readFileSync(planPath, 'utf-8');
|
|
1900
1974
|
const fm = extractFrontmatter(content);
|
|
1901
1975
|
|
|
1902
|
-
// Count tasks
|
|
1903
|
-
const
|
|
1904
|
-
const
|
|
1976
|
+
// Count tasks from canonical XML first, fallback to markdown task headings.
|
|
1977
|
+
const xmlTaskMatches = content.match(/<task\b[^>]*>/gi) || [];
|
|
1978
|
+
const markdownTaskMatches = content.match(/##\s*Task\s*\d+/gi) || [];
|
|
1979
|
+
const taskCount = xmlTaskMatches.length > 0 ? xmlTaskMatches.length : markdownTaskMatches.length;
|
|
1905
1980
|
|
|
1906
1981
|
// Parse wave as integer
|
|
1907
1982
|
const wave = parseInt(fm.wave, 10) || 1;
|
|
@@ -1916,10 +1991,24 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
1916
1991
|
hasCheckpoints = true;
|
|
1917
1992
|
}
|
|
1918
1993
|
|
|
1919
|
-
// Parse files-modified
|
|
1994
|
+
// Parse files-modified/files_modified (both accepted).
|
|
1920
1995
|
let filesModified = [];
|
|
1921
|
-
|
|
1922
|
-
|
|
1996
|
+
const filesModifiedField = fm.files_modified ?? fm['files-modified'];
|
|
1997
|
+
if (filesModifiedField) {
|
|
1998
|
+
filesModified = Array.isArray(filesModifiedField) ? filesModifiedField : [filesModifiedField];
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// Objective: canonical <objective> block first line overrides frontmatter objective.
|
|
2002
|
+
let objective = fm.objective || null;
|
|
2003
|
+
const objectiveTagMatch = content.match(/<objective>\s*([\s\S]*?)<\/objective>/i);
|
|
2004
|
+
if (objectiveTagMatch) {
|
|
2005
|
+
const firstLine = objectiveTagMatch[1]
|
|
2006
|
+
.split('\n')
|
|
2007
|
+
.map(line => line.trim())
|
|
2008
|
+
.find(Boolean);
|
|
2009
|
+
if (firstLine) {
|
|
2010
|
+
objective = firstLine;
|
|
2011
|
+
}
|
|
1923
2012
|
}
|
|
1924
2013
|
|
|
1925
2014
|
const hasSummary = completedPlanIds.has(planId);
|
|
@@ -1931,7 +2020,7 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
1931
2020
|
id: planId,
|
|
1932
2021
|
wave,
|
|
1933
2022
|
autonomous,
|
|
1934
|
-
objective
|
|
2023
|
+
objective,
|
|
1935
2024
|
files_modified: filesModified,
|
|
1936
2025
|
task_count: taskCount,
|
|
1937
2026
|
has_summary: hasSummary,
|
|
@@ -3158,16 +3247,16 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
3158
3247
|
// Update ROADMAP.md: mark phase complete
|
|
3159
3248
|
if (fs.existsSync(roadmapPath)) {
|
|
3160
3249
|
let roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
|
|
3250
|
+
const phaseEscaped = escapeRegex(phaseNum);
|
|
3161
3251
|
|
|
3162
3252
|
// Checkbox: - [ ] Phase N: β - [x] Phase N: (...completed DATE)
|
|
3163
3253
|
const checkboxPattern = new RegExp(
|
|
3164
|
-
`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${
|
|
3254
|
+
`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phaseEscaped}[:\\s][^\\n]*)`,
|
|
3165
3255
|
'i'
|
|
3166
3256
|
);
|
|
3167
3257
|
roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
|
|
3168
3258
|
|
|
3169
3259
|
// Progress table: update Status to Complete, add date
|
|
3170
|
-
const phaseEscaped = phaseNum.replace('.', '\\.');
|
|
3171
3260
|
const tablePattern = new RegExp(
|
|
3172
3261
|
`(\\|\\s*${phaseEscaped}\\.?\\s[^|]*\\|[^|]*\\|)\\s*[^|]*(\\|)\\s*[^|]*(\\|)`,
|
|
3173
3262
|
'i'
|
|
@@ -3192,24 +3281,26 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
3192
3281
|
// Update REQUIREMENTS.md traceability for this phase's requirements
|
|
3193
3282
|
const reqPath = path.join(cwd, '.planning', 'REQUIREMENTS.md');
|
|
3194
3283
|
if (fs.existsSync(reqPath)) {
|
|
3195
|
-
// Extract
|
|
3196
|
-
const
|
|
3197
|
-
new RegExp(
|
|
3284
|
+
// Extract only this phase's section to avoid leaking into later phases.
|
|
3285
|
+
const sectionMatch = roadmapContent.match(
|
|
3286
|
+
new RegExp(`#{2,4}\\s*Phase\\s+${phaseEscaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s*Phase\\s+\\d|$)`, 'i')
|
|
3198
3287
|
);
|
|
3199
3288
|
|
|
3200
|
-
if (
|
|
3201
|
-
const
|
|
3289
|
+
if (sectionMatch) {
|
|
3290
|
+
const reqMatch = sectionMatch[0].match(/\*\*Requirements:\*\*\s*([^\n]+)/i);
|
|
3291
|
+
const reqIds = reqMatch ? (reqMatch[1].match(/\b[A-Z][A-Z0-9_-]*-\d+\b/g) || []) : [];
|
|
3202
3292
|
let reqContent = fs.readFileSync(reqPath, 'utf-8');
|
|
3203
3293
|
|
|
3204
3294
|
for (const reqId of reqIds) {
|
|
3295
|
+
const escapedReqId = escapeRegex(reqId);
|
|
3205
3296
|
// Update checkbox: - [ ] **REQ-ID** β - [x] **REQ-ID**
|
|
3206
3297
|
reqContent = reqContent.replace(
|
|
3207
|
-
new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${
|
|
3298
|
+
new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${escapedReqId}\\*\\*)`, 'gi'),
|
|
3208
3299
|
'$1x$2'
|
|
3209
3300
|
);
|
|
3210
3301
|
// Update traceability table: | REQ-ID | Phase N | Pending | β | REQ-ID | Phase N | Complete |
|
|
3211
3302
|
reqContent = reqContent.replace(
|
|
3212
|
-
new RegExp(`(\\|\\s*${
|
|
3303
|
+
new RegExp(`(\\|\\s*${escapedReqId}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, 'gi'),
|
|
3213
3304
|
'$1 Complete $2'
|
|
3214
3305
|
);
|
|
3215
3306
|
}
|
|
@@ -3225,16 +3316,20 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
3225
3316
|
let isLastPhase = true;
|
|
3226
3317
|
|
|
3227
3318
|
try {
|
|
3319
|
+
const isMilestonePhase = getMilestonePhaseFilter(cwd);
|
|
3228
3320
|
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
3229
|
-
const dirs = entries
|
|
3230
|
-
|
|
3321
|
+
const dirs = entries
|
|
3322
|
+
.filter(e => e.isDirectory())
|
|
3323
|
+
.map(e => e.name)
|
|
3324
|
+
.filter(d => isMilestonePhase(d))
|
|
3325
|
+
.sort((a, b) => comparePhaseNum(a, b));
|
|
3326
|
+
const currentPhase = normalizePhaseName(phaseNum);
|
|
3231
3327
|
|
|
3232
3328
|
// Find the next phase directory after current
|
|
3233
3329
|
for (const dir of dirs) {
|
|
3234
|
-
const dm = dir.match(/^(\d+(?:\.\d+)
|
|
3330
|
+
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i);
|
|
3235
3331
|
if (dm) {
|
|
3236
|
-
|
|
3237
|
-
if (dirFloat > currentFloat) {
|
|
3332
|
+
if (comparePhaseNum(dm[1], currentPhase) > 0) {
|
|
3238
3333
|
nextPhaseNum = dm[1];
|
|
3239
3334
|
nextPhaseName = dm[2] || null;
|
|
3240
3335
|
isLastPhase = false;
|
|
@@ -3328,10 +3423,15 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
3328
3423
|
let totalPlans = 0;
|
|
3329
3424
|
let totalTasks = 0;
|
|
3330
3425
|
const accomplishments = [];
|
|
3426
|
+
const isMilestonePhase = getMilestonePhaseFilter(cwd);
|
|
3331
3427
|
|
|
3332
3428
|
try {
|
|
3333
3429
|
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
3334
|
-
const dirs = entries
|
|
3430
|
+
const dirs = entries
|
|
3431
|
+
.filter(e => e.isDirectory())
|
|
3432
|
+
.map(e => e.name)
|
|
3433
|
+
.filter(d => isMilestonePhase(d))
|
|
3434
|
+
.sort((a, b) => comparePhaseNum(a, b));
|
|
3335
3435
|
|
|
3336
3436
|
for (const dir of dirs) {
|
|
3337
3437
|
phaseCount++;
|
|
@@ -3375,13 +3475,16 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
3375
3475
|
fs.renameSync(auditFile, path.join(archiveDir, `${version}-MILESTONE-AUDIT.md`));
|
|
3376
3476
|
}
|
|
3377
3477
|
|
|
3378
|
-
// Create/
|
|
3478
|
+
// Create/prepend MILESTONES.md entry (reverse chronological order)
|
|
3379
3479
|
const accomplishmentsList = accomplishments.map(a => `- ${a}`).join('\n');
|
|
3380
3480
|
const milestoneEntry = `## ${version} ${milestoneName} (Shipped: ${today})\n\n**Phases completed:** ${phaseCount} phases, ${totalPlans} plans, ${totalTasks} tasks\n\n**Key accomplishments:**\n${accomplishmentsList || '- (none recorded)'}\n\n---\n\n`;
|
|
3381
3481
|
|
|
3382
3482
|
if (fs.existsSync(milestonesPath)) {
|
|
3383
3483
|
const existing = fs.readFileSync(milestonesPath, 'utf-8');
|
|
3384
|
-
|
|
3484
|
+
const existingBody = existing
|
|
3485
|
+
.replace(/^#\s*Milestones[^\n]*\n*/i, '')
|
|
3486
|
+
.trimStart();
|
|
3487
|
+
fs.writeFileSync(milestonesPath, `# Milestones\n\n${milestoneEntry}${existingBody}`, 'utf-8');
|
|
3385
3488
|
} else {
|
|
3386
3489
|
fs.writeFileSync(milestonesPath, `# Milestones\n\n${milestoneEntry}`, 'utf-8');
|
|
3387
3490
|
}
|
|
@@ -3412,7 +3515,11 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
3412
3515
|
fs.mkdirSync(phaseArchiveDir, { recursive: true });
|
|
3413
3516
|
|
|
3414
3517
|
const phaseEntries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
3415
|
-
const phaseDirNames = phaseEntries
|
|
3518
|
+
const phaseDirNames = phaseEntries
|
|
3519
|
+
.filter(e => e.isDirectory())
|
|
3520
|
+
.map(e => e.name)
|
|
3521
|
+
.filter(d => isMilestonePhase(d))
|
|
3522
|
+
.sort((a, b) => comparePhaseNum(a, b));
|
|
3416
3523
|
for (const dir of phaseDirNames) {
|
|
3417
3524
|
fs.renameSync(path.join(phasesDir, dir), path.join(phaseArchiveDir, dir));
|
|
3418
3525
|
}
|
|
@@ -3977,15 +4084,15 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
3977
4084
|
if (override) {
|
|
3978
4085
|
// Override can be a string (legacy) or { m, t } object
|
|
3979
4086
|
if (typeof override === 'string') {
|
|
3980
|
-
return { model: 'inherit', thinking: override === 'high' || override === 'medium' || override === 'low' ? override : '
|
|
4087
|
+
return { model: 'inherit', thinking: override === 'xhigh' || override === 'high' || override === 'medium' || override === 'low' ? override : 'high' };
|
|
3981
4088
|
}
|
|
3982
|
-
return { model: 'inherit', thinking: override.t || '
|
|
4089
|
+
return { model: 'inherit', thinking: override.t || 'high' };
|
|
3983
4090
|
}
|
|
3984
4091
|
|
|
3985
4092
|
// Fall back to profile lookup
|
|
3986
4093
|
const profile = config.model_profile || 'balanced';
|
|
3987
4094
|
const agentModels = MODEL_PROFILES[agentType];
|
|
3988
|
-
if (!agentModels) return { model: 'inherit', thinking: '
|
|
4095
|
+
if (!agentModels) return { model: 'inherit', thinking: 'high' };
|
|
3989
4096
|
const entry = agentModels[profile] || agentModels['balanced'] || DEFAULT_ENTRY;
|
|
3990
4097
|
return { model: 'inherit', thinking: entry.t };
|
|
3991
4098
|
}
|
|
@@ -4844,12 +4951,54 @@ function cmdInitProgress(cwd, includes, raw) {
|
|
|
4844
4951
|
|
|
4845
4952
|
async function main() {
|
|
4846
4953
|
const args = process.argv.slice(2);
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4954
|
+
let raw = false;
|
|
4955
|
+
let cwd = process.cwd();
|
|
4956
|
+
|
|
4957
|
+
const setCwd = (value) => {
|
|
4958
|
+
if (!value) {
|
|
4959
|
+
error('Missing value for --cwd');
|
|
4960
|
+
}
|
|
4961
|
+
const resolved = path.resolve(process.cwd(), value);
|
|
4962
|
+
try {
|
|
4963
|
+
const stat = fs.statSync(resolved);
|
|
4964
|
+
if (!stat.isDirectory()) {
|
|
4965
|
+
throw new Error('not-a-dir');
|
|
4966
|
+
}
|
|
4967
|
+
} catch {
|
|
4968
|
+
error(`Invalid --cwd: ${value}`);
|
|
4969
|
+
}
|
|
4970
|
+
cwd = resolved;
|
|
4971
|
+
};
|
|
4972
|
+
|
|
4973
|
+
for (let i = 0; i < args.length;) {
|
|
4974
|
+
const arg = args[i];
|
|
4975
|
+
if (arg === '--raw') {
|
|
4976
|
+
raw = true;
|
|
4977
|
+
args.splice(i, 1);
|
|
4978
|
+
continue;
|
|
4979
|
+
}
|
|
4980
|
+
if (arg === '--cwd') {
|
|
4981
|
+
const value = args[i + 1];
|
|
4982
|
+
if (!value || value.startsWith('--')) {
|
|
4983
|
+
error('Missing value for --cwd');
|
|
4984
|
+
}
|
|
4985
|
+
setCwd(value);
|
|
4986
|
+
args.splice(i, 2);
|
|
4987
|
+
continue;
|
|
4988
|
+
}
|
|
4989
|
+
if (arg.startsWith('--cwd=')) {
|
|
4990
|
+
const value = arg.slice('--cwd='.length);
|
|
4991
|
+
if (!value) {
|
|
4992
|
+
error('Missing value for --cwd');
|
|
4993
|
+
}
|
|
4994
|
+
setCwd(value);
|
|
4995
|
+
args.splice(i, 1);
|
|
4996
|
+
continue;
|
|
4997
|
+
}
|
|
4998
|
+
i++;
|
|
4999
|
+
}
|
|
4850
5000
|
|
|
4851
5001
|
const command = args[0];
|
|
4852
|
-
const cwd = process.cwd();
|
|
4853
5002
|
|
|
4854
5003
|
if (!command) {
|
|
4855
5004
|
error('Usage: gsd-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, init');
|
|
@@ -4859,9 +5008,9 @@ async function main() {
|
|
|
4859
5008
|
case 'state': {
|
|
4860
5009
|
const subcommand = args[1];
|
|
4861
5010
|
if (subcommand === 'update') {
|
|
4862
|
-
cmdStateUpdate(cwd, args[2], args[3]);
|
|
5011
|
+
stateLib.cmdStateUpdate(cwd, args[2], args[3]);
|
|
4863
5012
|
} else if (subcommand === 'get') {
|
|
4864
|
-
cmdStateGet(cwd, args[2], raw);
|
|
5013
|
+
stateLib.cmdStateGet(cwd, args[2], raw);
|
|
4865
5014
|
} else if (subcommand === 'patch') {
|
|
4866
5015
|
const patches = {};
|
|
4867
5016
|
for (let i = 2; i < args.length; i += 2) {
|
|
@@ -4871,16 +5020,18 @@ async function main() {
|
|
|
4871
5020
|
patches[key] = value;
|
|
4872
5021
|
}
|
|
4873
5022
|
}
|
|
4874
|
-
cmdStatePatch(cwd, patches, raw);
|
|
5023
|
+
stateLib.cmdStatePatch(cwd, patches, raw);
|
|
5024
|
+
} else if (subcommand === 'json') {
|
|
5025
|
+
stateLib.cmdStateJson(cwd, raw);
|
|
4875
5026
|
} else if (subcommand === 'advance-plan') {
|
|
4876
|
-
cmdStateAdvancePlan(cwd, raw);
|
|
5027
|
+
stateLib.cmdStateAdvancePlan(cwd, raw);
|
|
4877
5028
|
} else if (subcommand === 'record-metric') {
|
|
4878
5029
|
const phaseIdx = args.indexOf('--phase');
|
|
4879
5030
|
const planIdx = args.indexOf('--plan');
|
|
4880
5031
|
const durationIdx = args.indexOf('--duration');
|
|
4881
5032
|
const tasksIdx = args.indexOf('--tasks');
|
|
4882
5033
|
const filesIdx = args.indexOf('--files');
|
|
4883
|
-
cmdStateRecordMetric(cwd, {
|
|
5034
|
+
stateLib.cmdStateRecordMetric(cwd, {
|
|
4884
5035
|
phase: phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
|
4885
5036
|
plan: planIdx !== -1 ? args[planIdx + 1] : null,
|
|
4886
5037
|
duration: durationIdx !== -1 ? args[durationIdx + 1] : null,
|
|
@@ -4888,42 +5039,50 @@ async function main() {
|
|
|
4888
5039
|
files: filesIdx !== -1 ? args[filesIdx + 1] : null,
|
|
4889
5040
|
}, raw);
|
|
4890
5041
|
} else if (subcommand === 'update-progress') {
|
|
4891
|
-
cmdStateUpdateProgress(cwd, raw);
|
|
5042
|
+
stateLib.cmdStateUpdateProgress(cwd, raw);
|
|
4892
5043
|
} else if (subcommand === 'add-decision') {
|
|
4893
5044
|
const phaseIdx = args.indexOf('--phase');
|
|
4894
5045
|
const summaryIdx = args.indexOf('--summary');
|
|
5046
|
+
const summaryFileIdx = args.indexOf('--summary-file');
|
|
4895
5047
|
const rationaleIdx = args.indexOf('--rationale');
|
|
4896
|
-
|
|
5048
|
+
const rationaleFileIdx = args.indexOf('--rationale-file');
|
|
5049
|
+
stateLib.cmdStateAddDecision(cwd, {
|
|
4897
5050
|
phase: phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
|
4898
5051
|
summary: summaryIdx !== -1 ? args[summaryIdx + 1] : null,
|
|
5052
|
+
summary_file: summaryFileIdx !== -1 ? args[summaryFileIdx + 1] : null,
|
|
4899
5053
|
rationale: rationaleIdx !== -1 ? args[rationaleIdx + 1] : '',
|
|
5054
|
+
rationale_file: rationaleFileIdx !== -1 ? args[rationaleFileIdx + 1] : null,
|
|
4900
5055
|
}, raw);
|
|
4901
5056
|
} else if (subcommand === 'add-blocker') {
|
|
4902
5057
|
const textIdx = args.indexOf('--text');
|
|
4903
|
-
|
|
5058
|
+
const textFileIdx = args.indexOf('--text-file');
|
|
5059
|
+
stateLib.cmdStateAddBlocker(cwd, {
|
|
5060
|
+
text: textIdx !== -1 ? args[textIdx + 1] : null,
|
|
5061
|
+
text_file: textFileIdx !== -1 ? args[textFileIdx + 1] : null,
|
|
5062
|
+
}, raw);
|
|
4904
5063
|
} else if (subcommand === 'resolve-blocker') {
|
|
4905
5064
|
const textIdx = args.indexOf('--text');
|
|
4906
|
-
cmdStateResolveBlocker(cwd, textIdx !== -1 ? args[textIdx + 1] : null, raw);
|
|
5065
|
+
stateLib.cmdStateResolveBlocker(cwd, textIdx !== -1 ? args[textIdx + 1] : null, raw);
|
|
4907
5066
|
} else if (subcommand === 'record-session') {
|
|
4908
5067
|
const stoppedIdx = args.indexOf('--stopped-at');
|
|
4909
5068
|
const resumeIdx = args.indexOf('--resume-file');
|
|
4910
|
-
cmdStateRecordSession(cwd, {
|
|
5069
|
+
stateLib.cmdStateRecordSession(cwd, {
|
|
4911
5070
|
stopped_at: stoppedIdx !== -1 ? args[stoppedIdx + 1] : null,
|
|
4912
5071
|
resume_file: resumeIdx !== -1 ? args[resumeIdx + 1] : 'None',
|
|
4913
5072
|
}, raw);
|
|
4914
5073
|
} else {
|
|
4915
|
-
cmdStateLoad(cwd, raw);
|
|
5074
|
+
stateLib.cmdStateLoad(cwd, raw);
|
|
4916
5075
|
}
|
|
4917
5076
|
break;
|
|
4918
5077
|
}
|
|
4919
5078
|
|
|
4920
5079
|
case 'resolve-model': {
|
|
4921
|
-
cmdResolveModel(cwd, args[1], raw);
|
|
5080
|
+
commandsLib.cmdResolveModel(cwd, args[1], raw);
|
|
4922
5081
|
break;
|
|
4923
5082
|
}
|
|
4924
5083
|
|
|
4925
5084
|
case 'find-phase': {
|
|
4926
|
-
cmdFindPhase(cwd, args[1], raw);
|
|
5085
|
+
phaseLib.cmdFindPhase(cwd, args[1], raw);
|
|
4927
5086
|
break;
|
|
4928
5087
|
}
|
|
4929
5088
|
|
|
@@ -4933,7 +5092,7 @@ async function main() {
|
|
|
4933
5092
|
// Parse --files flag (collect args after --files, stopping at other flags)
|
|
4934
5093
|
const filesIndex = args.indexOf('--files');
|
|
4935
5094
|
const files = filesIndex !== -1 ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--')) : [];
|
|
4936
|
-
cmdCommit(cwd, message, files, raw, amend);
|
|
5095
|
+
commandsLib.cmdCommit(cwd, message, files, raw, amend);
|
|
4937
5096
|
break;
|
|
4938
5097
|
}
|
|
4939
5098
|
|
|
@@ -4941,14 +5100,14 @@ async function main() {
|
|
|
4941
5100
|
const summaryPath = args[1];
|
|
4942
5101
|
const countIndex = args.indexOf('--check-count');
|
|
4943
5102
|
const checkCount = countIndex !== -1 ? parseInt(args[countIndex + 1], 10) : 2;
|
|
4944
|
-
cmdVerifySummary(cwd, summaryPath, checkCount, raw);
|
|
5103
|
+
verifyLib.cmdVerifySummary(cwd, summaryPath, checkCount, raw);
|
|
4945
5104
|
break;
|
|
4946
5105
|
}
|
|
4947
5106
|
|
|
4948
5107
|
case 'template': {
|
|
4949
5108
|
const subcommand = args[1];
|
|
4950
5109
|
if (subcommand === 'select') {
|
|
4951
|
-
cmdTemplateSelect(cwd, args[2], raw);
|
|
5110
|
+
templateLib.cmdTemplateSelect(cwd, args[2], raw);
|
|
4952
5111
|
} else if (subcommand === 'fill') {
|
|
4953
5112
|
const templateType = args[2];
|
|
4954
5113
|
const phaseIdx = args.indexOf('--phase');
|
|
@@ -4957,7 +5116,7 @@ async function main() {
|
|
|
4957
5116
|
const typeIdx = args.indexOf('--type');
|
|
4958
5117
|
const waveIdx = args.indexOf('--wave');
|
|
4959
5118
|
const fieldsIdx = args.indexOf('--fields');
|
|
4960
|
-
cmdTemplateFill(cwd, templateType, {
|
|
5119
|
+
templateLib.cmdTemplateFill(cwd, templateType, {
|
|
4961
5120
|
phase: phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
|
4962
5121
|
plan: planIdx !== -1 ? args[planIdx + 1] : null,
|
|
4963
5122
|
name: nameIdx !== -1 ? args[nameIdx + 1] : null,
|
|
@@ -4976,17 +5135,17 @@ async function main() {
|
|
|
4976
5135
|
const file = args[2];
|
|
4977
5136
|
if (subcommand === 'get') {
|
|
4978
5137
|
const fieldIdx = args.indexOf('--field');
|
|
4979
|
-
cmdFrontmatterGet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, raw);
|
|
5138
|
+
frontmatterLib.cmdFrontmatterGet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, raw);
|
|
4980
5139
|
} else if (subcommand === 'set') {
|
|
4981
5140
|
const fieldIdx = args.indexOf('--field');
|
|
4982
5141
|
const valueIdx = args.indexOf('--value');
|
|
4983
|
-
cmdFrontmatterSet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, valueIdx !== -1 ? args[valueIdx + 1] : undefined, raw);
|
|
5142
|
+
frontmatterLib.cmdFrontmatterSet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, valueIdx !== -1 ? args[valueIdx + 1] : undefined, raw);
|
|
4984
5143
|
} else if (subcommand === 'merge') {
|
|
4985
5144
|
const dataIdx = args.indexOf('--data');
|
|
4986
|
-
cmdFrontmatterMerge(cwd, file, dataIdx !== -1 ? args[dataIdx + 1] : null, raw);
|
|
5145
|
+
frontmatterLib.cmdFrontmatterMerge(cwd, file, dataIdx !== -1 ? args[dataIdx + 1] : null, raw);
|
|
4987
5146
|
} else if (subcommand === 'validate') {
|
|
4988
5147
|
const schemaIdx = args.indexOf('--schema');
|
|
4989
|
-
cmdFrontmatterValidate(cwd, file, schemaIdx !== -1 ? args[schemaIdx + 1] : null, raw);
|
|
5148
|
+
frontmatterLib.cmdFrontmatterValidate(cwd, file, schemaIdx !== -1 ? args[schemaIdx + 1] : null, raw);
|
|
4990
5149
|
} else {
|
|
4991
5150
|
error('Unknown frontmatter subcommand. Available: get, set, merge, validate');
|
|
4992
5151
|
}
|
|
@@ -4996,17 +5155,17 @@ async function main() {
|
|
|
4996
5155
|
case 'verify': {
|
|
4997
5156
|
const subcommand = args[1];
|
|
4998
5157
|
if (subcommand === 'plan-structure') {
|
|
4999
|
-
cmdVerifyPlanStructure(cwd, args[2], raw);
|
|
5158
|
+
verifyLib.cmdVerifyPlanStructure(cwd, args[2], raw);
|
|
5000
5159
|
} else if (subcommand === 'phase-completeness') {
|
|
5001
|
-
cmdVerifyPhaseCompleteness(cwd, args[2], raw);
|
|
5160
|
+
verifyLib.cmdVerifyPhaseCompleteness(cwd, args[2], raw);
|
|
5002
5161
|
} else if (subcommand === 'references') {
|
|
5003
|
-
cmdVerifyReferences(cwd, args[2], raw);
|
|
5162
|
+
verifyLib.cmdVerifyReferences(cwd, args[2], raw);
|
|
5004
5163
|
} else if (subcommand === 'commits') {
|
|
5005
|
-
cmdVerifyCommits(cwd, args.slice(2), raw);
|
|
5164
|
+
verifyLib.cmdVerifyCommits(cwd, args.slice(2), raw);
|
|
5006
5165
|
} else if (subcommand === 'artifacts') {
|
|
5007
|
-
cmdVerifyArtifacts(cwd, args[2], raw);
|
|
5166
|
+
verifyLib.cmdVerifyArtifacts(cwd, args[2], raw);
|
|
5008
5167
|
} else if (subcommand === 'key-links') {
|
|
5009
|
-
cmdVerifyKeyLinks(cwd, args[2], raw);
|
|
5168
|
+
verifyLib.cmdVerifyKeyLinks(cwd, args[2], raw);
|
|
5010
5169
|
} else {
|
|
5011
5170
|
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links');
|
|
5012
5171
|
}
|
|
@@ -5014,42 +5173,42 @@ async function main() {
|
|
|
5014
5173
|
}
|
|
5015
5174
|
|
|
5016
5175
|
case 'generate-slug': {
|
|
5017
|
-
cmdGenerateSlug(args[1], raw);
|
|
5176
|
+
commandsLib.cmdGenerateSlug(args[1], raw);
|
|
5018
5177
|
break;
|
|
5019
5178
|
}
|
|
5020
5179
|
|
|
5021
5180
|
case 'current-timestamp': {
|
|
5022
|
-
cmdCurrentTimestamp(args[1] || 'full', raw);
|
|
5181
|
+
commandsLib.cmdCurrentTimestamp(args[1] || 'full', raw);
|
|
5023
5182
|
break;
|
|
5024
5183
|
}
|
|
5025
5184
|
|
|
5026
5185
|
case 'list-todos': {
|
|
5027
|
-
cmdListTodos(cwd, args[1], raw);
|
|
5186
|
+
commandsLib.cmdListTodos(cwd, args[1], raw);
|
|
5028
5187
|
break;
|
|
5029
5188
|
}
|
|
5030
5189
|
|
|
5031
5190
|
case 'verify-path-exists': {
|
|
5032
|
-
cmdVerifyPathExists(cwd, args[1], raw);
|
|
5191
|
+
commandsLib.cmdVerifyPathExists(cwd, args[1], raw);
|
|
5033
5192
|
break;
|
|
5034
5193
|
}
|
|
5035
5194
|
|
|
5036
5195
|
case 'config-ensure-section': {
|
|
5037
|
-
cmdConfigEnsureSection(cwd, raw);
|
|
5196
|
+
configLib.cmdConfigEnsureSection(cwd, raw);
|
|
5038
5197
|
break;
|
|
5039
5198
|
}
|
|
5040
5199
|
|
|
5041
5200
|
case 'config-set': {
|
|
5042
|
-
cmdConfigSet(cwd, args[1], args[2], raw);
|
|
5201
|
+
configLib.cmdConfigSet(cwd, args[1], args[2], raw);
|
|
5043
5202
|
break;
|
|
5044
5203
|
}
|
|
5045
5204
|
|
|
5046
5205
|
case 'config-get': {
|
|
5047
|
-
cmdConfigGet(cwd, args[1], raw);
|
|
5206
|
+
configLib.cmdConfigGet(cwd, args[1], raw);
|
|
5048
5207
|
break;
|
|
5049
5208
|
}
|
|
5050
5209
|
|
|
5051
5210
|
case 'history-digest': {
|
|
5052
|
-
cmdHistoryDigest(cwd, raw);
|
|
5211
|
+
commandsLib.cmdHistoryDigest(cwd, raw);
|
|
5053
5212
|
break;
|
|
5054
5213
|
}
|
|
5055
5214
|
|
|
@@ -5063,7 +5222,7 @@ async function main() {
|
|
|
5063
5222
|
phase: phaseIndex !== -1 ? args[phaseIndex + 1] : null,
|
|
5064
5223
|
includeArchived: args.includes('--include-archived'),
|
|
5065
5224
|
};
|
|
5066
|
-
cmdPhasesList(cwd, options, raw);
|
|
5225
|
+
phaseLib.cmdPhasesList(cwd, options, raw);
|
|
5067
5226
|
} else {
|
|
5068
5227
|
error('Unknown phases subcommand. Available: list');
|
|
5069
5228
|
}
|
|
@@ -5073,11 +5232,11 @@ async function main() {
|
|
|
5073
5232
|
case 'roadmap': {
|
|
5074
5233
|
const subcommand = args[1];
|
|
5075
5234
|
if (subcommand === 'get-phase') {
|
|
5076
|
-
cmdRoadmapGetPhase(cwd, args[2], raw);
|
|
5235
|
+
roadmapLib.cmdRoadmapGetPhase(cwd, args[2], raw);
|
|
5077
5236
|
} else if (subcommand === 'analyze') {
|
|
5078
|
-
cmdRoadmapAnalyze(cwd, raw);
|
|
5237
|
+
roadmapLib.cmdRoadmapAnalyze(cwd, raw);
|
|
5079
5238
|
} else if (subcommand === 'update-plan-progress') {
|
|
5080
|
-
cmdRoadmapUpdatePlanProgress(cwd, args[2], raw);
|
|
5239
|
+
roadmapLib.cmdRoadmapUpdatePlanProgress(cwd, args[2], raw);
|
|
5081
5240
|
} else {
|
|
5082
5241
|
error('Unknown roadmap subcommand. Available: get-phase, analyze, update-plan-progress');
|
|
5083
5242
|
}
|
|
@@ -5087,22 +5246,32 @@ async function main() {
|
|
|
5087
5246
|
case 'phase': {
|
|
5088
5247
|
const subcommand = args[1];
|
|
5089
5248
|
if (subcommand === 'next-decimal') {
|
|
5090
|
-
cmdPhaseNextDecimal(cwd, args[2], raw);
|
|
5249
|
+
phaseLib.cmdPhaseNextDecimal(cwd, args[2], raw);
|
|
5091
5250
|
} else if (subcommand === 'add') {
|
|
5092
|
-
cmdPhaseAdd(cwd, args.slice(2).join(' '), raw);
|
|
5251
|
+
phaseLib.cmdPhaseAdd(cwd, args.slice(2).join(' '), raw);
|
|
5093
5252
|
} else if (subcommand === 'insert') {
|
|
5094
|
-
cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
|
|
5253
|
+
phaseLib.cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
|
|
5095
5254
|
} else if (subcommand === 'remove') {
|
|
5096
5255
|
const forceFlag = args.includes('--force');
|
|
5097
|
-
cmdPhaseRemove(cwd, args[2], { force: forceFlag }, raw);
|
|
5256
|
+
phaseLib.cmdPhaseRemove(cwd, args[2], { force: forceFlag }, raw);
|
|
5098
5257
|
} else if (subcommand === 'complete') {
|
|
5099
|
-
cmdPhaseComplete(cwd, args[2], raw);
|
|
5258
|
+
phaseLib.cmdPhaseComplete(cwd, args[2], raw);
|
|
5100
5259
|
} else {
|
|
5101
5260
|
error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete');
|
|
5102
5261
|
}
|
|
5103
5262
|
break;
|
|
5104
5263
|
}
|
|
5105
5264
|
|
|
5265
|
+
case 'requirements': {
|
|
5266
|
+
const subcommand = args[1];
|
|
5267
|
+
if (subcommand === 'mark-complete') {
|
|
5268
|
+
milestoneLib.cmdRequirementsMarkComplete(cwd, args.slice(2), raw);
|
|
5269
|
+
} else {
|
|
5270
|
+
error('Unknown requirements subcommand. Available: mark-complete');
|
|
5271
|
+
}
|
|
5272
|
+
break;
|
|
5273
|
+
}
|
|
5274
|
+
|
|
5106
5275
|
case 'milestone': {
|
|
5107
5276
|
const subcommand = args[1];
|
|
5108
5277
|
if (subcommand === 'complete') {
|
|
@@ -5118,7 +5287,7 @@ async function main() {
|
|
|
5118
5287
|
}
|
|
5119
5288
|
milestoneName = nameArgs.join(' ') || null;
|
|
5120
5289
|
}
|
|
5121
|
-
cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases }, raw);
|
|
5290
|
+
milestoneLib.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases }, raw);
|
|
5122
5291
|
} else {
|
|
5123
5292
|
error('Unknown milestone subcommand. Available: complete');
|
|
5124
5293
|
}
|
|
@@ -5128,10 +5297,10 @@ async function main() {
|
|
|
5128
5297
|
case 'validate': {
|
|
5129
5298
|
const subcommand = args[1];
|
|
5130
5299
|
if (subcommand === 'consistency') {
|
|
5131
|
-
cmdValidateConsistency(cwd, raw);
|
|
5300
|
+
verifyLib.cmdValidateConsistency(cwd, raw);
|
|
5132
5301
|
} else if (subcommand === 'health') {
|
|
5133
5302
|
const repairFlag = args.includes('--repair');
|
|
5134
|
-
cmdValidateHealth(cwd, { repair: repairFlag }, raw);
|
|
5303
|
+
verifyLib.cmdValidateHealth(cwd, { repair: repairFlag }, raw);
|
|
5135
5304
|
} else {
|
|
5136
5305
|
error('Unknown validate subcommand. Available: consistency, health');
|
|
5137
5306
|
}
|
|
@@ -5140,14 +5309,14 @@ async function main() {
|
|
|
5140
5309
|
|
|
5141
5310
|
case 'progress': {
|
|
5142
5311
|
const subcommand = args[1] || 'json';
|
|
5143
|
-
cmdProgressRender(cwd, subcommand, raw);
|
|
5312
|
+
commandsLib.cmdProgressRender(cwd, subcommand, raw);
|
|
5144
5313
|
break;
|
|
5145
5314
|
}
|
|
5146
5315
|
|
|
5147
5316
|
case 'todo': {
|
|
5148
5317
|
const subcommand = args[1];
|
|
5149
5318
|
if (subcommand === 'complete') {
|
|
5150
|
-
cmdTodoComplete(cwd, args[2], raw);
|
|
5319
|
+
commandsLib.cmdTodoComplete(cwd, args[2], raw);
|
|
5151
5320
|
} else {
|
|
5152
5321
|
error('Unknown todo subcommand. Available: complete');
|
|
5153
5322
|
}
|
|
@@ -5162,7 +5331,7 @@ async function main() {
|
|
|
5162
5331
|
phase: phaseIndex !== -1 ? args[phaseIndex + 1] : null,
|
|
5163
5332
|
name: nameIndex !== -1 ? args.slice(nameIndex + 1).join(' ') : null,
|
|
5164
5333
|
};
|
|
5165
|
-
cmdScaffold(cwd, scaffoldType, scaffoldOptions, raw);
|
|
5334
|
+
commandsLib.cmdScaffold(cwd, scaffoldType, scaffoldOptions, raw);
|
|
5166
5335
|
break;
|
|
5167
5336
|
}
|
|
5168
5337
|
|
|
@@ -5171,40 +5340,40 @@ async function main() {
|
|
|
5171
5340
|
const includes = parseIncludeFlag(args);
|
|
5172
5341
|
switch (workflow) {
|
|
5173
5342
|
case 'execute-phase':
|
|
5174
|
-
cmdInitExecutePhase(cwd, args[2],
|
|
5343
|
+
initLib.cmdInitExecutePhase(cwd, args[2], raw);
|
|
5175
5344
|
break;
|
|
5176
5345
|
case 'plan-phase':
|
|
5177
|
-
cmdInitPlanPhase(cwd, args[2],
|
|
5346
|
+
initLib.cmdInitPlanPhase(cwd, args[2], raw);
|
|
5178
5347
|
break;
|
|
5179
5348
|
case 'new-project':
|
|
5180
|
-
cmdInitNewProject(cwd, raw);
|
|
5349
|
+
initLib.cmdInitNewProject(cwd, raw);
|
|
5181
5350
|
break;
|
|
5182
5351
|
case 'new-milestone':
|
|
5183
|
-
cmdInitNewMilestone(cwd, raw);
|
|
5352
|
+
initLib.cmdInitNewMilestone(cwd, raw);
|
|
5184
5353
|
break;
|
|
5185
5354
|
case 'quick':
|
|
5186
|
-
cmdInitQuick(cwd, args.slice(2).join(' '), raw);
|
|
5355
|
+
initLib.cmdInitQuick(cwd, args.slice(2).join(' '), raw);
|
|
5187
5356
|
break;
|
|
5188
5357
|
case 'resume':
|
|
5189
|
-
cmdInitResume(cwd, raw);
|
|
5358
|
+
initLib.cmdInitResume(cwd, raw);
|
|
5190
5359
|
break;
|
|
5191
5360
|
case 'verify-work':
|
|
5192
|
-
cmdInitVerifyWork(cwd, args[2], raw);
|
|
5361
|
+
initLib.cmdInitVerifyWork(cwd, args[2], raw);
|
|
5193
5362
|
break;
|
|
5194
5363
|
case 'phase-op':
|
|
5195
|
-
cmdInitPhaseOp(cwd, args[2], raw);
|
|
5364
|
+
initLib.cmdInitPhaseOp(cwd, args[2], raw);
|
|
5196
5365
|
break;
|
|
5197
5366
|
case 'todos':
|
|
5198
|
-
cmdInitTodos(cwd, args[2], raw);
|
|
5367
|
+
initLib.cmdInitTodos(cwd, args[2], raw);
|
|
5199
5368
|
break;
|
|
5200
5369
|
case 'milestone-op':
|
|
5201
|
-
cmdInitMilestoneOp(cwd, raw);
|
|
5370
|
+
initLib.cmdInitMilestoneOp(cwd, raw);
|
|
5202
5371
|
break;
|
|
5203
5372
|
case 'map-codebase':
|
|
5204
|
-
cmdInitMapCodebase(cwd, raw);
|
|
5373
|
+
initLib.cmdInitMapCodebase(cwd, raw);
|
|
5205
5374
|
break;
|
|
5206
5375
|
case 'progress':
|
|
5207
|
-
cmdInitProgress(cwd, includes, raw);
|
|
5376
|
+
initLib.cmdInitProgress(cwd, includes, raw);
|
|
5208
5377
|
break;
|
|
5209
5378
|
default:
|
|
5210
5379
|
error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, phase-op, todos, milestone-op, map-codebase, progress`);
|
|
@@ -5213,12 +5382,12 @@ async function main() {
|
|
|
5213
5382
|
}
|
|
5214
5383
|
|
|
5215
5384
|
case 'phase-plan-index': {
|
|
5216
|
-
cmdPhasePlanIndex(cwd, args[1], raw);
|
|
5385
|
+
phaseLib.cmdPhasePlanIndex(cwd, args[1], raw);
|
|
5217
5386
|
break;
|
|
5218
5387
|
}
|
|
5219
5388
|
|
|
5220
5389
|
case 'state-snapshot': {
|
|
5221
|
-
cmdStateSnapshot(cwd, raw);
|
|
5390
|
+
stateLib.cmdStateSnapshot(cwd, raw);
|
|
5222
5391
|
break;
|
|
5223
5392
|
}
|
|
5224
5393
|
|
|
@@ -5226,7 +5395,7 @@ async function main() {
|
|
|
5226
5395
|
const summaryPath = args[1];
|
|
5227
5396
|
const fieldsIndex = args.indexOf('--fields');
|
|
5228
5397
|
const fields = fieldsIndex !== -1 ? args[fieldsIndex + 1].split(',') : null;
|
|
5229
|
-
cmdSummaryExtract(cwd, summaryPath, fields, raw);
|
|
5398
|
+
commandsLib.cmdSummaryExtract(cwd, summaryPath, fields, raw);
|
|
5230
5399
|
break;
|
|
5231
5400
|
}
|
|
5232
5401
|
|
|
@@ -5234,7 +5403,7 @@ async function main() {
|
|
|
5234
5403
|
const query = args[1];
|
|
5235
5404
|
const limitIdx = args.indexOf('--limit');
|
|
5236
5405
|
const freshnessIdx = args.indexOf('--freshness');
|
|
5237
|
-
await cmdWebsearch(query, {
|
|
5406
|
+
await commandsLib.cmdWebsearch(query, {
|
|
5238
5407
|
limit: limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : 10,
|
|
5239
5408
|
freshness: freshnessIdx !== -1 ? args[freshnessIdx + 1] : null,
|
|
5240
5409
|
}, raw);
|
|
@@ -16,21 +16,21 @@ function toPosixPath(p) {
|
|
|
16
16
|
// βββ Model Profile Table βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
17
17
|
|
|
18
18
|
const MODEL_PROFILES = {
|
|
19
|
-
// quality
|
|
20
|
-
'gsd-planner': { quality: { m: 'gpt-5.3-codex', t: '
|
|
21
|
-
'gsd-roadmapper': { quality: { m: 'gpt-5.3-codex', t: '
|
|
22
|
-
'gsd-executor': { quality: { m: 'gpt-5.3-codex', t: '
|
|
23
|
-
'gsd-phase-researcher': { quality: { m: 'gpt-5.3-codex', t: '
|
|
24
|
-
'gsd-project-researcher': { quality: { m: 'gpt-5.3-codex', t: '
|
|
25
|
-
'gsd-research-synthesizer': { quality: { m: 'gpt-5.3-codex', t: '
|
|
26
|
-
'gsd-debugger': { quality: { m: 'gpt-5.3-codex', t: '
|
|
27
|
-
'gsd-codebase-mapper': { quality: { m: 'gpt-5.3-codex', t: '
|
|
28
|
-
'gsd-verifier': { quality: { m: 'gpt-5.3-codex', t: '
|
|
29
|
-
'gsd-plan-checker': { quality: { m: 'gpt-5.3-codex', t: '
|
|
30
|
-
'gsd-integration-checker': { quality: { m: 'gpt-5.3-codex', t: '
|
|
19
|
+
// quality balanced budget
|
|
20
|
+
'gsd-planner': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'xhigh' }, budget: { m: 'gpt-5.3-codex', t: 'high' } },
|
|
21
|
+
'gsd-roadmapper': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
22
|
+
'gsd-executor': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
23
|
+
'gsd-phase-researcher': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
24
|
+
'gsd-project-researcher': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
25
|
+
'gsd-research-synthesizer': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
26
|
+
'gsd-debugger': { quality: { m: 'gpt-5.3-codex', t: 'xhigh' }, balanced: { m: 'gpt-5.3-codex', t: 'xhigh' }, budget: { m: 'gpt-5.3-codex', t: 'high' } },
|
|
27
|
+
'gsd-codebase-mapper': { quality: { m: 'gpt-5.3-codex', t: 'medium' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
28
|
+
'gsd-verifier': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'high' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
29
|
+
'gsd-plan-checker': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
30
|
+
'gsd-integration-checker': { quality: { m: 'gpt-5.3-codex', t: 'high' }, balanced: { m: 'gpt-5.3-codex', t: 'medium' }, budget: { m: 'gpt-5.3-codex', t: 'medium' } },
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const DEFAULT_ENTRY = { m: 'gpt-5.3-codex', t: '
|
|
33
|
+
const DEFAULT_ENTRY = { m: 'gpt-5.3-codex', t: 'high' };
|
|
34
34
|
|
|
35
35
|
// βββ Output helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
36
36
|
|
|
@@ -366,15 +366,15 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
366
366
|
if (override) {
|
|
367
367
|
// Override can be a string (thinking level) or { m, t } object
|
|
368
368
|
if (typeof override === 'string') {
|
|
369
|
-
return { model: 'inherit', thinking: override === 'high' || override === 'medium' || override === 'low' ? override : '
|
|
369
|
+
return { model: 'inherit', thinking: override === 'xhigh' || override === 'high' || override === 'medium' || override === 'low' ? override : 'high' };
|
|
370
370
|
}
|
|
371
|
-
return { model: 'inherit', thinking: override.t || '
|
|
371
|
+
return { model: 'inherit', thinking: override.t || 'high' };
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
// Fall back to profile lookup
|
|
375
375
|
const profile = config.model_profile || 'balanced';
|
|
376
376
|
const agentModels = MODEL_PROFILES[agentType];
|
|
377
|
-
if (!agentModels) return { model: 'inherit', thinking: '
|
|
377
|
+
if (!agentModels) return { model: 'inherit', thinking: 'high' };
|
|
378
378
|
const entry = agentModels[profile] || agentModels['balanced'] || DEFAULT_ENTRY;
|
|
379
379
|
return { model: 'inherit', thinking: entry.t };
|
|
380
380
|
}
|
|
@@ -17,7 +17,7 @@ Default: `balanced` if not set or config missing.
|
|
|
17
17
|
Look up the agent in the table for the resolved profile. Each entry returns:
|
|
18
18
|
|
|
19
19
|
```json
|
|
20
|
-
{ "model": "inherit", "thinking": "
|
|
20
|
+
{ "model": "inherit", "thinking": "xhigh" }
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
All agents use `gpt-5.3-codex` (via `"inherit"`). The `thinking` field controls reasoning effort.
|
|
@@ -29,7 +29,7 @@ Task(
|
|
|
29
29
|
prompt="...",
|
|
30
30
|
subagent_type="gsd-planner",
|
|
31
31
|
model="inherit",
|
|
32
|
-
thinking="{resolved_thinking}" # "high", "medium", or "low"
|
|
32
|
+
thinking="{resolved_thinking}" # "xhigh", "high", "medium", or "low"
|
|
33
33
|
)
|
|
34
34
|
```
|
|
35
35
|
|
|
@@ -6,17 +6,17 @@ Model profiles control the reasoning effort level for each GSD agent. All agents
|
|
|
6
6
|
|
|
7
7
|
| Agent | `quality` | `balanced` | `budget` |
|
|
8
8
|
| ------------------------ | --------- | ---------- | --------- |
|
|
9
|
-
| gsd-planner |
|
|
10
|
-
| gsd-roadmapper | π’ high
|
|
11
|
-
| gsd-executor | π’ high
|
|
12
|
-
| gsd-phase-researcher | π‘ medium
|
|
13
|
-
| gsd-project-researcher | π‘ medium
|
|
14
|
-
| gsd-research-synthesizer | π‘ medium
|
|
15
|
-
| gsd-debugger |
|
|
16
|
-
| gsd-codebase-mapper |
|
|
17
|
-
| gsd-verifier |
|
|
18
|
-
| gsd-plan-checker | π‘ medium
|
|
19
|
-
| gsd-integration-checker | π‘ medium
|
|
9
|
+
| gsd-planner | π΄ xhigh | π΄ xhigh | π’ high |
|
|
10
|
+
| gsd-roadmapper | π΄ xhigh | π’ high | π‘ medium |
|
|
11
|
+
| gsd-executor | π΄ xhigh | π’ high | π‘ medium |
|
|
12
|
+
| gsd-phase-researcher | π’ high | π‘ medium | π‘ medium |
|
|
13
|
+
| gsd-project-researcher | π’ high | π‘ medium | π‘ medium |
|
|
14
|
+
| gsd-research-synthesizer | π’ high | π‘ medium | π‘ medium |
|
|
15
|
+
| gsd-debugger | π΄ xhigh | π΄ xhigh | π’ high |
|
|
16
|
+
| gsd-codebase-mapper | π‘ medium | π‘ medium | π‘ medium |
|
|
17
|
+
| gsd-verifier | π’ high | π’ high | π‘ medium |
|
|
18
|
+
| gsd-plan-checker | π’ high | π‘ medium | π‘ medium |
|
|
19
|
+
| gsd-integration-checker | π’ high | π‘ medium | π‘ medium |
|
|
20
20
|
|
|
21
21
|
All entries resolve to `model: "inherit"` (uses the session's gpt-5.3-codex). The `thinking` field controls reasoning effort.
|
|
22
22
|
|
|
@@ -24,39 +24,39 @@ All entries resolve to `model: "inherit"` (uses the session's gpt-5.3-codex). Th
|
|
|
24
24
|
|
|
25
25
|
**quality** - Maximum reasoning for every role
|
|
26
26
|
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
27
|
+
- π΄ **xhigh** for decision-makers: planner, roadmapper, executor, debugger
|
|
28
|
+
- π’ **high** for analysis: researchers, verifiers, checkers
|
|
29
|
+
- π‘ **medium** for read-only mapping
|
|
30
30
|
- Use when: critical architecture work, complex debugging
|
|
31
31
|
|
|
32
32
|
**balanced** (default) - Smart thinking allocation
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
34
|
+
- π΄ **xhigh** only for planner and debugger (highest-impact decisions)
|
|
35
|
+
- π’ **high** for executor and verifier (needs reasoning but follows plans)
|
|
36
|
+
- π‘ **medium** for everything else (structured output, scanning)
|
|
37
37
|
- Use when: normal development
|
|
38
38
|
|
|
39
39
|
**budget** - Minimal reasoning budget
|
|
40
40
|
|
|
41
|
-
-
|
|
42
|
-
-
|
|
41
|
+
- π’ **high** for planner and debugger (always need some reasoning)
|
|
42
|
+
- π‘ **medium** for everything else
|
|
43
43
|
- Use when: high-volume work, less critical phases
|
|
44
44
|
|
|
45
45
|
## Role-Based Thinking Rationale
|
|
46
46
|
|
|
47
|
-
**Why
|
|
47
|
+
**Why xhigh thinking for gsd-planner?**
|
|
48
48
|
Planning involves architecture decisions, goal decomposition, and task design. These decisions cascade through the entire phase β worth the extra reasoning budget.
|
|
49
49
|
|
|
50
|
-
**Why
|
|
50
|
+
**Why xhigh thinking for gsd-debugger even in balanced?**
|
|
51
51
|
Root cause analysis requires deep reasoning. A debugger that misdiagnoses wastes more tokens in re-runs than the reasoning cost.
|
|
52
52
|
|
|
53
|
-
**Why
|
|
53
|
+
**Why medium thinking for gsd-codebase-mapper?**
|
|
54
54
|
Read-only file scanning and pattern extraction. No decisions to make β just structured output from file contents.
|
|
55
55
|
|
|
56
|
-
**Why
|
|
57
|
-
Verification requires goal-backward reasoning β checking if code _delivers_ what the phase promised.
|
|
56
|
+
**Why high thinking for gsd-verifier in balanced?**
|
|
57
|
+
Verification requires goal-backward reasoning β checking if code _delivers_ what the phase promised. Medium thinking may miss subtle gaps.
|
|
58
58
|
|
|
59
|
-
**Why
|
|
59
|
+
**Why medium thinking for researchers in balanced?**
|
|
60
60
|
Research agents scan and collect information. The synthesis happens elsewhere. They don't need deep reasoning for reading files.
|
|
61
61
|
|
|
62
62
|
## Resolution Logic
|
|
@@ -70,7 +70,7 @@ Orchestrators resolve model and thinking before spawning:
|
|
|
70
70
|
4. Pass model + thinking to Task call
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Returns: `{ model: "inherit", thinking: "high"|"medium"|"low" }`
|
|
73
|
+
Returns: `{ model: "inherit", thinking: "xhigh"|"high"|"medium"|"low" }`
|
|
74
74
|
|
|
75
75
|
## Per-Agent Overrides
|
|
76
76
|
|
|
@@ -80,13 +80,13 @@ Override thinking level for specific agents:
|
|
|
80
80
|
{
|
|
81
81
|
"model_profile": "balanced",
|
|
82
82
|
"model_overrides": {
|
|
83
|
-
"gsd-executor": "
|
|
84
|
-
"gsd-codebase-mapper": "
|
|
83
|
+
"gsd-executor": "xhigh",
|
|
84
|
+
"gsd-codebase-mapper": "high"
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
Valid override values: `"high"`, `"medium"`, `"low"`.
|
|
89
|
+
Valid override values: `"xhigh"`, `"high"`, `"medium"`, `"low"`.
|
|
90
90
|
|
|
91
91
|
## Switching Profiles
|
|
92
92
|
|
|
@@ -309,9 +309,9 @@ Usage: `$gsd-settings`
|
|
|
309
309
|
**`$gsd-set-profile <profile>`**
|
|
310
310
|
Quick switch model profile for GSD agents.
|
|
311
311
|
|
|
312
|
-
- `quality` β
|
|
313
|
-
- `balanced` β
|
|
314
|
-
- `budget` β minimal thinking β
|
|
312
|
+
- `quality` β xhigh thinking for decision-makers, high for analysis agents
|
|
313
|
+
- `balanced` β xhigh thinking for planner/debugger, high/medium for others (default)
|
|
314
|
+
- `budget` β minimal thinking β high for planner/debugger, medium everywhere else
|
|
315
315
|
|
|
316
316
|
Usage: `$gsd-set-profile budget`
|
|
317
317
|
|
|
@@ -164,9 +164,9 @@ AskUserQuestion([
|
|
|
164
164
|
question: "Which AI models for planning agents?",
|
|
165
165
|
multiSelect: false,
|
|
166
166
|
options: [
|
|
167
|
-
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex β
|
|
168
|
-
{ label: "Quality", description: "gpt-5.3-codex β
|
|
169
|
-
{ label: "Budget", description: "gpt-5.3-codex β
|
|
167
|
+
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex β xhigh/high/medium thinking allocation per role" },
|
|
168
|
+
{ label: "Quality", description: "gpt-5.3-codex β xhigh thinking for all decision-makers" },
|
|
169
|
+
{ label: "Budget", description: "gpt-5.3-codex β high/medium thinking, fastest/cheapest" }
|
|
170
170
|
]
|
|
171
171
|
}
|
|
172
172
|
])
|
|
@@ -459,9 +459,9 @@ questions: [
|
|
|
459
459
|
question: "Which AI models for planning agents?",
|
|
460
460
|
multiSelect: false,
|
|
461
461
|
options: [
|
|
462
|
-
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex β
|
|
463
|
-
{ label: "Quality", description: "gpt-5.3-codex β
|
|
464
|
-
{ label: "Budget", description: "gpt-5.3-codex β
|
|
462
|
+
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex β xhigh/high/medium thinking allocation per role" },
|
|
463
|
+
{ label: "Quality", description: "gpt-5.3-codex β xhigh thinking for all decision-makers" },
|
|
464
|
+
{ label: "Budget", description: "gpt-5.3-codex β high/medium thinking, fastest/cheapest" }
|
|
465
465
|
]
|
|
466
466
|
}
|
|
467
467
|
]
|
|
@@ -58,9 +58,9 @@ Agents will now use:
|
|
|
58
58
|
Example:
|
|
59
59
|
| Agent | Model | Thinking |
|
|
60
60
|
|-------|-------|----------|
|
|
61
|
-
| gsd-planner | gpt-5.3-codex |
|
|
62
|
-
| gsd-executor | gpt-5.3-codex |
|
|
63
|
-
| gsd-verifier | gpt-5.3-codex |
|
|
61
|
+
| gsd-planner | gpt-5.3-codex | xhigh |
|
|
62
|
+
| gsd-executor | gpt-5.3-codex | high |
|
|
63
|
+
| gsd-verifier | gpt-5.3-codex | high |
|
|
64
64
|
| ... | ... | ... |
|
|
65
65
|
|
|
66
66
|
Next spawned agents will use the new profile.
|
|
@@ -43,9 +43,9 @@ AskUserQuestion([
|
|
|
43
43
|
header: "Model",
|
|
44
44
|
multiSelect: false,
|
|
45
45
|
options: [
|
|
46
|
-
{ label: "Quality", description: "gpt-5.3-codex with
|
|
47
|
-
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex with
|
|
48
|
-
{ label: "Budget", description: "gpt-5.3-codex with
|
|
46
|
+
{ label: "Quality", description: "gpt-5.3-codex with xhigh thinking for decision-makers, high for analysis" },
|
|
47
|
+
{ label: "Balanced (Recommended)", description: "gpt-5.3-codex with xhigh thinking for planner/debugger, high/medium for others" },
|
|
48
|
+
{ label: "Budget", description: "gpt-5.3-codex with high thinking for planner/debugger, medium everywhere else" }
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
51
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@undeemed/get-shit-done-codex",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.2",
|
|
4
4
|
"description": "A meta-prompting, context engineering and spec-driven development system for OpenAI Codex (CLI and Desktop). Fork of get-shit-done by TΓCHES, adapted for Codex.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"get-shit-done-codex": "bin/install.js"
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build:hooks": "node scripts/build-hooks.js",
|
|
69
69
|
"prepublishOnly": "npm run build:hooks",
|
|
70
|
-
"test": "node
|
|
70
|
+
"test": "node scripts/run-tests.cjs",
|
|
71
|
+
"test:coverage": "node scripts/run-tests.cjs --coverage"
|
|
71
72
|
}
|
|
72
73
|
}
|
package/scripts/run-tests.cjs
CHANGED
|
@@ -1,29 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { spawnSync } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
function collectTests(dir) {
|
|
8
|
+
if (!fs.existsSync(dir)) return [];
|
|
9
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
10
|
+
const files = [];
|
|
11
|
+
|
|
12
|
+
for (const entry of entries) {
|
|
13
|
+
const fullPath = path.join(dir, entry.name);
|
|
14
|
+
if (entry.isDirectory()) {
|
|
15
|
+
files.push(...collectTests(fullPath));
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (entry.isFile() && entry.name.endsWith(".test.cjs")) {
|
|
19
|
+
files.push(fullPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return files;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const withCoverage = process.argv.includes("--coverage");
|
|
27
|
+
const testFiles = collectTests(path.resolve(__dirname, "..", "tests")).sort();
|
|
28
|
+
|
|
29
|
+
if (testFiles.length === 0) {
|
|
30
|
+
console.error("No test files found in ./tests");
|
|
19
31
|
process.exit(1);
|
|
20
32
|
}
|
|
21
33
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
const args = [];
|
|
35
|
+
if (withCoverage) args.push("--experimental-test-coverage");
|
|
36
|
+
args.push("--test", ...testFiles);
|
|
37
|
+
|
|
38
|
+
const result = spawnSync(process.execPath, args, { stdio: "inherit" });
|
|
39
|
+
if (result.error) {
|
|
40
|
+
console.error(result.error.message);
|
|
41
|
+
process.exit(1);
|
|
29
42
|
}
|
|
43
|
+
process.exit(result.status ?? 1);
|