@opengsd/gsd-core 1.19.0 → 1.20.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 -1
- package/agents/gsd-code-fixer.compact.md +5 -5
- package/agents/gsd-code-fixer.md +9 -4
- package/agents/gsd-code-reviewer.compact.md +49 -8
- package/agents/gsd-code-reviewer.md +53 -14
- package/agents/gsd-executor.md +8 -4
- package/commands/gsd/update.md +5 -2
- package/gsd-core/bin/gsd-tools.cjs +73 -23
- package/gsd-core/bin/lib/capability-lifecycle.cjs +1 -12
- package/gsd-core/bin/lib/capability-registry.cjs +284 -93
- package/gsd-core/bin/lib/capability-validator.cjs +15 -0
- package/gsd-core/bin/lib/commands.cjs +27 -17
- package/gsd-core/bin/lib/config-loader.cjs +3 -3
- package/gsd-core/bin/lib/core-utils.cjs +11 -0
- package/gsd-core/bin/lib/frontmatter.cjs +21 -3
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +2 -2
- package/gsd-core/bin/lib/gate-context-drift.cjs +1 -1
- package/gsd-core/bin/lib/gate-phase-context.cjs +7 -8
- package/gsd-core/bin/lib/gate-schema-drift.cjs +1 -1
- package/gsd-core/bin/lib/git-info-exclude.cjs +1 -6
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +13 -9
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +9 -7
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +3 -3
- package/gsd-core/bin/lib/init.cjs +180 -67
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +34 -1
- package/gsd-core/bin/lib/markdown-table.cjs +23 -0
- package/gsd-core/bin/lib/mcp-server.cjs +8 -5
- package/gsd-core/bin/lib/milestone.cjs +18 -50
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +119 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +2 -0
- package/gsd-core/bin/lib/phase-id.cjs +609 -35
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -74
- package/gsd-core/bin/lib/phase-locator.cjs +328 -19
- package/gsd-core/bin/lib/phase.cjs +2990 -666
- package/gsd-core/bin/lib/planning-document.cjs +26 -5
- package/gsd-core/bin/lib/planning-inspect.cjs +27 -35
- package/gsd-core/bin/lib/planning-snapshot.cjs +12 -7
- package/gsd-core/bin/lib/planning-workspace.cjs +3 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +23 -2
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +2 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -0
- package/gsd-core/bin/lib/review-lane-invocation.cjs +125 -18
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +11 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +730 -144
- package/gsd-core/bin/lib/roadmap-progress.cjs +136 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +8 -5
- package/gsd-core/bin/lib/roadmap.cjs +358 -106
- package/gsd-core/bin/lib/shell-command-projection.cjs +36 -9
- package/gsd-core/bin/lib/smart-entry.cjs +22 -11
- package/gsd-core/bin/lib/state-contract.cjs +11 -7
- package/gsd-core/bin/lib/state-document.cjs +332 -23
- package/gsd-core/bin/lib/state-transition.cjs +39 -10
- package/gsd-core/bin/lib/state.cjs +498 -179
- package/gsd-core/bin/lib/template.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +3 -2
- package/gsd-core/bin/lib/vendor/re2js.cjs +863 -577
- package/gsd-core/bin/lib/vendor/re2js.d.cts +284 -219
- package/gsd-core/bin/lib/verify.cjs +2 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +26 -20
- package/gsd-core/bin/verify-reapply-patches.cjs +411 -10
- package/gsd-core/references/cicd-review-patterns.md +45 -0
- package/gsd-core/references/necessity-review.md +48 -0
- package/gsd-core/workflows/code-review-fix.md +46 -5
- package/gsd-core/workflows/code-review.md +3 -0
- package/gsd-core/workflows/execute-phase.md +1 -1
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +13 -9
- package/gsd-core/workflows/plan-phase.md +1 -1
- package/gsd-core/workflows/pr-branch.md +2 -0
- package/gsd-core/workflows/reapply-patches.md +104 -0
- package/gsd-core/workflows/review.md +54 -141
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +57 -9
- package/gsd-core/workflows/ship.md +12 -0
- package/hooks/dist/gsd-graphify-update.sh +6 -0
- package/hooks/dist/gsd-statusline.js +3 -2
- package/hooks/dist/gsd-windsurf-pre-write.js +4 -4
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/gsd-worktree-path-guard.js +4 -4
- package/hooks/dist/lib/git-probe.js +16 -0
- package/hooks/gsd-graphify-update.sh +6 -0
- package/hooks/gsd-statusline.js +3 -2
- package/hooks/gsd-windsurf-pre-write.js +4 -4
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/gsd-worktree-path-guard.js +4 -4
- package/hooks/lib/git-probe.js +16 -0
- package/package.json +3 -3
- package/pi/package-agents/gsd-code-fixer.md +9 -4
- package/pi/package-agents/gsd-code-reviewer.md +53 -14
- package/pi/package-agents/gsd-executor.md +8 -4
- package/pi/package-agents/manifest.json +3 -3
- package/pi/package-skills/gsd-update/SKILL.md +4 -1
- package/scripts/ci-next-health.cjs +246 -23
- package/scripts/docs-guard-registry.cjs +2 -0
- package/scripts/gen-features.cjs +14 -2
- package/scripts/lib/drift-scan.cjs +27 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +6 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +11 -0
- package/scripts/lint-phase-enumeration-drift.cjs +8 -4
- package/scripts/lint-roadmap-progress-drift.cjs +421 -0
- package/scripts/mutation-matrix.cjs +23 -1
- package/scripts/sync-next-version.cjs +38 -6
- package/skills/gsd-update/SKILL.md +5 -2
- package/vscode/package.json +1 -1
|
@@ -22,7 +22,7 @@ const path = require('path');
|
|
|
22
22
|
const { spawnSync } = require('child_process');
|
|
23
23
|
const { tokenize, skipToSubcommand } = require('./lib/git-cmd.js');
|
|
24
24
|
const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
|
|
25
|
-
const { reportIfUndetermined, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
25
|
+
const { reportIfUndetermined, gitEnv, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
26
26
|
|
|
27
27
|
// This guard is almost entirely advisory (fail open — a broken advisory must
|
|
28
28
|
// never wedge every tool call), with ONE hard block (#3504 force-add-on-
|
|
@@ -83,6 +83,7 @@ function forceGitAddCwds(command, defaultCwd) {
|
|
|
83
83
|
function currentBranch(cwd) {
|
|
84
84
|
const result = spawnSync('git', ['branch', '--show-current'], { // allow-index-refresh: reads HEAD only, never opens the index
|
|
85
85
|
cwd,
|
|
86
|
+
env: gitEnv(),
|
|
86
87
|
encoding: 'utf8',
|
|
87
88
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
88
89
|
windowsHide: true,
|
|
@@ -18,7 +18,7 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { spawnSync } = require('child_process');
|
|
20
20
|
const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
|
|
21
|
-
const { reportIfUndetermined, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
21
|
+
const { reportIfUndetermined, gitEnv, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
22
22
|
|
|
23
23
|
// This guard's outer catch has always exited 0 (fail open): a path guard that
|
|
24
24
|
// cannot resolve the worktree must not block the user's edit — its whole job
|
|
@@ -49,10 +49,10 @@ const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeou
|
|
|
49
49
|
// Parity: tests/git-optional-locks-parity.test.cjs.
|
|
50
50
|
// A raw plugin-marketplace or git-clone install never ran `npm run build:lib`
|
|
51
51
|
// (#3582), so the compiled owner can be absent. This guard only runs
|
|
52
|
-
// `git rev-parse`, which never opens the index, so the
|
|
52
|
+
// `git rev-parse`, which never opens the index, so the scrubbed gitEnv() base
|
|
53
53
|
// loses nothing; requiring the artifact unguarded would throw at load and the
|
|
54
54
|
// containment guard would silently stop running.
|
|
55
|
-
let readOnlyGitEnv = (
|
|
55
|
+
let readOnlyGitEnv = (base = process.env) => base;
|
|
56
56
|
try {
|
|
57
57
|
const { ensureRuntimeBuild } = require('../gsd-core/bin/ensure-runtime-build.cjs');
|
|
58
58
|
ensureRuntimeBuild();
|
|
@@ -62,7 +62,7 @@ try {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function git(args, cwd) {
|
|
65
|
-
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv() });
|
|
65
|
+
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv(gitEnv()) });
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// Walk up from `start` to find the nearest existing directory.
|
|
@@ -92,7 +92,23 @@ function reportIfUndetermined(hookName, probeLabel, result) {
|
|
|
92
92
|
const BLOCKING_GUARD_PROBE_TIMEOUT_MS = 5000;
|
|
93
93
|
const BLOCKING_GUARD_MAX_SEQUENTIAL_PROBES = 3;
|
|
94
94
|
|
|
95
|
+
// #5548: repo-location vars git sets in hooks; inherited, they override the
|
|
96
|
+
// probe's cwd/-C. Parity-tested copy of GIT_LOCATION_ENV_VARS in
|
|
97
|
+
// src/shell-command-projection.cts (hooks ship standalone and cannot import it).
|
|
98
|
+
const GIT_LOCATION_ENV_VARS = [
|
|
99
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES', 'GIT_OBJECT_DIRECTORY', 'GIT_DIR', 'GIT_WORK_TREE',
|
|
100
|
+
'GIT_IMPLICIT_WORK_TREE', 'GIT_GRAFT_FILE', 'GIT_INDEX_FILE', 'GIT_NO_REPLACE_OBJECTS',
|
|
101
|
+
'GIT_REPLACE_REF_BASE', 'GIT_PREFIX', 'GIT_SHALLOW_FILE', 'GIT_COMMON_DIR',
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
/** `env` (default process.env) minus the repo-location vars (case-insensitive, for Windows). */
|
|
105
|
+
function gitEnv(env = process.env) {
|
|
106
|
+
return Object.fromEntries(Object.entries(env).filter(([k]) => !GIT_LOCATION_ENV_VARS.includes(k.toUpperCase())));
|
|
107
|
+
}
|
|
108
|
+
|
|
95
109
|
module.exports = {
|
|
110
|
+
GIT_LOCATION_ENV_VARS,
|
|
111
|
+
gitEnv,
|
|
96
112
|
classifyGitProbe,
|
|
97
113
|
reportIfUndetermined,
|
|
98
114
|
BLOCKING_GUARD_PROBE_TIMEOUT_MS,
|
|
@@ -81,6 +81,12 @@ case "$COMMAND" in
|
|
|
81
81
|
*) exit 0 ;;
|
|
82
82
|
esac
|
|
83
83
|
|
|
84
|
+
# #5548: inherited repo-location vars (GIT_DIR, GIT_INDEX_FILE, ...) would override
|
|
85
|
+
# cwd for every git call below. Drop git's own list minus the config-injection vars.
|
|
86
|
+
for v in $(git rev-parse --local-env-vars 2>/dev/null); do
|
|
87
|
+
case "$v" in GIT_CONFIG|GIT_CONFIG_PARAMETERS|GIT_CONFIG_COUNT) ;; *) unset "$v" ;; esac
|
|
88
|
+
done
|
|
89
|
+
|
|
84
90
|
# Gate 3 — inside git repo
|
|
85
91
|
git rev-parse --git-dir >/dev/null 2>&1 || exit 0
|
|
86
92
|
|
package/hooks/gsd-statusline.js
CHANGED
|
@@ -18,6 +18,7 @@ const os = require('os');
|
|
|
18
18
|
// monkeypatching childProcess.execFileSync.
|
|
19
19
|
const childProcess = require('child_process');
|
|
20
20
|
const { HOOK_ON_CRASH, allow, crash } = require('./lib/hook-exit.js');
|
|
21
|
+
const { gitEnv } = require('./lib/git-probe.js');
|
|
21
22
|
|
|
22
23
|
// This hook's build-seam outer catch (require.main guard just below) has
|
|
23
24
|
// always exited 0 (fail open — the statusline renders on EVERY prompt, so a
|
|
@@ -934,7 +935,7 @@ function readGitStatus(dir) {
|
|
|
934
935
|
// or untracked files; overflow still degrades safely to segment-absent via
|
|
935
936
|
// the catch below.
|
|
936
937
|
return childProcess.execFileSync('git', ['-C', dir, 'status', '--porcelain=v2', '--branch'],
|
|
937
|
-
{ encoding: 'utf8', timeout: GIT_STATUS_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true, env: readOnlyGitEnv() });
|
|
938
|
+
{ encoding: 'utf8', timeout: GIT_STATUS_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true, env: readOnlyGitEnv(gitEnv()) });
|
|
938
939
|
} catch (e) {
|
|
939
940
|
return null;
|
|
940
941
|
}
|
|
@@ -1029,7 +1030,7 @@ function readStateHeadCommits(root, stamp) {
|
|
|
1029
1030
|
try {
|
|
1030
1031
|
return childProcess.execFileSync('git', // allow-index-refresh: rev-list walks the commit graph and never opens the index
|
|
1031
1032
|
['-C', root, 'rev-list', '--left-right', '--count', `${stamp}...HEAD`],
|
|
1032
|
-
{ encoding: 'utf8', timeout: STATE_FRESHNESS_GIT_TIMEOUT_MS,
|
|
1033
|
+
{ env: gitEnv(), encoding: 'utf8', timeout: STATE_FRESHNESS_GIT_TIMEOUT_MS,
|
|
1033
1034
|
stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
1034
1035
|
} catch (e) {
|
|
1035
1036
|
return null;
|
|
@@ -31,7 +31,7 @@ const fs = require('fs');
|
|
|
31
31
|
const path = require('path');
|
|
32
32
|
const { spawnSync } = require('child_process');
|
|
33
33
|
const { allow, deny } = require('./lib/hook-exit.js');
|
|
34
|
-
const { reportIfUndetermined, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
34
|
+
const { reportIfUndetermined, gitEnv, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
35
35
|
|
|
36
36
|
// #3911 (ADR-3889 Phase 7): the exit(2) call site (block(), below) is
|
|
37
37
|
// migrated to hook-exit.js's deny(undefined, reason) — see
|
|
@@ -64,10 +64,10 @@ const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeou
|
|
|
64
64
|
// Parity: tests/git-optional-locks-parity.test.cjs.
|
|
65
65
|
// A raw plugin-marketplace or git-clone install never ran `npm run build:lib`
|
|
66
66
|
// (#3582), so the compiled owner can be absent. This guard only runs
|
|
67
|
-
// `git rev-parse`, which never opens the index, so the
|
|
67
|
+
// `git rev-parse`, which never opens the index, so the scrubbed gitEnv() base
|
|
68
68
|
// loses nothing; requiring the artifact unguarded would throw at load and the
|
|
69
69
|
// containment guard would silently stop running.
|
|
70
|
-
let readOnlyGitEnv = (
|
|
70
|
+
let readOnlyGitEnv = (base = process.env) => base;
|
|
71
71
|
try {
|
|
72
72
|
const { ensureRuntimeBuild } = require('../gsd-core/bin/ensure-runtime-build.cjs');
|
|
73
73
|
ensureRuntimeBuild();
|
|
@@ -77,7 +77,7 @@ try {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
function git(args, cwd) {
|
|
80
|
-
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv() });
|
|
80
|
+
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv(gitEnv()) });
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Walk up from `start` to find the nearest existing DIRECTORY (not merely an
|
|
@@ -22,7 +22,7 @@ const path = require('path');
|
|
|
22
22
|
const { spawnSync } = require('child_process');
|
|
23
23
|
const { tokenize, skipToSubcommand } = require('./lib/git-cmd.js');
|
|
24
24
|
const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
|
|
25
|
-
const { reportIfUndetermined, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
25
|
+
const { reportIfUndetermined, gitEnv, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
26
26
|
|
|
27
27
|
// This guard is almost entirely advisory (fail open — a broken advisory must
|
|
28
28
|
// never wedge every tool call), with ONE hard block (#3504 force-add-on-
|
|
@@ -83,6 +83,7 @@ function forceGitAddCwds(command, defaultCwd) {
|
|
|
83
83
|
function currentBranch(cwd) {
|
|
84
84
|
const result = spawnSync('git', ['branch', '--show-current'], { // allow-index-refresh: reads HEAD only, never opens the index
|
|
85
85
|
cwd,
|
|
86
|
+
env: gitEnv(),
|
|
86
87
|
encoding: 'utf8',
|
|
87
88
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
88
89
|
windowsHide: true,
|
|
@@ -18,7 +18,7 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { spawnSync } = require('child_process');
|
|
20
20
|
const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
|
|
21
|
-
const { reportIfUndetermined, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
21
|
+
const { reportIfUndetermined, gitEnv, BLOCKING_GUARD_PROBE_TIMEOUT_MS } = require('./lib/git-probe.js');
|
|
22
22
|
|
|
23
23
|
// This guard's outer catch has always exited 0 (fail open): a path guard that
|
|
24
24
|
// cannot resolve the worktree must not block the user's edit — its whole job
|
|
@@ -49,10 +49,10 @@ const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeou
|
|
|
49
49
|
// Parity: tests/git-optional-locks-parity.test.cjs.
|
|
50
50
|
// A raw plugin-marketplace or git-clone install never ran `npm run build:lib`
|
|
51
51
|
// (#3582), so the compiled owner can be absent. This guard only runs
|
|
52
|
-
// `git rev-parse`, which never opens the index, so the
|
|
52
|
+
// `git rev-parse`, which never opens the index, so the scrubbed gitEnv() base
|
|
53
53
|
// loses nothing; requiring the artifact unguarded would throw at load and the
|
|
54
54
|
// containment guard would silently stop running.
|
|
55
|
-
let readOnlyGitEnv = (
|
|
55
|
+
let readOnlyGitEnv = (base = process.env) => base;
|
|
56
56
|
try {
|
|
57
57
|
const { ensureRuntimeBuild } = require('../gsd-core/bin/ensure-runtime-build.cjs');
|
|
58
58
|
ensureRuntimeBuild();
|
|
@@ -62,7 +62,7 @@ try {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function git(args, cwd) {
|
|
65
|
-
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv() });
|
|
65
|
+
return spawnSync('git', args, { ...SPAWNOPT, cwd, env: readOnlyGitEnv(gitEnv()) });
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// Walk up from `start` to find the nearest existing directory.
|
package/hooks/lib/git-probe.js
CHANGED
|
@@ -92,7 +92,23 @@ function reportIfUndetermined(hookName, probeLabel, result) {
|
|
|
92
92
|
const BLOCKING_GUARD_PROBE_TIMEOUT_MS = 5000;
|
|
93
93
|
const BLOCKING_GUARD_MAX_SEQUENTIAL_PROBES = 3;
|
|
94
94
|
|
|
95
|
+
// #5548: repo-location vars git sets in hooks; inherited, they override the
|
|
96
|
+
// probe's cwd/-C. Parity-tested copy of GIT_LOCATION_ENV_VARS in
|
|
97
|
+
// src/shell-command-projection.cts (hooks ship standalone and cannot import it).
|
|
98
|
+
const GIT_LOCATION_ENV_VARS = [
|
|
99
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES', 'GIT_OBJECT_DIRECTORY', 'GIT_DIR', 'GIT_WORK_TREE',
|
|
100
|
+
'GIT_IMPLICIT_WORK_TREE', 'GIT_GRAFT_FILE', 'GIT_INDEX_FILE', 'GIT_NO_REPLACE_OBJECTS',
|
|
101
|
+
'GIT_REPLACE_REF_BASE', 'GIT_PREFIX', 'GIT_SHALLOW_FILE', 'GIT_COMMON_DIR',
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
/** `env` (default process.env) minus the repo-location vars (case-insensitive, for Windows). */
|
|
105
|
+
function gitEnv(env = process.env) {
|
|
106
|
+
return Object.fromEntries(Object.entries(env).filter(([k]) => !GIT_LOCATION_ENV_VARS.includes(k.toUpperCase())));
|
|
107
|
+
}
|
|
108
|
+
|
|
95
109
|
module.exports = {
|
|
110
|
+
GIT_LOCATION_ENV_VARS,
|
|
111
|
+
gitEnv,
|
|
96
112
|
classifyGitProbe,
|
|
97
113
|
reportIfUndetermined,
|
|
98
114
|
BLOCKING_GUARD_PROBE_TIMEOUT_MS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/gsd-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
5
5
|
"main": ".opencode/plugins/gsd-core.js",
|
|
6
6
|
"bin": {
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"gpt-tokenizer": "4.0.0",
|
|
92
92
|
"js-yaml": "^4.3.2",
|
|
93
93
|
"mutation-testing-metrics": "^3.7.3",
|
|
94
|
-
"re2js": "^2.8.
|
|
94
|
+
"re2js": "^2.8.7",
|
|
95
95
|
"saxes": "6.0.0",
|
|
96
96
|
"tap-parser": "18.3.4",
|
|
97
97
|
"typescript": "^6.0.3",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"lint:gate-positive-control": "node scripts/lint-gate-positive-control.cjs",
|
|
147
147
|
"lint:frontmatter-fence-drift": "node scripts/lint-frontmatter-fence-drift.cjs",
|
|
148
148
|
"lint:response-language": "node scripts/lint-response-language-coverage.cjs",
|
|
149
|
-
"lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && npm run lint:retired-runtime-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-portable-timeout.cjs && node scripts/lint-portable-grep.cjs && node scripts/lint-allowed-tools-parity.cjs && node scripts/lint-phase-arg-assignment.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-planning-document-positive-control.cjs && node scripts/lint-pr-branch-pattern-drift.cjs && node scripts/lint-fix-has-regression-tests.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs && node scripts/lint-plan-count-drift.cjs && node scripts/lint-milestone-window-drift.cjs && node scripts/lint-phase-enumeration-drift.cjs && node scripts/lint-planning-prompt-drift.cjs && node scripts/lint-unreachable-guard-drift.cjs && node scripts/lint-completion-ratio-drift.cjs && node scripts/lint-slug-derivation-drift.cjs && node scripts/lint-state-field-drift.cjs && node scripts/lint-state-write-path-drift.cjs && node scripts/lint-completion-predicate-drift.cjs && node scripts/lint-planning-snapshot-bypass-drift.cjs && node scripts/lint-health-diagnostic-rule-table.cjs && node scripts/lint-planning-artifact-writer-drift.cjs && node scripts/lint-frontmatter-scalar-broad-grep.cjs && node scripts/lint-removed-but-needed.cjs && node scripts/lint-no-adhoc-regex-escape.cjs && node scripts/lint-vendored-deps.cjs && node scripts/lint-docs-guard-registration.cjs && node scripts/lint-source-test-name-collision.cjs && npm run lint:hooks-runtime-build-seam && node scripts/check-contract-drift.cjs && node scripts/lint-mutation-test-derivation-drift.cjs && node scripts/lint-seam-enforcement.cjs && node scripts/lint-workflow-shellcheck.cjs && npm run lint:response-language && node scripts/lint-verify-lifecycle-writes.cjs && node scripts/lint-frontmatter-fence-drift.cjs && node scripts/lint-evaluation-scope-drift.cjs && node scripts/lint-gate-evidence-drift.cjs && node scripts/lint-gate-positive-control.cjs",
|
|
149
|
+
"lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && npm run lint:retired-runtime-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-portable-timeout.cjs && node scripts/lint-portable-grep.cjs && node scripts/lint-allowed-tools-parity.cjs && node scripts/lint-phase-arg-assignment.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-planning-document-positive-control.cjs && node scripts/lint-pr-branch-pattern-drift.cjs && node scripts/lint-fix-has-regression-tests.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs && node scripts/lint-plan-count-drift.cjs && node scripts/lint-milestone-window-drift.cjs && node scripts/lint-phase-enumeration-drift.cjs && node scripts/lint-planning-prompt-drift.cjs && node scripts/lint-unreachable-guard-drift.cjs && node scripts/lint-completion-ratio-drift.cjs && node scripts/lint-slug-derivation-drift.cjs && node scripts/lint-state-field-drift.cjs && node scripts/lint-state-write-path-drift.cjs && node scripts/lint-completion-predicate-drift.cjs && node scripts/lint-planning-snapshot-bypass-drift.cjs && node scripts/lint-health-diagnostic-rule-table.cjs && node scripts/lint-planning-artifact-writer-drift.cjs && node scripts/lint-frontmatter-scalar-broad-grep.cjs && node scripts/lint-removed-but-needed.cjs && node scripts/lint-no-adhoc-regex-escape.cjs && node scripts/lint-vendored-deps.cjs && node scripts/lint-docs-guard-registration.cjs && node scripts/lint-source-test-name-collision.cjs && npm run lint:hooks-runtime-build-seam && node scripts/check-contract-drift.cjs && node scripts/lint-mutation-test-derivation-drift.cjs && node scripts/lint-seam-enforcement.cjs && node scripts/lint-workflow-shellcheck.cjs && npm run lint:response-language && node scripts/lint-verify-lifecycle-writes.cjs && node scripts/lint-frontmatter-fence-drift.cjs && node scripts/lint-evaluation-scope-drift.cjs && node scripts/lint-gate-evidence-drift.cjs && node scripts/lint-gate-positive-control.cjs && node scripts/lint-roadmap-progress-drift.cjs",
|
|
150
150
|
"lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
|
|
151
151
|
"lint:regression-names": "node scripts/lint-regression-test-names.cjs",
|
|
152
152
|
"lint:descriptions": "node scripts/lint-descriptions.cjs",
|
|
@@ -157,6 +157,8 @@ Each finding starts with:
|
|
|
157
157
|
|
|
158
158
|
Where ID matches: `CR-\d+` or `BL-\d+` (Critical-tier-equivalent), `WR-\d+` (Warning), or `IN-\d+` (Info)
|
|
159
159
|
|
|
160
|
+
A finding whose body carries a `**Category:** necessity` line is a **necessity finding** (#4100): code the reviewer judged unnecessary, not broken. Its prefix still gives its severity.
|
|
161
|
+
|
|
160
162
|
**Required Fields:**
|
|
161
163
|
|
|
162
164
|
- **File:** line contains primary file path
|
|
@@ -438,7 +440,7 @@ This cleanup is unconditional when a worktree was created — register it mental
|
|
|
438
440
|
- `phase_dir`: Path to phase directory (e.g., `.planning/phases/02-code-review-command`)
|
|
439
441
|
- `padded_phase`: Zero-padded phase number (e.g., "02")
|
|
440
442
|
- `review_path`: Full path to REVIEW.md (e.g., `.planning/phases/02-code-review-command/02-REVIEW.md`)
|
|
441
|
-
- `fix_scope`: "critical_warning" (default) or "all" (includes Info findings)
|
|
443
|
+
- `fix_scope`: "critical_warning" (default) or "all" (includes Info and necessity findings)
|
|
442
444
|
- `fix_report_path`: Full path for REVIEW-FIX.md output (e.g., `.planning/phases/02-code-review-command/02-REVIEW-FIX.md`)
|
|
443
445
|
|
|
444
446
|
**3. Read REVIEW.md:**
|
|
@@ -464,6 +466,7 @@ Read `./CLAUDE.md` and check for `.claude/skills/` or `.agents/skills/` (as desc
|
|
|
464
466
|
For each finding, extract:
|
|
465
467
|
- `id`: Finding identifier (e.g., CR-01, WR-03, IN-12)
|
|
466
468
|
- `severity`: Critical (CR-* or BL-*), Warning (WR-*), Info (IN-*)
|
|
469
|
+
- `category`: `necessity` when the finding carries a `**Category:** necessity` line, otherwise none
|
|
467
470
|
- `title`: Issue title from `### ` heading
|
|
468
471
|
- `file`: Primary file path from **File:** line
|
|
469
472
|
- `files`: ALL file paths referenced in finding (including in Fix section) — for multi-file fixes
|
|
@@ -472,15 +475,17 @@ For each finding, extract:
|
|
|
472
475
|
- `fix`: Full fix content from **Fix:** section (may be multi-line, may contain code fences)
|
|
473
476
|
|
|
474
477
|
**2. Filter by fix_scope:**
|
|
475
|
-
- If `fix_scope == "critical_warning"`: include only CR-*, BL-*, and WR-* findings
|
|
476
|
-
- If `fix_scope == "all"`: include CR-*, BL-*, WR-*, and IN-* findings
|
|
478
|
+
- If `fix_scope == "critical_warning"`: include only CR-*, BL-*, and WR-* findings; `critical_warning` excludes necessity findings (removing code is a scope decision for the human, #4100). The marker overrides the prefix: a WR-* finding carrying `**Category:** necessity` is OUT of scope here, and is skipped without applying any edit
|
|
479
|
+
- If `fix_scope == "all"`: include CR-*, BL-*, WR-*, and IN-* findings; `all` includes necessity findings, ordered last. A necessity fix removes code, so record it as `fixed: requires human verification`
|
|
477
480
|
|
|
478
481
|
**3. Sort findings by severity:**
|
|
479
|
-
- Critical (CR-* and BL-*) first, then Warning, then Info
|
|
482
|
+
- Critical (CR-* and BL-*) first, then Warning, then Info, then necessity findings
|
|
480
483
|
- Within same severity, maintain document order
|
|
481
484
|
|
|
482
485
|
**4. Count findings in scope:**
|
|
483
486
|
Record `findings_in_scope` for REVIEW-FIX.md frontmatter.
|
|
487
|
+
|
|
488
|
+
If `findings_in_scope` is 0, apply nothing: write REVIEW-FIX.md with `fixed: 0`, `skipped: 0`, `status: all_fixed`, and a body stating that no finding was in scope and the out-of-scope findings remain in REVIEW.md.
|
|
484
489
|
</step>
|
|
485
490
|
|
|
486
491
|
<step name="apply_fixes">
|
|
@@ -60,6 +60,8 @@ This ensures project-specific patterns, conventions, and best practices are appl
|
|
|
60
60
|
|
|
61
61
|
**3. Code Quality** — Dead code, unused imports/variables, poor naming conventions, missing error handling, inconsistent patterns, overly complex functions (high cyclomatic complexity), code duplication, magic numbers, commented-out code
|
|
62
62
|
|
|
63
|
+
**4. Necessity** (#4100) — reachable code whose guarded-against problem cannot occur in this stack: impossible-state guard, already-defended-elsewhere, cargo-culted pattern, phantom requirement, generality without instantiation. At `standard`/`deep`, Read `__GSD_PI_ENGINE_ROOT__/gsd-core/references/necessity-review.md` before classifying findings; if it cannot be read, say so in the Summary and omit `necessity:`. `quick` does not assess necessity. Warning when provable from the repo, Info when it rests on judgment, Never Critical; each finding cites the evidence that the state cannot occur and carries a `**Category:** necessity` line.
|
|
64
|
+
|
|
63
65
|
**Out of Scope (v1):** Performance issues (O(n²) algorithms, memory leaks, inefficient queries) are NOT in scope for v1. Focus on correctness, security, and maintainability.
|
|
64
66
|
|
|
65
67
|
</review_scope>
|
|
@@ -70,12 +72,17 @@ This ensures project-specific patterns, conventions, and best practices are appl
|
|
|
70
72
|
|
|
71
73
|
**quick** — Pattern-matching only. Use grep/regex to scan for common anti-patterns without reading full file contents. Target: under 2 minutes.
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
- Hardcoded secrets
|
|
75
|
-
- Dangerous functions
|
|
76
|
-
- Debug artifacts
|
|
77
|
-
- Empty catch blocks
|
|
78
|
-
- Commented-out code
|
|
75
|
+
Checks (commands in `review_by_depth`):
|
|
76
|
+
- Hardcoded secrets
|
|
77
|
+
- Dangerous functions
|
|
78
|
+
- Debug artifacts
|
|
79
|
+
- Empty catch blocks
|
|
80
|
+
- Commented-out code
|
|
81
|
+
- Unpinned actions
|
|
82
|
+
- Non-idempotent install
|
|
83
|
+
- Missing job timeout
|
|
84
|
+
|
|
85
|
+
The last three: GitHub Actions workflows only.
|
|
79
86
|
|
|
80
87
|
**standard** (default) — Read each changed file. Check for bugs, security issues, and quality problems in context. Cross-reference imports and exports. Target: 5-15 minutes.
|
|
81
88
|
|
|
@@ -85,6 +92,7 @@ Language-aware checks:
|
|
|
85
92
|
- **Go**: Unchecked error returns, goroutine leaks, context not passed, `defer` in loops, race conditions
|
|
86
93
|
- **C/C++**: Buffer overflow patterns, use-after-free indicators, null pointer dereferences, missing bounds checks, memory leaks
|
|
87
94
|
- **Shell**: Unquoted variables, `eval` usage, missing `set -e`, command injection via interpolation
|
|
95
|
+
- **CI/CD pipelines** (by path: `.github/workflows/*.yml`, `Dockerfile*`, `docker-compose*.yml`, deploy scripts): Read `__GSD_PI_ENGINE_ROOT__/gsd-core/references/cicd-review-patterns.md`; if it cannot be read, say so in the Summary and check: non-idempotent steps (`npm install` vs `npm ci`, unlocked `pip install`, unguarded `mkdir`/`rm`), no job `timeout-minutes`, deploy without `concurrency` + `cancel-in-progress`, per-environment rebuild (not build-once), no health check or rollback, load-bearing `continue-on-error`, static credentials where OIDC works, unpinned actions
|
|
88
96
|
|
|
89
97
|
**deep** — All of standard, plus cross-file analysis. Trace function call chains across imports. Target: 15-30 minutes.
|
|
90
98
|
|
|
@@ -173,6 +181,7 @@ NOTE: Do NOT exclude all `.md` files — commands, workflows, and agents are sou
|
|
|
173
181
|
- Go: `.go`
|
|
174
182
|
- C/C++: `.c`, `.cpp`, `.h`, `.hpp`
|
|
175
183
|
- Shell: `.sh`, `.bash`
|
|
184
|
+
- CI/CD (by path): `.github/workflows/*.yml`/`*.yaml`, `Dockerfile*`, `docker-compose*.yml`, `deploy*.sh` (also Shell)
|
|
176
185
|
- Other: Review generically
|
|
177
186
|
|
|
178
187
|
**3. Exit early if empty:** If no source files remain after filtering, create REVIEW.md with:
|
|
@@ -193,22 +202,48 @@ NOTE: `status: clean` means "reviewed and found no issues." `status: skipped` me
|
|
|
193
202
|
Branch on depth level:
|
|
194
203
|
|
|
195
204
|
**For depth=quick:**
|
|
196
|
-
Run
|
|
205
|
+
Run every check from `<depth_levels>` quick section:
|
|
197
206
|
```bash
|
|
207
|
+
# Set FILE per scoped path with: while IFS= read -r FILE (never paste a name into code).
|
|
208
|
+
|
|
198
209
|
# Hardcoded secrets
|
|
199
|
-
grep -n -E "(password|secret|api_key|token|apikey|api-key)\s*[=:]\s*['\"]\
|
|
210
|
+
grep -n -E -- "(password|secret|api_key|token|apikey|api-key)\s*[=:]\s*['\"][^'\"]+['\"]" "$FILE"
|
|
200
211
|
|
|
201
212
|
# Dangerous functions
|
|
202
|
-
grep -n -E "eval\(|innerHTML|dangerouslySetInnerHTML|exec\(|system\(|shell_exec"
|
|
213
|
+
grep -n -E -- "eval\(|innerHTML|dangerouslySetInnerHTML|exec\(|system\(|shell_exec|passthru" "$FILE"
|
|
203
214
|
|
|
204
215
|
# Debug artifacts
|
|
205
|
-
grep -n -E "console\.log|debugger;|TODO|FIXME|XXX|HACK"
|
|
206
|
-
|
|
207
|
-
# Empty catch
|
|
208
|
-
grep -n -E "catch\s*\([^)]*\)\s*\{\s*\}"
|
|
216
|
+
grep -n -E -- "console\.log|debugger;|TODO|FIXME|XXX|HACK" "$FILE"
|
|
217
|
+
|
|
218
|
+
# Empty catch blocks
|
|
219
|
+
grep -n -E -- "catch\s*\([^)]*\)\s*\{\s*\}" "$FILE"
|
|
220
|
+
|
|
221
|
+
# Commented-out code
|
|
222
|
+
grep -n -E -- "^\s*//.*[{};]|^\s*#[[:space:]]*(if|for|while|def|class|elif|else|try|except|with)[[:space:](].*:[[:space:]]*$|^\s*/\*[^*].*[{};]" "$FILE"
|
|
223
|
+
|
|
224
|
+
# Unpinned actions
|
|
225
|
+
grep -n -E -- "^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]*['\"]?[^[:space:]'\"]+@(main|master|latest)['\"]?([[:space:]]|$)" "$FILE"
|
|
226
|
+
|
|
227
|
+
# Non-idempotent install
|
|
228
|
+
[ -f package-lock.json ] && grep -n -E -- "(^|[^[:alnum:]_-])npm[[:space:]]+(install|i)([[:space:]]|$)" "$FILE" | grep -v -E "^[0-9]+:[[:space:]]*#|[[:space:]](-g|--global)([[:space:]]|$)"
|
|
229
|
+
|
|
230
|
+
# Missing job timeout
|
|
231
|
+
awk '
|
|
232
|
+
function flush() { if (job != "" && runs && !timed) print line ": " job ": no job-level timeout-minutes"; job = "" }
|
|
233
|
+
{ sub(/\r$/, "") }
|
|
234
|
+
/^[^[:space:]#]/ { flush(); injobs = ($0 ~ /^jobs:[[:space:]]*(#.*)?$/); jind = -1; next }
|
|
235
|
+
!injobs || /^[[:space:]]*(#.*)?$/ { next }
|
|
236
|
+
{ ind = match($0, /[^ ]/) - 1 }
|
|
237
|
+
jind < 0 { jind = ind }
|
|
238
|
+
ind == jind { flush(); job = $0; sub(/^ +/, "", job); sub(/:.*/, "", job); line = NR; kind = -1; runs = 0; timed = 0; next }
|
|
239
|
+
kind < 0 { kind = ind }
|
|
240
|
+
ind == kind && /^ *runs-on:/ { runs = 1 }
|
|
241
|
+
ind == kind && /^ *timeout-minutes:/ { timed = 1 }
|
|
242
|
+
END { flush() }
|
|
243
|
+
' "$FILE"
|
|
209
244
|
```
|
|
210
245
|
|
|
211
|
-
Record findings with severity: secrets/dangerous=Critical, debug=Info, empty catch=Warning
|
|
246
|
+
Record findings with severity: secrets/dangerous=Critical, debug and commented-out code=Info, empty catch and the three CI/CD checks=Warning
|
|
212
247
|
|
|
213
248
|
**For depth=standard:**
|
|
214
249
|
For each file:
|
|
@@ -252,6 +287,7 @@ For each finding, assign severity:
|
|
|
252
287
|
- Type coercion issues (`==` vs `===`)
|
|
253
288
|
- Unhandled promise rejections
|
|
254
289
|
- Dead code paths that indicate logic errors
|
|
290
|
+
- CI/CD pipeline findings: every check in the CI/CD entry
|
|
255
291
|
|
|
256
292
|
**Info** — Style issues, naming improvements, dead code, unused imports, suggestions:
|
|
257
293
|
- Unused imports/variables
|
|
@@ -286,10 +322,13 @@ findings:
|
|
|
286
322
|
warning: N
|
|
287
323
|
info: N
|
|
288
324
|
total: N
|
|
325
|
+
necessity: N
|
|
289
326
|
status: clean | issues_found
|
|
290
327
|
---
|
|
291
328
|
```
|
|
292
329
|
|
|
330
|
+
Emit `necessity:` only at standard/deep depth. It counts the necessity findings among `warning` + `info` and is never added to `total`.
|
|
331
|
+
|
|
293
332
|
**3. Body sections (required order):**
|
|
294
333
|
1) `## Structural Findings (fallow)` — only when structural findings were provided; list normalized items first.
|
|
295
334
|
2) `## Narrative Findings (AI reviewer)` — your adversarial findings from direct code review, including any external-reviewer claim you independently verified (`(external: {slug})`, see `load_context` step 5).
|
|
@@ -761,7 +761,14 @@ Do NOT skip. Do NOT proceed to state updates if self-check fails.
|
|
|
761
761
|
</self_check>
|
|
762
762
|
|
|
763
763
|
<state_updates>
|
|
764
|
-
After SUMMARY.md, update STATE.md
|
|
764
|
+
After SUMMARY.md, update ROADMAP.md progress FIRST, then STATE.md. The ROADMAP write is the step that can decline (`missing_phase_details`), and a decline stops the plan before any STATE.md write, so STATE.md never advances past a plan the ROADMAP did not record:
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
# Update ROADMAP.md progress for this phase (plan counts, status). A decline stops here, before STATE.md moves.
|
|
768
|
+
PROGRESS=$(gsd_run query roadmap.update-plan-progress "${PHASE_NUMBER}") && REASON=$(jq -er '.reason//""' <<<"$PROGRESS") && [ "$REASON" != missing_phase_details ] || { echo "ERROR: ROADMAP update-plan-progress did not complete for ${PHASE_NUMBER}-${PLAN} (missing_phase_details decline, failed query, or jq not installed). STOP: skip this plan's completion steps." >&2; exit 1; }
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
Then update STATE.md using `gsd-tools query` state handlers (named flags):
|
|
765
772
|
|
|
766
773
|
```bash
|
|
767
774
|
# Advance plan counter (handles edge cases automatically)
|
|
@@ -788,9 +795,6 @@ gsd_run query state.record-session \
|
|
|
788
795
|
```
|
|
789
796
|
|
|
790
797
|
```bash
|
|
791
|
-
# Update ROADMAP.md progress for this phase (plan counts, status)
|
|
792
|
-
gsd_run query roadmap.update-plan-progress "${PHASE_NUMBER}"
|
|
793
|
-
|
|
794
798
|
# Mark completed requirements from PLAN.md frontmatter
|
|
795
799
|
# Extract the `requirements` array from the plan's frontmatter, then mark each complete
|
|
796
800
|
gsd_run query requirements.mark-complete ${REQ_IDS}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"gsd-advisor-researcher.md": "6988b236b53568bbcea7886d11ca9f0badf9aedb3f650d42ca894211d91aafe4",
|
|
4
4
|
"gsd-ai-researcher.md": "bdc567357f7361d7e427a2730bdac17c0b28ecb1bcbbc687df68d573f0ee9f3e",
|
|
5
5
|
"gsd-assumptions-analyzer.md": "56b243f4c50403cbc133ad8c91ae40aa1aeceadd6624d0fd26406ebf8c113205",
|
|
6
|
-
"gsd-code-fixer.md": "
|
|
7
|
-
"gsd-code-reviewer.md": "
|
|
6
|
+
"gsd-code-fixer.md": "2d806b6bae3797a7757b4872a93790fe33a4f22e90f6e71f6344b52df3048d52",
|
|
7
|
+
"gsd-code-reviewer.md": "459b38676fd7e6b7bf147a9c3d88243630ff289366a359c7c489536d38b2bd21",
|
|
8
8
|
"gsd-codebase-mapper.md": "5901db6721a6f2365be52819a41ab1c1590a7cbbbdc6d992dce2a7b99f7d12fb",
|
|
9
9
|
"gsd-debug-session-manager.md": "7b68386a6ab0169eb4c1b44afa921b8196db1eac1af3a0dd07a87d5ae2b208ef",
|
|
10
10
|
"gsd-debugger.md": "7328920b7fbee1b76af7259a14b96290562544d97c6ced1291e1e1f3529e1598",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"gsd-domain-researcher.md": "f1b07d9c79dcb89c90e5af7f61adfa5dc73ebe8429783d8cb281d7ae2bdc682b",
|
|
17
17
|
"gsd-eval-auditor.md": "9d77e7329c52741e7e62185b566231eb872c6b34afa6c869960a922af573b3d5",
|
|
18
18
|
"gsd-eval-planner.md": "efc12a2822d77a5989db2e3efe83b7fda9f0509bb203910d7e26eb9369f89949",
|
|
19
|
-
"gsd-executor.md": "
|
|
19
|
+
"gsd-executor.md": "45e9540f6380b1883ad5b144411b21447eef20f310cbd0ab7c72c2bdaf5f8c47",
|
|
20
20
|
"gsd-framework-selector.md": "96d52931468372ee88c4f1d551c13c97d2be8079053b55d992e0ea1720d3d5c9",
|
|
21
21
|
"gsd-integration-checker.md": "a233ab8c5c97b6099c649d1e9a09e88ff1ed1bf7df7c1b13bc766c33d58e09b9",
|
|
22
22
|
"gsd-intel-updater.md": "26c70b81580cc5bf713959bdcc84a16a35569861d2e79c07c71258ccd05ba9bc",
|
|
@@ -33,14 +33,17 @@ Routes to the update workflow which handles:
|
|
|
33
33
|
<flags>
|
|
34
34
|
- **--sync**: Sync managed GSD skills across runtime roots so multi-runtime users stay aligned after an update. Runs the sync-skills workflow (--from, --to, --dry-run, --apply flags supported).
|
|
35
35
|
- **--reapply**: Reapply local modifications after a GSD update. Uses three-way comparison (pristine baseline, user-modified backup, newly installed version) to merge user customizations back. Runs the reapply-patches workflow.
|
|
36
|
+
- **--interactive[=exceptions|all]** (with `--reapply` only): show each user edit next to the stock text with a recommended disposition and wait for a keep / retire / rewrite decision per edit. `all` shows every edit; `exceptions` (bare `--interactive`) shows only edits upstream adopted, partly adopted, reworded around, or orphaned, and keeps the rest. Without it, `--reapply` behaves exactly as before.
|
|
36
37
|
- **--next** (alias **--rc**): Target the `@next` RC dist-tag instead of `@latest` so you can install or refresh a release candidate (e.g. `1.4.0-rc.1`) through the normal update flow — scope/runtime detection, changelog preview, custom-file backup, and cache clearing all still apply. Omitting it keeps targeting `@latest` (no change). See ADR #660 for the RC channel.
|
|
37
38
|
- **(no flag)**: Standard update — check for new version, show changelog, install.
|
|
38
39
|
</flags>
|
|
39
40
|
|
|
40
41
|
<process>
|
|
42
|
+
If the arguments contain `--interactive` (bare or with a value) but not `--reapply`, STOP with: `--interactive applies only to --reapply (for example: /skill:gsd-update --reapply --interactive=all)`. Do nothing else.
|
|
43
|
+
|
|
41
44
|
Parse the first token of the `<arguments>` block:
|
|
42
45
|
- If it is `--sync`: strip the flag, execute the sync-skills workflow (passing remaining args for --from/--to/--dry-run/--apply).
|
|
43
|
-
- If it is `--reapply`: strip the flag, execute the reapply-patches workflow.
|
|
46
|
+
- If it is `--reapply`: strip the flag, execute the reapply-patches workflow, passing the remaining arguments (for example `--interactive=all`) to it.
|
|
44
47
|
- Otherwise (including `--next` / `--rc`): execute the update workflow end-to-end, passing the `<arguments>` block through so the workflow's parse_update_channel step can select the release channel.
|
|
45
48
|
|
|
46
49
|
</process>
|