@opengsd/gsd-core 1.16.0 → 1.18.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -2
- package/.opencode/plugins/gsd-core.js +251 -1
- package/.opencode/plugins/gsd-statusline/tui.tsx +55 -0
- package/GEMINI.md +1 -1
- package/agents/gsd-advisor-researcher.compact.md +1 -1
- package/agents/gsd-advisor-researcher.md +1 -1
- package/agents/gsd-assumptions-analyzer.compact.md +1 -1
- package/agents/gsd-assumptions-analyzer.md +1 -1
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +1 -1
- package/agents/gsd-code-reviewer.md +1 -1
- package/agents/gsd-codebase-mapper.compact.md +1 -1
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debug-session-manager.compact.md +6 -0
- package/agents/gsd-debug-session-manager.md +6 -0
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-verifier.compact.md +4 -4
- package/agents/gsd-doc-verifier.md +4 -3
- package/agents/gsd-doc-writer.compact.md +23 -5
- package/agents/gsd-doc-writer.md +19 -6
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +7 -3
- package/agents/gsd-integration-checker.compact.md +1 -1
- package/agents/gsd-integration-checker.md +1 -1
- package/agents/gsd-nyquist-auditor.compact.md +1 -1
- package/agents/gsd-nyquist-auditor.md +1 -1
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +2 -1
- package/agents/gsd-planner.md +5 -4
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +5 -5
- package/agents/gsd-research-synthesizer.md +5 -5
- package/agents/gsd-roadmapper.compact.md +1 -1
- package/agents/gsd-roadmapper.md +1 -1
- package/agents/gsd-security-auditor.compact.md +1 -1
- package/agents/gsd-security-auditor.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +1 -1
- package/agents/gsd-ui-auditor.md +1 -1
- package/agents/gsd-ui-checker.compact.md +1 -1
- package/agents/gsd-ui-checker.md +1 -1
- package/agents/gsd-ui-researcher.compact.md +13 -1
- package/agents/gsd-ui-researcher.md +28 -1
- package/agents/gsd-verifier.md +1 -1
- package/bin/gsd-mcp-server.js +3 -1
- package/bin/install.js +398 -95
- package/commands/gsd/code-review.md +8 -0
- package/commands/gsd/pause-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +34 -12
- package/gsd-core/bin/lib/adr-parser.cjs +37 -5
- package/gsd-core/bin/lib/capability-ledger.cjs +25 -0
- package/gsd-core/bin/lib/capability-lock.cjs +29 -7
- package/gsd-core/bin/lib/capability-registry.cjs +138 -80
- package/gsd-core/bin/lib/capability-source.cjs +3 -1
- package/gsd-core/bin/lib/capability-state.cjs +6 -3
- package/gsd-core/bin/lib/capability-validator.cjs +8 -5
- package/gsd-core/bin/lib/capability-writer.cjs +2 -1
- package/gsd-core/bin/lib/commands.cjs +33 -9
- package/gsd-core/bin/lib/config-loader.cjs +3 -3
- package/gsd-core/bin/lib/decision-coverage-support.cjs +19 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +5 -4
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +15 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +13 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +23 -3
- package/gsd-core/bin/lib/gate-predicate.cjs +8 -12
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +60 -5
- package/gsd-core/bin/lib/gate-ui-safety.cjs +2 -1
- package/gsd-core/bin/lib/graphify.cjs +3 -2
- package/gsd-core/bin/lib/init.cjs +43 -16
- package/gsd-core/bin/lib/install-effort-resolver.cjs +2 -2
- package/gsd-core/bin/lib/install-engine.cjs +11 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +4 -3
- package/gsd-core/bin/lib/install-profiles.cjs +5 -3
- package/gsd-core/bin/lib/install-shadow-report.cjs +12 -0
- package/gsd-core/bin/lib/installer-migrations/011-opencode-mcp-no-prompts.cjs +99 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +54 -1
- package/gsd-core/bin/lib/jsonc-edit.cjs +418 -0
- package/gsd-core/bin/lib/loop-host-contract.cjs +2 -1
- package/gsd-core/bin/lib/mcp-server.cjs +5 -1
- package/gsd-core/bin/lib/opencode-mcp-entry.cjs +39 -0
- package/gsd-core/bin/lib/opencode-version.cjs +486 -0
- package/gsd-core/bin/lib/phase.cjs +141 -11
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +2 -1
- package/gsd-core/bin/lib/report-parser.cjs +57 -1
- package/gsd-core/bin/lib/review-lane-invocation.cjs +40 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +20 -1
- package/gsd-core/bin/lib/roadmap.cjs +56 -5
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +142 -6
- package/gsd-core/bin/lib/runtime-homes.cjs +18 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +58 -3
- package/gsd-core/bin/lib/runtime-slash.cjs +13 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +2 -0
- package/gsd-core/bin/lib/smart-entry.cjs +100 -53
- package/gsd-core/bin/lib/state-document.cjs +37 -3
- package/gsd-core/bin/lib/state-transition.cjs +98 -19
- package/gsd-core/bin/lib/state.cjs +544 -126
- package/gsd-core/bin/lib/task-command-router.cjs +2 -3
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +5 -0
- package/gsd-core/bin/lib/tdd-test-files.cjs +42 -0
- package/gsd-core/bin/lib/update-context.cjs +18 -1
- package/gsd-core/bin/lib/verification.cjs +107 -17
- package/gsd-core/bin/lib/verify.cjs +36 -1
- package/gsd-core/references/agent-contracts.md +1 -1
- package/gsd-core/references/agent-skills-bootstrap.md +26 -7
- package/gsd-core/references/git-integration.md +3 -3
- package/gsd-core/references/planner-reversibility.md +18 -4
- package/gsd-core/references/planner-verify-command-grounding.md +18 -0
- package/gsd-core/references/tdd.md +4 -3
- package/gsd-core/references/verifier-phase-gates.md +8 -1
- package/gsd-core/workflows/add-backlog.md +10 -2
- package/gsd-core/workflows/add-phase.md +5 -1
- package/gsd-core/workflows/add-tests.md +5 -1
- package/gsd-core/workflows/add-todo.md +5 -1
- package/gsd-core/workflows/ai-integration-phase.md +5 -1
- package/gsd-core/workflows/audit-milestone.md +21 -9
- package/gsd-core/workflows/autonomous/templates/minimal-context.md +41 -0
- package/gsd-core/workflows/autonomous.md +52 -64
- package/gsd-core/workflows/check-todos.md +5 -1
- package/gsd-core/workflows/code-review-fix.md +5 -1
- package/gsd-core/workflows/code-review.md +21 -2
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +5 -1
- package/gsd-core/workflows/complete-milestone.md +25 -5
- package/gsd-core/workflows/debug.md +5 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +11 -3
- package/gsd-core/workflows/discuss-phase.md +5 -1
- package/gsd-core/workflows/docs-update/detail/elaboration.md +7 -6
- package/gsd-core/workflows/docs-update.md +27 -5
- package/gsd-core/workflows/edit-phase.md +5 -1
- package/gsd-core/workflows/eval-review.md +11 -3
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +5 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +12 -6
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +19 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +18 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +5 -1
- package/gsd-core/workflows/execute-phase.md +40 -7
- package/gsd-core/workflows/execute-plan.md +8 -4
- package/gsd-core/workflows/extract-learnings.md +6 -2
- package/gsd-core/workflows/forensics.md +5 -1
- package/gsd-core/workflows/import.md +5 -1
- package/gsd-core/workflows/insert-phase.md +5 -1
- package/gsd-core/workflows/manager.md +10 -2
- package/gsd-core/workflows/map-codebase.md +5 -1
- package/gsd-core/workflows/milestone-summary.md +10 -2
- package/gsd-core/workflows/new-milestone.md +13 -5
- package/gsd-core/workflows/new-project.md +9 -5
- package/gsd-core/workflows/next.md +8 -4
- package/gsd-core/workflows/pause-work.md +3 -3
- package/gsd-core/workflows/plan-phase/steps/auto-advance-check.md +70 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +5 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +6 -2
- package/gsd-core/workflows/plan-phase.md +41 -73
- package/gsd-core/workflows/plan-review-convergence.md +17 -5
- package/gsd-core/workflows/plant-seed.md +8 -4
- package/gsd-core/workflows/progress.md +6 -2
- package/gsd-core/workflows/quick-batch.md +5 -1
- package/gsd-core/workflows/quick.md +22 -7
- package/gsd-core/workflows/remove-phase.md +5 -1
- package/gsd-core/workflows/resume-project.md +19 -11
- package/gsd-core/workflows/review.md +6 -2
- package/gsd-core/workflows/scan.md +5 -1
- package/gsd-core/workflows/secure-phase.md +6 -2
- package/gsd-core/workflows/settings.md +3 -3
- package/gsd-core/workflows/ship.md +13 -10
- package/gsd-core/workflows/thread.md +10 -2
- package/gsd-core/workflows/transition.md +5 -1
- package/gsd-core/workflows/ui-phase.md +5 -1
- package/gsd-core/workflows/ui-review.md +6 -2
- package/gsd-core/workflows/ultraplan-phase.md +5 -1
- package/gsd-core/workflows/update.md +5 -1
- package/gsd-core/workflows/validate-phase.md +6 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -1
- package/gsd-core/workflows/verify-work.md +11 -3
- package/hooks/dist/gsd-agent-isolation-guard.js +3 -1
- package/hooks/dist/gsd-check-update.js +26 -20
- package/hooks/dist/gsd-context-monitor.js +14 -5
- package/hooks/dist/gsd-cursor-subagent-start.js +2 -1
- package/hooks/dist/gsd-secret-read-guard.js +189 -15
- package/hooks/dist/gsd-statusline.js +321 -22
- package/hooks/dist/gsd-validate-commit.sh +27 -5
- package/hooks/gsd-agent-isolation-guard.js +3 -1
- package/hooks/gsd-check-update.js +26 -20
- package/hooks/gsd-context-monitor.js +14 -5
- package/hooks/gsd-cursor-subagent-start.js +2 -1
- package/hooks/gsd-secret-read-guard.js +189 -15
- package/hooks/gsd-statusline.js +321 -22
- package/hooks/gsd-validate-commit.sh +27 -5
- package/package.json +1 -1
- package/scripts/audit-workflow-script-paths.cjs +1 -1
- package/scripts/diagnose-validate-commit-in-tier.cjs +270 -0
- package/scripts/diagnose-validate-commit-phases.cjs +348 -0
- package/scripts/diagnose-windows-spawn-watcher.cjs +317 -0
- package/scripts/docs-guard-registry.cjs +2 -0
- package/scripts/gen-capability-registry.cjs +7 -1
- package/scripts/gen-loop-host-contract.cjs +4 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +13 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +26 -0
- package/scripts/lint-phase-arg-assignment.cjs +2 -2
- package/scripts/lint-workflow-shellcheck-baseline.json +16 -16
- package/scripts/mutation-matrix.cjs +3 -1
- package/scripts/release-tarball-smoke.cjs +15 -7
- package/scripts/xtrace-phase-timing.cjs +205 -0
- package/skills/gsd-code-review/SKILL.md +8 -0
- package/skills/gsd-pause-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
|
@@ -325,22 +325,29 @@ const RUNTIME_CONFIG_FILES = Object.freeze(['settings.json', 'hooks.json', 'conf
|
|
|
325
325
|
* embeds a launch path without registering it, which a structured
|
|
326
326
|
* JSON.parse of the expected schema would miss entirely.
|
|
327
327
|
*
|
|
328
|
-
* Windows configs store paths with backslashes, which JSON/TOML doubles on
|
|
329
|
-
* write; collapsing `\\` to `\` first makes the raw text scan work on both
|
|
330
|
-
* platforms without parsing each config format separately (POSIX text has no
|
|
331
|
-
* backslashes, so the collapse is a no-op there).
|
|
332
|
-
*
|
|
333
328
|
* Every writer bakes `configDir` through the same posixNormalize seam
|
|
334
329
|
* (src/runtime-hooks-surface.cts) before writing it into config text, on
|
|
335
330
|
* every platform — so the anchor must match that projection, not the
|
|
336
331
|
* OS-native `configDir` string this function receives.
|
|
332
|
+
*
|
|
333
|
+
* The scanned text goes through that same projection (#5084): a registration
|
|
334
|
+
* the installer did not write — a hand-edited settings.json, another tool's
|
|
335
|
+
* writer — may spell its path with Windows-native backslashes, and an anchor
|
|
336
|
+
* and haystack in different separator forms never match, so the dangling-hook
|
|
337
|
+
* check would skip it silently. Scan both the backslash-unescaped projection
|
|
338
|
+
* (JSON and TOML basic strings) and the unchanged projection (TOML literal
|
|
339
|
+
* strings). Unescaping a literal UNC prefix drops a leading separator, so
|
|
340
|
+
* neither projection alone is sufficient. A Set combines identical paths.
|
|
337
341
|
*/
|
|
338
342
|
function configuredEntrypointsIn(text, configDir) {
|
|
339
343
|
const normalizedPrefix = shellCmdProjection.posixNormalize(configDir).replace(/\/+$/, '') + '/';
|
|
340
344
|
const scriptPathRe = new RegExp(`${escapeRegex(normalizedPrefix)}[^"']{0,400}?\\.(?:js|cjs|mjs|sh|cmd|ps1)`, 'g');
|
|
341
345
|
const found = new Set();
|
|
342
|
-
for (const
|
|
343
|
-
|
|
346
|
+
for (const candidateText of [text.replace(/\\\\/g, '\\'), text]) {
|
|
347
|
+
const scannedText = shellCmdProjection.posixNormalize(candidateText);
|
|
348
|
+
for (const match of scannedText.matchAll(scriptPathRe)) {
|
|
349
|
+
found.add(path.resolve(match[0]));
|
|
350
|
+
}
|
|
344
351
|
}
|
|
345
352
|
return [...found];
|
|
346
353
|
}
|
|
@@ -696,6 +703,7 @@ function runSmoke({
|
|
|
696
703
|
...effectiveNpmEnv,
|
|
697
704
|
HOME: runtimeHome,
|
|
698
705
|
USERPROFILE: runtimeHome,
|
|
706
|
+
GSD_HOME: runtimeHome, // #5017: the defaults store root follows HOME
|
|
699
707
|
// Same reason as the init check above: install.js skips its main()
|
|
700
708
|
// block when GSD_TEST_MODE is set and would exit 0 writing nothing.
|
|
701
709
|
GSD_TEST_MODE: '',
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Per-line cost attribution for a `bash -x` trace whose PS4 stamps every
|
|
5
|
+
* traced command with a millisecond timestamp, its line number and enclosing
|
|
6
|
+
* function (#5473).
|
|
7
|
+
*
|
|
8
|
+
* The stamp is `<depth marks>@@<nonce>@@<epoch-ms>@@<lineno>@@<function>@@ `, so
|
|
9
|
+
* one trace line looks like `++@@k3f9@@1760615775123@@271@@@@ MSG_SUFFIX=...`.
|
|
10
|
+
* The nonce is a per-run random token: a traced value that merely LOOKS like a
|
|
11
|
+
* stamp (hostile or accidental) cannot forge one without knowing it.
|
|
12
|
+
*
|
|
13
|
+
* WHAT A GAP MEANS. bash prints a trace line (and so evaluates PS4) AFTER it
|
|
14
|
+
* has expanded the command's words and BEFORE it runs the command. The gap
|
|
15
|
+
* between stamp i and stamp i+1 is therefore
|
|
16
|
+
*
|
|
17
|
+
* execution of command i + expansion of command i+1
|
|
18
|
+
*
|
|
19
|
+
* which cannot be split from the trace alone. Both attributions are reported:
|
|
20
|
+
* `afterMs` (the gap that FOLLOWS the line) is large for a line that EXECUTES
|
|
21
|
+
* slowly (an external command, a `$(...)` already expanded); `beforeMs` (the
|
|
22
|
+
* gap that PRECEDES it) is large for a line whose EXPANSION is slow (a
|
|
23
|
+
* `${var//pat/x}` or `${var:off}` over a 112KB value, whose result is only
|
|
24
|
+
* printed once it is computed). Neither alone is "the cost of the line".
|
|
25
|
+
*
|
|
26
|
+
* Every traced command also pays one stamp (a subshell and a perl); measure it
|
|
27
|
+
* with a run of no-ops (see the CLI) and read gaps below it as zero.
|
|
28
|
+
*
|
|
29
|
+
* No I/O and no clock: every function returns a value computed from its
|
|
30
|
+
* arguments. The CLI that runs bash is scripts/diagnose-validate-commit-phases.cjs.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** PS4 to hand to `bash -x`; `timestampCommand` prints the epoch milliseconds. */
|
|
34
|
+
function stampPs4(timestampCommand, nonce) {
|
|
35
|
+
return `+@@${nonce}@@$(${timestampCommand})@@\${LINENO}@@\${FUNCNAME:-}@@ `;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* How the stamp reaches bash. Every other route failed somewhere:
|
|
40
|
+
* - an exported PS4: bash 5.x does not run the command substitution in a PS4
|
|
41
|
+
* it imported from the environment, so it silently degrades to `+ `;
|
|
42
|
+
* - BASH_ENV: bash reads the system bashrc INSTEAD of it in some
|
|
43
|
+
* environments (it did in the gsd-test tester container);
|
|
44
|
+
* - `bash -c '... . "$0"'`: puts an uncontrolled path inside a shell command.
|
|
45
|
+
* So the script under test is run as an ordinary script that has ONE line
|
|
46
|
+
* inserted after its shebang, which assigns PS4 (read from a sibling file, so
|
|
47
|
+
* the stamp text is never quoted into shell code) and turns on xtrace. `$0`,
|
|
48
|
+
* `exit` and sibling files then behave exactly as in a direct run (the CLI's
|
|
49
|
+
* tests pin this against the real hook).
|
|
50
|
+
*/
|
|
51
|
+
const TRACE_PS4_FILE = 'xtrace-ps4.txt';
|
|
52
|
+
const INJECTED_LINES = 1;
|
|
53
|
+
const INJECTED_LINE = `PS4="$(cat "\${0%/*}/${TRACE_PS4_FILE}")"; set -x`;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `scriptText` with the tracing line inserted after its shebang (or at the top
|
|
57
|
+
* when it has none). The script must be run by a path containing a `/`, with
|
|
58
|
+
* the PS4 text in TRACE_PS4_FILE beside it. Adds exactly INJECTED_LINES lines.
|
|
59
|
+
*/
|
|
60
|
+
function injectTracing(scriptText) {
|
|
61
|
+
const text = String(scriptText);
|
|
62
|
+
if (!text.startsWith('#!')) return `${INJECTED_LINE}\n${text}`;
|
|
63
|
+
const eol = text.indexOf('\n');
|
|
64
|
+
if (eol === -1) return `${text}\n${INJECTED_LINE}\n`;
|
|
65
|
+
return `${text.slice(0, eol + 1)}${INJECTED_LINE}\n${text.slice(eol + 1)}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// What follows the depth marks and the nonce: `<epoch-ms>@@<lineno>@@<function>@@ `.
|
|
69
|
+
const STAMP_TAIL = /^(\d+)@@(\d+)@@([^@]*)@@ ?/;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parse a stamped trace. Lines with no stamp are continuations of the
|
|
73
|
+
* previous command (a traced value that itself contains newlines) and are
|
|
74
|
+
* folded into it; text before the first stamp is ignored.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} text
|
|
77
|
+
* @param {string} nonce the nonce given to stampPs4
|
|
78
|
+
* @returns {{ t: number, line: number, depth: number, fn: string, cmd: string }[]}
|
|
79
|
+
*/
|
|
80
|
+
function parseTimedXtrace(text, nonce) {
|
|
81
|
+
// The nonce is matched as a literal prefix, never compiled into a pattern.
|
|
82
|
+
const head = `@@${nonce}@@`;
|
|
83
|
+
const entries = [];
|
|
84
|
+
const lines = String(text).split('\n');
|
|
85
|
+
// A stream ends with the newline of its last line; that is a terminator, not
|
|
86
|
+
// an empty continuation of the last command.
|
|
87
|
+
if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();
|
|
88
|
+
for (const raw of lines) {
|
|
89
|
+
let depth = 0;
|
|
90
|
+
while (raw[depth] === '+') depth++;
|
|
91
|
+
const tail = depth > 0 && raw.startsWith(head, depth)
|
|
92
|
+
? STAMP_TAIL.exec(raw.slice(depth + head.length))
|
|
93
|
+
: null;
|
|
94
|
+
if (tail) {
|
|
95
|
+
entries.push({
|
|
96
|
+
t: Number(tail[1]),
|
|
97
|
+
line: Number(tail[2]),
|
|
98
|
+
depth,
|
|
99
|
+
fn: tail[3],
|
|
100
|
+
cmd: raw.slice(depth + head.length + tail[0].length),
|
|
101
|
+
});
|
|
102
|
+
} else if (entries.length > 0) {
|
|
103
|
+
entries[entries.length - 1].cmd += `\n${raw}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return entries;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Entries with their line numbers moved back by `injected` lines, so a stamp
|
|
111
|
+
* reports the line of the ORIGINAL script, not of the instrumented copy.
|
|
112
|
+
*/
|
|
113
|
+
function shiftLines(entries, injected) {
|
|
114
|
+
return entries.map((e) => ({ ...e, line: e.line - injected }));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Attribute the gaps around each entry to its (function, line): `afterMs` is
|
|
119
|
+
* the gap to the NEXT stamp, `beforeMs` the gap from the PREVIOUS one (see the
|
|
120
|
+
* header for what each means). A clock that steps backwards counts as zero.
|
|
121
|
+
*
|
|
122
|
+
* @param {{ t: number, line: number, fn?: string, cmd: string }[]} entries
|
|
123
|
+
* @returns {{ costs: { fn: string, line: number, afterMs: number, beforeMs: number, maxMs: number, count: number, sample: string }[], totalMs: number }}
|
|
124
|
+
*/
|
|
125
|
+
function phaseCosts(entries) {
|
|
126
|
+
const byKey = new Map();
|
|
127
|
+
const last = entries.length - 1;
|
|
128
|
+
for (let i = 0; i <= last; i++) {
|
|
129
|
+
const after = i < last ? Math.max(0, entries[i + 1].t - entries[i].t) : 0;
|
|
130
|
+
const before = i > 0 ? Math.max(0, entries[i].t - entries[i - 1].t) : 0;
|
|
131
|
+
const e = entries[i];
|
|
132
|
+
const fn = e.fn || '';
|
|
133
|
+
const key = `${fn}\u0000${e.line}`;
|
|
134
|
+
const acc = byKey.get(key) || { fn, line: e.line, afterMs: 0, beforeMs: 0, maxMs: 0, count: 0, sample: '' };
|
|
135
|
+
acc.afterMs += after;
|
|
136
|
+
acc.beforeMs += before;
|
|
137
|
+
acc.count += 1;
|
|
138
|
+
const peak = Math.max(after, before);
|
|
139
|
+
if (peak >= acc.maxMs) {
|
|
140
|
+
acc.maxMs = peak;
|
|
141
|
+
acc.sample = e.cmd;
|
|
142
|
+
}
|
|
143
|
+
byKey.set(key, acc);
|
|
144
|
+
}
|
|
145
|
+
const totalMs = entries.length > 1 ? Math.max(0, entries[last].t - entries[0].t) : 0;
|
|
146
|
+
return { costs: [...byKey.values()], totalMs };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** A line's weight when ranking: the larger of its two attributions. */
|
|
150
|
+
const peakMs = (c) => Math.max(c.afterMs, c.beforeMs);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The `n` most expensive lines, costliest first; ties broken by function then
|
|
154
|
+
* line number so the order is deterministic.
|
|
155
|
+
*/
|
|
156
|
+
function slowestLines(costs, n) {
|
|
157
|
+
return [...costs]
|
|
158
|
+
.sort((a, b) => peakMs(b) - peakMs(a) || (a.fn < b.fn ? -1 : a.fn > b.fn ? 1 : 0) || a.line - b.line)
|
|
159
|
+
.slice(0, n);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Elapsed time per run of `size` source lines of the script's top level, in
|
|
164
|
+
* line order, plus one entry per function. `afterMs` summed over a region is
|
|
165
|
+
* the time from its first stamp to the next region's, so regions roughly
|
|
166
|
+
* partition the run: a coarse "which phase" view that needs no knowledge of
|
|
167
|
+
* the script.
|
|
168
|
+
*
|
|
169
|
+
* @returns {{ label: string, afterMs: number }[]}
|
|
170
|
+
*/
|
|
171
|
+
function rollupByRegion(costs, size) {
|
|
172
|
+
if (!Number.isInteger(size) || size < 1) throw new RangeError('region size must be a positive integer');
|
|
173
|
+
const regions = new Map();
|
|
174
|
+
for (const c of costs) {
|
|
175
|
+
const start = Math.floor((c.line - 1) / size) * size + 1;
|
|
176
|
+
const label = c.fn ? `in ${c.fn}()` : `lines ${start}-${start + size - 1}`;
|
|
177
|
+
const from = c.fn ? Number.MAX_SAFE_INTEGER : start; // functions sort after the top level
|
|
178
|
+
const acc = regions.get(label) || { label, from, afterMs: 0 };
|
|
179
|
+
acc.afterMs += c.afterMs;
|
|
180
|
+
regions.set(label, acc);
|
|
181
|
+
}
|
|
182
|
+
return [...regions.values()]
|
|
183
|
+
.sort((a, b) => a.from - b.from || (a.label < b.label ? -1 : a.label > b.label ? 1 : 0))
|
|
184
|
+
.map(({ label, afterMs }) => ({ label, afterMs }));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** One-line, length-bounded rendering of a traced command for a report. */
|
|
188
|
+
function abbreviate(cmd, max = 100) {
|
|
189
|
+
const flat = String(cmd).replace(/\s+/g, ' ').trim();
|
|
190
|
+
return flat.length <= max ? flat : `${flat.slice(0, max)}… (${flat.length} chars)`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = {
|
|
194
|
+
stampPs4,
|
|
195
|
+
TRACE_PS4_FILE,
|
|
196
|
+
INJECTED_LINES,
|
|
197
|
+
injectTracing,
|
|
198
|
+
parseTimedXtrace,
|
|
199
|
+
shiftLines,
|
|
200
|
+
phaseCosts,
|
|
201
|
+
peakMs,
|
|
202
|
+
slowestLines,
|
|
203
|
+
rollupByRegion,
|
|
204
|
+
abbreviate,
|
|
205
|
+
};
|
|
@@ -48,6 +48,14 @@ Optional flags parsed from the `<arguments>` block:
|
|
|
48
48
|
- `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely.
|
|
49
49
|
|
|
50
50
|
Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `<required_reading>` blocks.
|
|
51
|
+
|
|
52
|
+
## Outside a phase
|
|
53
|
+
|
|
54
|
+
Reviewer lanes run without a phase (`gsd_run` is defined by the runtime-launcher preamble inside workflow fences; in a plain shell call `node <install>/gsd-core/bin/gsd-tools.cjs` instead): pipe canonical repo-relative file paths (one per line) to stdin of
|
|
55
|
+
`gsd_run review-lane dispatch-step --repo-root <root> --depth <quick|standard|deep> --base-sha <sha> --run-dir "$(mktemp -d)" --cap-id code-review --point execute:post --explicit <slugs> --raw`.
|
|
56
|
+
`review-lane` flags are space-separated (`--depth quick`), never `--flag=value`. `--explicit` (omitted, nothing dispatches yet the call exits ok), `--depth`, `--base-sha` (lane reviews changes relative to it; commit them first) and stdin paths are required; `--run-dir` should be a fresh temp dir (default `.` writes the prompt file into the current directory); read each lane's output path (`results[].reviewPath`) from the JSON before removing it. `--cap-id`/`--point` select the `code-review` capability, which must be enabled (`workflow.code_review`) and active at `--point` — `execute:post`, or `execute:wave:post` when `workflow.code_review_point` selects it; otherwise nothing dispatches.
|
|
57
|
+
`--explicit` takes comma-separated canonical slugs, no spaces (`codex,antigravity`), not flag aliases (`antigravity`, not `agy`); slugs: first column of `gsd_run review-lane sections` (`review-lane flags` lists flags/aliases).
|
|
58
|
+
Each lane declares its own model key, which is not always its slug (antigravity's is `review.models.agy`); see the `review.models.*` table in `docs/CONFIGURATION.md`. Unset = lane default model.
|
|
51
59
|
</context>
|
|
52
60
|
|
|
53
61
|
<process>
|
|
@@ -21,7 +21,7 @@ Routes to the pause-work workflow which handles:
|
|
|
21
21
|
- Current phase detection from recent files
|
|
22
22
|
- Complete state gathering (position, completed work, remaining work, decisions, blockers)
|
|
23
23
|
- Handoff file creation with all context sections
|
|
24
|
-
- Git commit
|
|
24
|
+
- Git commit handoff
|
|
25
25
|
- Resume instructions
|
|
26
26
|
</objective>
|
|
27
27
|
|
package/vscode/package.json
CHANGED