@opengsd/gsd-core 1.20.1 → 1.21.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/.opencode/plugins/gsd-core.js +33 -2
- package/agents/gsd-executor.md +1 -1
- package/agents/gsd-plan-checker.md +1 -1
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-verifier.md +2 -2
- package/bin/install.js +234 -126
- package/commands/gsd/autonomous.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +450 -753
- package/gsd-core/bin/lib/capability-activation.cjs +8 -2
- package/gsd-core/bin/lib/capability-command-router.cjs +6 -2
- package/gsd-core/bin/lib/capability-ledger.cjs +1 -1
- package/gsd-core/bin/lib/capability-lock.cjs +19 -27
- package/gsd-core/bin/lib/capability-registry.cjs +74 -71
- package/gsd-core/bin/lib/capability-validator.cjs +1 -0
- package/gsd-core/bin/lib/capability-writer.cjs +7 -4
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +142 -62
- package/gsd-core/bin/lib/claude-orchestration.cjs +214 -122
- package/gsd-core/bin/lib/cli-surface.cjs +545 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +356 -103
- package/gsd-core/bin/lib/commands.cjs +80 -2
- package/gsd-core/bin/lib/config-file-read.cjs +85 -0
- package/gsd-core/bin/lib/config-loader.cjs +23 -15
- package/gsd-core/bin/lib/config.cjs +139 -101
- package/gsd-core/bin/lib/configuration.cjs +41 -2
- package/gsd-core/bin/lib/criterion-baseline.cjs +346 -0
- package/gsd-core/bin/lib/criterion-replay.cjs +380 -0
- package/gsd-core/bin/lib/estimate-cli.cjs +5 -1
- package/gsd-core/bin/lib/gap-checker.cjs +12 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +593 -27
- package/gsd-core/bin/lib/gate-phase-context.cjs +16 -4
- package/gsd-core/bin/lib/graphify.cjs +19 -2
- package/gsd-core/bin/lib/health-diagnostic.cjs +5 -1
- package/gsd-core/bin/lib/init.cjs +13 -11
- package/gsd-core/bin/lib/install-effort-resolver.cjs +24 -4
- package/gsd-core/bin/lib/install-engine.cjs +11 -19
- package/gsd-core/bin/lib/install-fs-adapter.cjs +5 -1
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -3
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +62 -31
- package/gsd-core/bin/lib/markdown-table.cjs +39 -1
- package/gsd-core/bin/lib/milestone.cjs +8 -6
- package/gsd-core/bin/lib/model-resolver.cjs +8 -4
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +14 -0
- package/gsd-core/bin/lib/phase-locator.cjs +8 -3
- package/gsd-core/bin/lib/phase.cjs +107 -31
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +46 -23
- package/gsd-core/bin/lib/planning-snapshot.cjs +8 -4
- package/gsd-core/bin/lib/planning-workspace.cjs +20 -10
- package/gsd-core/bin/lib/profile-output.cjs +9 -6
- package/gsd-core/bin/lib/project-context.cjs +439 -0
- package/gsd-core/bin/lib/project-root.cjs +9 -230
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +1 -1
- package/gsd-core/bin/lib/report-parser.cjs +16 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +328 -50
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +24 -5
- package/gsd-core/bin/lib/roadmap.cjs +2 -2
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +7 -4
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +81 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +279 -8
- package/gsd-core/bin/lib/runtime-slash.cjs +7 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +1010 -10
- package/gsd-core/bin/lib/stale-bake-guard.cjs +4 -1
- package/gsd-core/bin/lib/state-transition.cjs +91 -41
- package/gsd-core/bin/lib/state.cjs +446 -61
- package/gsd-core/bin/lib/surface.cjs +4 -7
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +10 -3
- package/gsd-core/bin/lib/verify-command-router.cjs +6 -1
- package/gsd-core/bin/lib/verify.cjs +49 -6
- package/gsd-core/bin/lib/worktree-safety.cjs +8 -111
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/autonomous-smart-discuss.md +99 -18
- package/gsd-core/references/checkpoints.md +1 -1
- package/gsd-core/references/planner-guidance.md +11 -0
- package/gsd-core/references/planner-human-verify-mode.md +1 -1
- package/gsd-core/references/planner-reversibility.md +2 -0
- package/gsd-core/references/planner-verify-command-grounding.md +22 -6
- package/gsd-core/workflows/autonomous.md +4 -4
- package/gsd-core/workflows/code-review-fix.md +5 -7
- package/gsd-core/workflows/execute-phase.md +21 -7
- package/gsd-core/workflows/plan-phase/steps/plan-pre-dispatch.md +101 -0
- package/gsd-core/workflows/plan-phase.md +18 -19
- package/hooks/dist/gsd-agent-isolation-guard.js +3 -2
- package/hooks/dist/gsd-config-reload.js +2 -2
- package/hooks/dist/gsd-context-monitor.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -5
- package/hooks/dist/gsd-read-injection-scanner.js +2 -2
- package/hooks/dist/gsd-secret-read-guard.js +141 -6
- package/hooks/dist/gsd-statusline.js +3 -2
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/lib/config-read.js +49 -0
- package/hooks/dist/lib/git-cmd.js +3 -1
- package/hooks/dist/lib/git-head-tree.js +474 -0
- package/hooks/dist/lib/isolation-sentinel.js +97 -17
- package/hooks/dist/lib/secret-read-exemptions.js +161 -0
- package/hooks/gsd-agent-isolation-guard.js +3 -2
- package/hooks/gsd-config-reload.js +2 -2
- package/hooks/gsd-context-monitor.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +8 -5
- package/hooks/gsd-read-injection-scanner.js +2 -2
- package/hooks/gsd-secret-read-guard.js +141 -6
- package/hooks/gsd-statusline.js +3 -2
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/lib/config-read.js +49 -0
- package/hooks/lib/git-cmd.js +3 -1
- package/hooks/lib/git-head-tree.js +474 -0
- package/hooks/lib/isolation-sentinel.js +97 -17
- package/hooks/lib/secret-read-exemptions.js +161 -0
- package/package.json +7 -2
- package/pi/package-agents/gsd-executor.md +1 -1
- package/pi/package-agents/gsd-plan-checker.md +1 -1
- package/pi/package-agents/gsd-planner.md +3 -3
- package/pi/package-agents/gsd-verifier.md +2 -2
- package/pi/package-agents/manifest.json +4 -4
- package/pi/package-skills/gsd-autonomous/SKILL.md +1 -1
- package/scripts/changeset/cli.cjs +2 -2
- package/scripts/changeset/serialize.cjs +12 -2
- package/scripts/ci-compact-v8-coverage.cjs +204 -0
- package/scripts/ci-fix-next-rerun.cjs +149 -0
- package/scripts/ci-next-health.cjs +52 -9
- package/scripts/ci-test-scope.cjs +77 -71
- package/scripts/command-contract-helpers.cjs +56 -7
- package/scripts/docs-guard-registry.cjs +3 -0
- package/scripts/gen-cli-surface-manifest.cjs +287 -0
- package/scripts/gen-platform-conformance-tier.cjs +258 -19
- package/scripts/lib/macos-conformance-tier.generated.cjs +55 -47
- package/scripts/lib/platform-conformance-tier.generated.cjs +19 -64
- package/scripts/lib/shellcheck-fetch.cjs +71 -4
- package/scripts/lint-removed-but-needed.cjs +562 -50
- package/scripts/release-notes/changelog-release-notes.cjs +345 -0
- package/scripts/release-notes/discord-release-summary.cjs +82 -1
- package/scripts/timeout-evidence-from-ci.cjs +964 -0
- package/skills/gsd-autonomous/SKILL.md +1 -1
- package/vscode/package.json +1 -1
|
@@ -15,6 +15,14 @@
|
|
|
15
15
|
* reader (no third-party archive library), and caches the extracted binary
|
|
16
16
|
* for reuse across runs.
|
|
17
17
|
*
|
|
18
|
+
* The download retries a transient failure (HTTP 408/429/5xx, network error,
|
|
19
|
+
* request timeout) up to DOWNLOAD_ATTEMPTS times, sleeping DOWNLOAD_BACKOFF_MS
|
|
20
|
+
* between attempts (#6095). The attempt count and the DOWNLOAD_BACKOFF_MS
|
|
21
|
+
* sleeps are bounded; total wall time is not bounded by this module, because
|
|
22
|
+
* DOWNLOAD_TIMEOUT_MS is a per-hop socket idle timeout (a body that keeps
|
|
23
|
+
* trickling bytes never trips it). The CI job's timeout-minutes is the outer
|
|
24
|
+
* bound. A non-transient failure (404, too many redirects) fails at once.
|
|
25
|
+
*
|
|
18
26
|
* Zip-slip defense: unlike `decompress`, which wrote extracted files using
|
|
19
27
|
* PATHS TAKEN FROM THE ARCHIVE (the exact defect class in GHSA-mp2f-45pm-
|
|
20
28
|
* 3cg9 — a malicious archive entry named e.g. `../../etc/passwd` gets
|
|
@@ -62,9 +70,18 @@ const MAX_REDIRECTS = 5;
|
|
|
62
70
|
// SHELLCHECK_TIMEOUT_MS bound on the ShellCheck subprocess. A bare `timeout`
|
|
63
71
|
// option on the request does NOT abort it by itself — Node only emits a
|
|
64
72
|
// 'timeout' event, which must be handled by destroying the request (see the
|
|
65
|
-
// `req.on('timeout', ...)` below).
|
|
73
|
+
// `req.on('timeout', ...)` below). This is a per-hop IDLE timeout (socket
|
|
74
|
+
// inactivity): a stalled hop fails after it, but a body that keeps trickling
|
|
75
|
+
// bytes never trips it. downloadWithRetry bounds the attempt count and the
|
|
76
|
+
// DOWNLOAD_BACKOFF_MS sleeps; total wall time is not bounded by this module
|
|
77
|
+
// (the CI job's timeout-minutes is the outer bound).
|
|
66
78
|
const DOWNLOAD_TIMEOUT_MS = 30_000;
|
|
67
79
|
|
|
80
|
+
// Total download attempts and the sleeps (ms) between them: a sleep of
|
|
81
|
+
// DOWNLOAD_BACKOFF_MS[i] follows failed attempt i + 1 (#6095).
|
|
82
|
+
const DOWNLOAD_ATTEMPTS = 3;
|
|
83
|
+
const DOWNLOAD_BACKOFF_MS = [2000, 5000];
|
|
84
|
+
|
|
68
85
|
/**
|
|
69
86
|
* Issue one real HTTPS request. Exists as its own function purely so tests
|
|
70
87
|
* can inject a fake in its place (see `httpsGetFollowingRedirects`'s
|
|
@@ -95,7 +112,9 @@ function httpsGetFollowingRedirects(url, redirectsLeft = MAX_REDIRECTS, requestF
|
|
|
95
112
|
if (status >= 300 && status < 400 && res.headers.location) {
|
|
96
113
|
res.resume(); // drain so the socket can be reused/closed
|
|
97
114
|
if (redirectsLeft <= 0) {
|
|
98
|
-
|
|
115
|
+
const err = new Error(`too many redirects fetching ${url}`);
|
|
116
|
+
err.code = 'TOO_MANY_REDIRECTS';
|
|
117
|
+
reject(err);
|
|
99
118
|
return;
|
|
100
119
|
}
|
|
101
120
|
const next = new URL(res.headers.location, url).toString();
|
|
@@ -104,7 +123,9 @@ function httpsGetFollowingRedirects(url, redirectsLeft = MAX_REDIRECTS, requestF
|
|
|
104
123
|
}
|
|
105
124
|
if (status !== 200) {
|
|
106
125
|
res.resume();
|
|
107
|
-
|
|
126
|
+
const err = new Error(`unexpected HTTP ${status} fetching ${url}`);
|
|
127
|
+
err.status = status;
|
|
128
|
+
reject(err);
|
|
108
129
|
return;
|
|
109
130
|
}
|
|
110
131
|
const chunks = [];
|
|
@@ -124,6 +145,48 @@ function httpsGetFollowingRedirects(url, redirectsLeft = MAX_REDIRECTS, requestF
|
|
|
124
145
|
});
|
|
125
146
|
}
|
|
126
147
|
|
|
148
|
+
/**
|
|
149
|
+
* True when a download failure is worth retrying: HTTP 408, 429 or 5xx, or an
|
|
150
|
+
* error with no HTTP status (network error, request timeout, socket reset).
|
|
151
|
+
* False for any other status (e.g. 404, a wrong pinned asset) and for
|
|
152
|
+
* `too many redirects`, which is deterministic.
|
|
153
|
+
*/
|
|
154
|
+
function isTransientDownloadError(err) {
|
|
155
|
+
const status = err && err.status;
|
|
156
|
+
if (typeof status === 'number') {
|
|
157
|
+
return status === 408 || status === 429 || (status >= 500 && status <= 599);
|
|
158
|
+
}
|
|
159
|
+
return !(err && err.code === 'TOO_MANY_REDIRECTS');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* GET `url` via `getFn`, retrying a transient failure up to `attempts` times
|
|
164
|
+
* with `backoffMs[i]` sleeps between attempts. A non-transient error rejects
|
|
165
|
+
* at once; exhausting the attempts rejects with one Error listing every
|
|
166
|
+
* attempt. `sleep` and `getFn` are injectable so tests never wait.
|
|
167
|
+
*/
|
|
168
|
+
async function downloadWithRetry(
|
|
169
|
+
url,
|
|
170
|
+
{
|
|
171
|
+
attempts = DOWNLOAD_ATTEMPTS,
|
|
172
|
+
backoffMs = DOWNLOAD_BACKOFF_MS,
|
|
173
|
+
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
174
|
+
getFn = httpsGetFollowingRedirects,
|
|
175
|
+
} = {},
|
|
176
|
+
) {
|
|
177
|
+
const failures = [];
|
|
178
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
179
|
+
try {
|
|
180
|
+
return await getFn(url);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
if (!isTransientDownloadError(e)) throw e;
|
|
183
|
+
failures.push(`attempt ${attempt}: ${e.message}`);
|
|
184
|
+
if (attempt < attempts) await sleep(backoffMs[Math.min(attempt - 1, backoffMs.length - 1)]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
throw new Error(failures.join('; '));
|
|
188
|
+
}
|
|
189
|
+
|
|
127
190
|
/**
|
|
128
191
|
* Find the entry named (or path-ending-in) `targetName` inside a raw
|
|
129
192
|
* (already gunzipped) POSIX tar byte stream and return its content as a
|
|
@@ -204,7 +267,7 @@ async function resolveShellcheckBin() {
|
|
|
204
267
|
|
|
205
268
|
let gz;
|
|
206
269
|
try {
|
|
207
|
-
gz = await
|
|
270
|
+
gz = await downloadWithRetry(url);
|
|
208
271
|
} catch (e) {
|
|
209
272
|
throw new ExitError(1, `lint-workflow-shellcheck: failed to download ShellCheck (${url}): ${e.message}`);
|
|
210
273
|
}
|
|
@@ -241,7 +304,11 @@ module.exports = {
|
|
|
241
304
|
CACHED_BIN_PATH,
|
|
242
305
|
MAX_REDIRECTS,
|
|
243
306
|
DOWNLOAD_TIMEOUT_MS,
|
|
307
|
+
DOWNLOAD_ATTEMPTS,
|
|
308
|
+
DOWNLOAD_BACKOFF_MS,
|
|
244
309
|
extractFileFromTar,
|
|
245
310
|
httpsGetFollowingRedirects,
|
|
311
|
+
isTransientDownloadError,
|
|
312
|
+
downloadWithRetry,
|
|
246
313
|
resolveShellcheckBin,
|
|
247
314
|
};
|