@opengsd/gsd-core 1.5.0-rc.4 → 1.5.0-rc.5
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/plugin.json +1 -1
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-planner.md +4 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-verifier.md +45 -13
- package/bin/install.js +3 -1
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +49 -48
- package/gsd-core/bin/lib/agent-command-router.cjs +2 -2
- package/gsd-core/bin/lib/agent-install-check.cjs +143 -0
- package/gsd-core/bin/lib/audit-command-router.cjs +4 -4
- package/gsd-core/bin/lib/capability-activation.cjs +37 -10
- package/gsd-core/bin/lib/capability-registry.cjs +2 -0
- package/gsd-core/bin/lib/capability-state.cjs +80 -30
- package/gsd-core/bin/lib/capability-writer.cjs +5 -4
- package/gsd-core/bin/lib/check-command-router.cjs +50 -51
- package/gsd-core/bin/lib/commands.cjs +20 -2
- package/gsd-core/bin/lib/config-loader.cjs +3 -4
- package/gsd-core/bin/lib/config-schema.cjs +1 -1
- package/gsd-core/bin/lib/config-types.cjs +2 -1
- package/gsd-core/bin/lib/config.cjs +5 -2
- package/gsd-core/bin/lib/docs.cjs +14 -2
- package/gsd-core/bin/lib/frontmatter.cjs +2 -2
- package/gsd-core/bin/lib/gap-checker.cjs +5 -2
- package/gsd-core/bin/lib/git-base-branch.cjs +27 -1
- package/gsd-core/bin/lib/graphify-command-router.cjs +6 -8
- package/gsd-core/bin/lib/graphify.cjs +7 -31
- package/gsd-core/bin/lib/gsd2-import.cjs +2 -2
- package/gsd-core/bin/lib/init.cjs +30 -4
- package/gsd-core/bin/lib/intel-command-router.cjs +6 -3
- package/gsd-core/bin/lib/intel.cjs +28 -34
- package/gsd-core/bin/lib/io.cjs +2 -4
- package/gsd-core/bin/lib/learnings.cjs +2 -2
- package/gsd-core/bin/lib/loop-resolver.cjs +45 -167
- package/gsd-core/bin/lib/milestone.cjs +13 -5
- package/gsd-core/bin/lib/model-resolver.cjs +3 -4
- package/gsd-core/bin/lib/phase-id.cjs +2 -4
- package/gsd-core/bin/lib/phase-locator.cjs +3 -6
- package/gsd-core/bin/lib/phase.cjs +18 -7
- package/gsd-core/bin/lib/probe-core.cjs +33 -11
- package/gsd-core/bin/lib/profile-output.cjs +5 -2
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +485 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-parser.cjs +3 -5
- package/gsd-core/bin/lib/roadmap.cjs +9 -4
- package/gsd-core/bin/lib/state.cjs +11 -2
- package/gsd-core/bin/lib/task-command-router.cjs +2 -2
- package/gsd-core/bin/lib/template.cjs +11 -2
- package/gsd-core/bin/lib/uat.cjs +8 -2
- package/gsd-core/bin/lib/verification.cjs +8 -5
- package/gsd-core/bin/lib/verify.cjs +311 -4
- package/gsd-core/bin/lib/workstream-inventory.cjs +2 -2
- package/gsd-core/bin/lib/workstream.cjs +8 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +37 -2
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/references/planner-antipatterns.md +46 -0
- package/gsd-core/references/planning-config.md +5 -1
- package/gsd-core/references/prohibition-probe.md +51 -2
- package/gsd-core/templates/verification-report.md +16 -3
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +9 -0
- package/gsd-core/workflows/execute-phase.md +5 -1
- package/gsd-core/workflows/quick.md +3 -0
- package/gsd-core/workflows/settings-advanced.md +5 -5
- package/gsd-core/workflows/settings-integrations.md +5 -5
- package/gsd-core/workflows/spec-phase.md +25 -2
- package/gsd-core/workflows/verify-phase.md +22 -7
- package/package.json +2 -2
- package/scripts/gen-capability-registry.cjs +27 -1
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
- package/scripts/research-profiles.cjs +2 -2
- package/gsd-core/bin/lib/core.cjs +0 -345
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-core",
|
|
3
3
|
"displayName": "GSD Core",
|
|
4
|
-
"version": "1.5.0-rc.
|
|
4
|
+
"version": "1.5.0-rc.5",
|
|
5
5
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "open-gsd",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsd-phase-researcher
|
|
3
3
|
description: Researches how to implement a phase before planning. Produces RESEARCH.md consumed by gsd-planner. Spawned by /gsd:plan-phase orchestrator.
|
|
4
|
-
tools: Read, Write, Edit, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__*, mcp__firecrawl__*, mcp__exa__*, mcp__tavily__*, mcp__ref__*, mcp__jina__*
|
|
4
|
+
tools: Read, Write, Edit, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__*, mcp__firecrawl__*, mcp__exa__*, mcp__tavily__*, mcp__ref__*, mcp__jina__*, mcp__perplexity__*
|
|
5
5
|
color: cyan
|
|
6
6
|
# hooks:
|
|
7
7
|
# PostToolUse:
|
package/agents/gsd-planner.md
CHANGED
|
@@ -198,6 +198,10 @@ Every task has four required fields:
|
|
|
198
198
|
Full rules + worked examples: @gsd-core/references/planner-antipatterns.md ("Comment-Text Discipline").
|
|
199
199
|
</comment_text_discipline>
|
|
200
200
|
|
|
201
|
+
<region_scoped_negative_gate>
|
|
202
|
+
**Region-scoped negative gates (WARN, #968):** Region-scope a file-wide negative grep when a sibling task needs that construct elsewhere in the same file; `validate_plan` WARNS. See: @gsd-core/references/planner-antipatterns.md ("Region-Scoped Negative Gates").
|
|
203
|
+
</region_scoped_negative_gate>
|
|
204
|
+
|
|
201
205
|
**<done>:** Acceptance criteria - measurable state of completion.
|
|
202
206
|
- Good: "Valid credentials return 200 + JWT cookie, invalid credentials return 401"
|
|
203
207
|
- Bad: "Authentication is complete"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsd-project-researcher
|
|
3
3
|
description: Researches domain ecosystem before roadmap creation. Produces files in .planning/research/ consumed during roadmap creation. Spawned by /gsd:new-project or /gsd:new-milestone orchestrators.
|
|
4
|
-
tools: Read, Write, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__*, mcp__firecrawl__*, mcp__exa__*, mcp__tavily__*, mcp__ref__*, mcp__jina__*
|
|
4
|
+
tools: Read, Write, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__*, mcp__firecrawl__*, mcp__exa__*, mcp__tavily__*, mcp__ref__*, mcp__jina__*, mcp__perplexity__*
|
|
5
5
|
color: cyan
|
|
6
6
|
# hooks:
|
|
7
7
|
# PostToolUse:
|
package/agents/gsd-verifier.md
CHANGED
|
@@ -180,21 +180,28 @@ For each truth, determine if codebase enables it.
|
|
|
180
180
|
|
|
181
181
|
**Verification status:**
|
|
182
182
|
|
|
183
|
-
- ✓ VERIFIED: All supporting artifacts pass all checks
|
|
183
|
+
- ✓ VERIFIED: All supporting artifacts pass all checks — and, for a behavior-dependent truth, a behavioral test exercises the asserted behavior (see below)
|
|
184
|
+
- ⚠️ PRESENT_BEHAVIOR_UNVERIFIED: Supporting artifacts are present and wired, but the truth asserts runtime behavior that no test exercises — present, not behaviorally proven. Routes to human verification (Step 8) and does NOT count toward the verified score (Step 9).
|
|
184
185
|
- ✗ FAILED: One or more artifacts missing, stub, or unwired
|
|
185
186
|
- ? UNCERTAIN: Can't verify programmatically (needs human)
|
|
186
187
|
|
|
188
|
+
**Behavior-dependent truths.** A truth is *behavior-dependent* when its correctness hinges on runtime behavior grep/presence checks cannot see — a **state transition** or a **cancellation / cleanup / ordering invariant** (e.g. "cancels the in-flight task and bumps the generation counter", "resets the busy flag on abort", "rolls back on failure"). For these, symbol presence + wiring is *necessary but not sufficient*: the code can be present and wired yet still leak state on the very path the invariant covers.
|
|
189
|
+
|
|
187
190
|
For each truth:
|
|
188
191
|
|
|
189
192
|
1. Identify supporting artifacts
|
|
190
193
|
2. Check artifact status (Step 4)
|
|
191
194
|
3. Check wiring status (Step 5)
|
|
192
|
-
4. **Before marking FAIL:** Check for override (Step 3b)
|
|
193
|
-
5.
|
|
195
|
+
4. **Before marking FAIL or PRESENT_BEHAVIOR_UNVERIFIED:** Check for override (Step 3b)
|
|
196
|
+
5. **Classify behavior-dependence.** If the truth asserts a state transition or a cancellation/cleanup/ordering invariant, its status cannot be VERIFIED on presence alone:
|
|
197
|
+
- A pre-existing test exercises the transition/invariant and passes (confirm via Step 7b's single-named-test path) → ✓ VERIFIED.
|
|
198
|
+
- No such test exists, or it can't run without a server/state mutation → ⚠️ PRESENT_BEHAVIOR_UNVERIFIED. Emit a human-verification item (Step 8) and do not count it toward the verified score (Step 9).
|
|
199
|
+
- An accepted override (Step 3b) carries the truth as PASSED (override), exactly as it does for a FAILED truth.
|
|
200
|
+
6. Determine truth status
|
|
194
201
|
|
|
195
202
|
## Step 3b: Check Verification Overrides
|
|
196
203
|
|
|
197
|
-
Before marking any must-have as FAILED, check the VERIFICATION.md frontmatter for an `overrides:` entry that matches this must-have.
|
|
204
|
+
Before marking any must-have as FAILED or ⚠️ PRESENT_BEHAVIOR_UNVERIFIED, check the VERIFICATION.md frontmatter for an `overrides:` entry that matches this must-have.
|
|
198
205
|
|
|
199
206
|
**Override check procedure:**
|
|
200
207
|
|
|
@@ -204,12 +211,12 @@ Before marking any must-have as FAILED, check the VERIFICATION.md frontmatter fo
|
|
|
204
211
|
4. Key technical terms (file paths, component names, API endpoints) have higher weight
|
|
205
212
|
|
|
206
213
|
**If override found:**
|
|
207
|
-
- Mark as `PASSED (override)` instead of FAIL
|
|
214
|
+
- Mark as `PASSED (override)` instead of FAIL/PRESENT_BEHAVIOR_UNVERIFIED
|
|
208
215
|
- Evidence: `Override: {reason} — accepted by {accepted_by} on {accepted_at}`
|
|
209
|
-
- Count toward passing score, not failing score
|
|
216
|
+
- Count toward passing score (`verified_truths`), not failing score
|
|
210
217
|
|
|
211
218
|
**If no override found:**
|
|
212
|
-
- Mark as FAILED as normal
|
|
219
|
+
- Mark as FAILED (or ⚠️ PRESENT_BEHAVIOR_UNVERIFIED, per Step 3 step 5) as normal
|
|
213
220
|
- Consider suggesting an override if the failure looks intentional (alternative implementation exists)
|
|
214
221
|
|
|
215
222
|
**Suggesting overrides:** When a must-have FAILs but evidence shows an alternative implementation that achieves the same intent, include an override suggestion in the report:
|
|
@@ -461,6 +468,8 @@ Anti-pattern scanning (Step 7) checks for code smells. Behavioral spot-checks go
|
|
|
461
468
|
|
|
462
469
|
**When to run:** For phases that produce runnable code (APIs, CLI tools, build scripts, data pipelines). Skip for documentation-only or config-only phases.
|
|
463
470
|
|
|
471
|
+
**Behavioral evidence for behavior-dependent truths (Step 3).** When a truth asserts a state transition or a cancellation/cleanup/ordering invariant, the single named test below is what upgrades it from ⚠️ PRESENT_BEHAVIOR_UNVERIFIED to ✓ VERIFIED. Run only the one named test that exercises the transition/invariant — never the full suite (per #25/#753). If no such test exists, leave the truth ⚠️ PRESENT_BEHAVIOR_UNVERIFIED and route it to human verification (Step 8); do not mark it VERIFIED on presence.
|
|
472
|
+
|
|
464
473
|
**How:**
|
|
465
474
|
|
|
466
475
|
1. **Identify checkable behaviors** from must-haves truths. Select 2-4 that can be tested with a single command:
|
|
@@ -548,6 +557,8 @@ done
|
|
|
548
557
|
|
|
549
558
|
**Needs human if uncertain:** Complex wiring grep can't trace, dynamic state behavior, edge cases.
|
|
550
559
|
|
|
560
|
+
**Behavior-unverified truths (Step 3):** Every truth left ⚠️ PRESENT_BEHAVIOR_UNVERIFIED is recorded in the `behavior_unverified_items` frontmatter list (emitted whenever the count > 0, regardless of overall status, so it survives a gaps_found phase) and surfaces for human verification; when the overall status is human_needed it also appears in the human_verification section. Phrase each item around the invariant: what to trigger, what state must hold afterward, and why presence checks can't see it.
|
|
561
|
+
|
|
551
562
|
**Harvest deferred items from PLAN.md (#3309 / `workflow.human_verify_mode = end-of-phase`):** Scan every PLAN file in the phase for `<verify><human-check>` blocks on `auto` tasks. These are verification items the planner deliberately deferred from `checkpoint:human-verify` to end-of-phase to avoid the executor cold-start cost. Each block has the same shape used by the planner:
|
|
552
563
|
|
|
553
564
|
```xml
|
|
@@ -579,18 +590,30 @@ Classify status using this decision tree IN ORDER (most restrictive first):
|
|
|
579
590
|
1. IF any truth FAILED, artifact MISSING/STUB, key link NOT_WIRED, or blocker anti-pattern found:
|
|
580
591
|
→ **status: gaps_found**
|
|
581
592
|
|
|
582
|
-
2. IF Step 8 produced ANY human verification items (section is non-empty):
|
|
593
|
+
2. IF Step 8 produced ANY human verification items (section is non-empty) — this includes every ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truth from Step 3:
|
|
583
594
|
→ **status: human_needed**
|
|
584
|
-
(Even if all truths are VERIFIED
|
|
595
|
+
(Even if all other truths are VERIFIED — human items take priority)
|
|
585
596
|
|
|
586
597
|
3. IF all truths VERIFIED, all artifacts pass, all links WIRED, no blockers, AND no human verification items:
|
|
587
598
|
→ **status: passed**
|
|
588
599
|
|
|
589
|
-
**passed is ONLY valid when the human verification section is empty.** If
|
|
600
|
+
**passed is ONLY valid when the human verification section is empty.** If Step 8 produced any items — including any truth left ⚠️ PRESENT_BEHAVIOR_UNVERIFIED — the status is not `passed`: it is `human_needed`, or `gaps_found` when rule 1 also fires (the ordered tree keeps gaps_found's precedence).
|
|
601
|
+
|
|
602
|
+
**A ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truth is never FAILED and never VERIFIED.** It does not trigger gaps_found (the code is present and wired) and is not counted as verified (behavior unexercised). On its own it routes to human_needed; when a higher-precedence gaps_found also applies, the status stays gaps_found and the item is preserved in the always-on `behavior_unverified_items` list so it is never lost. Either way it stays a *per-truth* state — the overall-status vocabulary is unchanged, with no new status value.
|
|
590
603
|
|
|
591
604
|
> **Shared status seam**: the status vocabulary (`passed`, `gaps_found`, `human_needed`) and the per-status routing (next action and next command for each value) are owned by `src/verification.cts` via `gsd_run query verification.status`. This agent is the single emitter of the frontmatter status field; consumers (ship.md, execute-phase.md) read routing from that query instead of re-deriving it.
|
|
592
605
|
|
|
593
|
-
**Score
|
|
606
|
+
**Score (presence- vs behavior-verified split):**
|
|
607
|
+
|
|
608
|
+
- `verified_truths` counts ✓ VERIFIED truths plus PASSED (override) truths (Step 3b). For a behavior-dependent truth, VERIFIED means a behavioral test passed, not just that symbols are present.
|
|
609
|
+
- ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truths are the *only* ones excluded from `verified_truths`; they are reported separately as `behavior_unverified`.
|
|
610
|
+
|
|
611
|
+
```text
|
|
612
|
+
score: verified_truths / total_truths # e.g. 6/7
|
|
613
|
+
behavior_unverified: P # truths present + wired but behavior not exercised
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
A headline N/N therefore certifies that every behavior-dependent truth had behavioral evidence — a clean score can no longer be reached on symbol presence alone.
|
|
594
617
|
|
|
595
618
|
## Step 9b: Filter Deferred Items
|
|
596
619
|
|
|
@@ -699,6 +722,7 @@ phase: XX-name
|
|
|
699
722
|
verified: YYYY-MM-DDTHH:MM:SSZ
|
|
700
723
|
status: passed | gaps_found | human_needed
|
|
701
724
|
score: N/M must-haves verified
|
|
725
|
+
behavior_unverified: 0 # Count of ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truths (present + wired, behavior not exercised); each is detailed in behavior_unverified_items below (and in human_verification when status is human_needed)
|
|
702
726
|
overrides_applied: 0 # Count of PASSED (override) items included in score
|
|
703
727
|
overrides: # Only if overrides exist — carried forward or newly added
|
|
704
728
|
- must_have: "Must-have text that was overridden"
|
|
@@ -725,6 +749,11 @@ deferred: # Only if deferred items exist (Step 9b)
|
|
|
725
749
|
- truth: "Observable truth addressed in a later phase"
|
|
726
750
|
addressed_in: "Phase N"
|
|
727
751
|
evidence: "Matching goal or success criteria text"
|
|
752
|
+
behavior_unverified_items: # Only if behavior_unverified > 0 — emitted regardless of overall status, so these survive a gaps_found phase
|
|
753
|
+
- truth: "Observable truth whose state transition or cancellation/cleanup/ordering invariant no test exercises"
|
|
754
|
+
test: "What to trigger"
|
|
755
|
+
expected: "What state must hold afterward"
|
|
756
|
+
why_human: "Why presence checks can't see it"
|
|
728
757
|
human_verification: # Only if status: human_needed
|
|
729
758
|
- test: "What to do"
|
|
730
759
|
expected: "What should happen"
|
|
@@ -746,8 +775,9 @@ human_verification: # Only if status: human_needed
|
|
|
746
775
|
| --- | ------- | ---------- | -------------- |
|
|
747
776
|
| 1 | {truth} | ✓ VERIFIED | {evidence} |
|
|
748
777
|
| 2 | {truth} | ✗ FAILED | {what's wrong} |
|
|
778
|
+
| 3 | {truth} | ⚠️ PRESENT_BEHAVIOR_UNVERIFIED | {present + wired; no test exercises the transition/invariant — see Human Verification} |
|
|
749
779
|
|
|
750
|
-
**Score:** {N}/{M} truths verified
|
|
780
|
+
**Score:** {N}/{M} truths verified ({P} present, behavior-unverified)
|
|
751
781
|
|
|
752
782
|
### Deferred Items
|
|
753
783
|
|
|
@@ -834,7 +864,7 @@ Structured gaps in VERIFICATION.md frontmatter for `/gsd:plan-phase --gaps`.
|
|
|
834
864
|
|
|
835
865
|
{If human_needed:}
|
|
836
866
|
### Human Verification Required
|
|
837
|
-
{N} items need human testing:
|
|
867
|
+
{N} items need human testing (including {P} present-but-behavior-unverified truths — code wired, transition/invariant not exercised by a test):
|
|
838
868
|
1. **{Test name}** — {what to do}
|
|
839
869
|
- Expected: {what should happen}
|
|
840
870
|
|
|
@@ -857,6 +887,8 @@ Automated checks passed. Awaiting human verification.
|
|
|
857
887
|
|
|
858
888
|
**Keep verification fast.** Use grep/file checks, not running the app.
|
|
859
889
|
|
|
890
|
+
**Presence is not behavior.** Grep/file checks prove a symbol is present and wired — they do not prove a state transition or a cancellation/cleanup/ordering invariant holds at runtime. For a behavior-dependent truth, require a passing behavioral test (Step 7b's single named test) or mark it ⚠️ PRESENT_BEHAVIOR_UNVERIFIED and route to human verification. Never let symbol presence alone produce a VERIFIED on a behavior-dependent truth.
|
|
891
|
+
|
|
860
892
|
**DO NOT commit.** Leave committing to the orchestrator.
|
|
861
893
|
|
|
862
894
|
</critical_rules>
|
package/bin/install.js
CHANGED
|
@@ -265,9 +265,11 @@ const _gsdLibDir = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
|
|
265
265
|
const { MODEL_PROFILES: GSD_MODEL_PROFILES } = require(path.join(_gsdLibDir, 'model-profiles.cjs'));
|
|
266
266
|
const {
|
|
267
267
|
RUNTIME_PROFILE_MAP: GSD_RUNTIME_PROFILE_MAP,
|
|
268
|
+
} = require(path.join(_gsdLibDir, 'model-catalog.cjs'));
|
|
269
|
+
const {
|
|
268
270
|
resolveTierEntry: gsdResolveTierEntry,
|
|
269
271
|
EFFORT_SET: GSD_EFFORT_SET,
|
|
270
|
-
} = require(path.join(_gsdLibDir, '
|
|
272
|
+
} = require(path.join(_gsdLibDir, 'model-resolver.cjs'));
|
|
271
273
|
|
|
272
274
|
// #443 — model-catalog and config-defaults.manifest.json exports needed only
|
|
273
275
|
// by effort-resolution code paths (resolveInstallTimeEffort /
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-core",
|
|
3
|
-
"version": "1.5.0-rc.
|
|
3
|
+
"version": "1.5.0-rc.5",
|
|
4
4
|
"description": "GSD Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads gsd's operating context into every Gemini CLI session.",
|
|
5
5
|
"contextFileName": "GEMINI.md"
|
|
6
6
|
}
|
|
@@ -194,13 +194,14 @@
|
|
|
194
194
|
const fs = require('fs');
|
|
195
195
|
const path = require('path');
|
|
196
196
|
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
|
|
197
|
-
const
|
|
198
|
-
const { error, ERROR_REASON } =
|
|
197
|
+
const io = require('./lib/io.cjs');
|
|
198
|
+
const { error, ERROR_REASON, setJsonErrorMode, output } = io;
|
|
199
|
+
const projectRoot = require('./lib/project-root.cjs');
|
|
199
200
|
// Resolve findProjectRoot lazily at call time rather than binding it at module
|
|
200
|
-
// load. It is
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
const findProjectRoot = (...args) =>
|
|
201
|
+
// load. It is sourced from project-root.cjs; a call-time lookup is robust
|
|
202
|
+
// against any require/load-ordering edge where the export isn't bound yet
|
|
203
|
+
// when this entrypoint is first required (#604).
|
|
204
|
+
const findProjectRoot = (...args) => projectRoot.findProjectRoot(...args);
|
|
204
205
|
const { getActiveWorkstream } = require('./lib/planning-workspace.cjs');
|
|
205
206
|
const { resolveActiveWorkstream, applyResolvedWorkstreamEnv } = require('./lib/active-workstream-store.cjs');
|
|
206
207
|
const state = require('./lib/state.cjs');
|
|
@@ -255,7 +256,7 @@ const { getEffectiveAuthority, classifyDriftSeverity } = require('./lib/plan-dri
|
|
|
255
256
|
* @param {string} opts.cwd - project dir
|
|
256
257
|
* @param {boolean} opts.raw - raw output mode
|
|
257
258
|
* @param {Function} opts.error - error reporter
|
|
258
|
-
* @param {Function} opts.output - output emitter (
|
|
259
|
+
* @param {Function} opts.output - output emitter (output)
|
|
259
260
|
*/
|
|
260
261
|
function _dispatchNonFamily({ registryCommand, registryArgs, legacyCommand, legacyArgs, cwd, raw, error, output }) {
|
|
261
262
|
void registryCommand;
|
|
@@ -294,7 +295,7 @@ function _dispatchNonFamily({ registryCommand, registryArgs, legacyCommand, lega
|
|
|
294
295
|
* @param {string[]} opts.args Remaining args passed to the router
|
|
295
296
|
* @param {string} opts.cwd Project working directory
|
|
296
297
|
* @param {boolean} opts.raw Raw output mode flag
|
|
297
|
-
* @param {Function} opts.error Error reporter (
|
|
298
|
+
* @param {Function} opts.error Error reporter (io.error)
|
|
298
299
|
* @param {object} [opts.registry] Injectable registry (for tests)
|
|
299
300
|
* @param {Function} [opts.requireModule] Injectable module loader (for tests)
|
|
300
301
|
* @returns {boolean} true if the command was dispatched, false otherwise
|
|
@@ -404,10 +405,10 @@ async function main() {
|
|
|
404
405
|
// their plain-text diagnostic.
|
|
405
406
|
const jsonErrorsIdx = args.indexOf('--json-errors');
|
|
406
407
|
if (jsonErrorsIdx !== -1) {
|
|
407
|
-
|
|
408
|
+
setJsonErrorMode(true);
|
|
408
409
|
args.splice(jsonErrorsIdx, 1);
|
|
409
410
|
} else if (process.env.GSD_JSON_ERRORS === '1') {
|
|
410
|
-
|
|
411
|
+
setJsonErrorMode(true);
|
|
411
412
|
}
|
|
412
413
|
|
|
413
414
|
// Optional cwd override for sandboxed subagents running outside project root.
|
|
@@ -433,7 +434,7 @@ async function main() {
|
|
|
433
434
|
// Resolve worktree root: in a linked worktree, .planning/ lives in the main worktree.
|
|
434
435
|
// However, in monorepo worktrees where the subdirectory itself owns .planning/,
|
|
435
436
|
// skip worktree resolution — the CWD is already the correct project root.
|
|
436
|
-
const { resolveWorktreeRoot } = require('./lib/
|
|
437
|
+
const { resolveWorktreeRoot } = require('./lib/worktree-safety.cjs');
|
|
437
438
|
if (!fs.existsSync(path.join(cwd, '.planning'))) {
|
|
438
439
|
const worktreeRoot = resolveWorktreeRoot(cwd);
|
|
439
440
|
if (worktreeRoot !== cwd) {
|
|
@@ -596,7 +597,7 @@ async function main() {
|
|
|
596
597
|
}
|
|
597
598
|
|
|
598
599
|
// Intercept stdout to transparently resolve @file: references (#1891).
|
|
599
|
-
//
|
|
600
|
+
// io.cjs output() writes @file:<path> when JSON > 50KB. The --pick path
|
|
600
601
|
// already resolves this, but the normal path wrote @file: to stdout, forcing
|
|
601
602
|
// every workflow to have a bash-specific `if [[ "$INIT" == @file:* ]]` check
|
|
602
603
|
// that breaks on PowerShell and other non-bash shells.
|
|
@@ -802,7 +803,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
802
803
|
cwd,
|
|
803
804
|
raw,
|
|
804
805
|
error,
|
|
805
|
-
output:
|
|
806
|
+
output: output,
|
|
806
807
|
});
|
|
807
808
|
if (!handled) phase.cmdFindPhase(cwd, args[1], raw);
|
|
808
809
|
break;
|
|
@@ -895,7 +896,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
895
896
|
cwd,
|
|
896
897
|
raw,
|
|
897
898
|
error,
|
|
898
|
-
output:
|
|
899
|
+
output: output,
|
|
899
900
|
});
|
|
900
901
|
if (handled) break;
|
|
901
902
|
}
|
|
@@ -957,7 +958,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
957
958
|
cwd,
|
|
958
959
|
raw,
|
|
959
960
|
error,
|
|
960
|
-
output:
|
|
961
|
+
output: output,
|
|
961
962
|
});
|
|
962
963
|
if (!handled) commands.cmdGenerateSlug(args[1], raw);
|
|
963
964
|
break;
|
|
@@ -997,7 +998,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
997
998
|
cwd,
|
|
998
999
|
raw,
|
|
999
1000
|
error,
|
|
1000
|
-
output:
|
|
1001
|
+
output: output,
|
|
1001
1002
|
});
|
|
1002
1003
|
if (!handled) config.cmdConfigEnsureSection(cwd, raw);
|
|
1003
1004
|
break;
|
|
@@ -1013,7 +1014,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1013
1014
|
cwd,
|
|
1014
1015
|
raw,
|
|
1015
1016
|
error,
|
|
1016
|
-
output:
|
|
1017
|
+
output: output,
|
|
1017
1018
|
});
|
|
1018
1019
|
if (!handled) config.cmdConfigSet(cwd, args[1], args[2], raw);
|
|
1019
1020
|
break;
|
|
@@ -1029,7 +1030,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1029
1030
|
cwd,
|
|
1030
1031
|
raw,
|
|
1031
1032
|
error,
|
|
1032
|
-
output:
|
|
1033
|
+
output: output,
|
|
1033
1034
|
});
|
|
1034
1035
|
if (!handled) config.cmdConfigSetModelProfile(cwd, args[1], raw);
|
|
1035
1036
|
break;
|
|
@@ -1054,7 +1055,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1054
1055
|
cwd,
|
|
1055
1056
|
raw,
|
|
1056
1057
|
error,
|
|
1057
|
-
output:
|
|
1058
|
+
output: output,
|
|
1058
1059
|
});
|
|
1059
1060
|
if (!handled) config.cmdConfigGet(cwd, args[1], raw, defaultValue);
|
|
1060
1061
|
break;
|
|
@@ -1070,7 +1071,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1070
1071
|
cwd,
|
|
1071
1072
|
raw,
|
|
1072
1073
|
error,
|
|
1073
|
-
output:
|
|
1074
|
+
output: output,
|
|
1074
1075
|
});
|
|
1075
1076
|
if (!handled) config.cmdConfigNewProject(cwd, args[1], raw);
|
|
1076
1077
|
break;
|
|
@@ -1183,7 +1184,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1183
1184
|
args,
|
|
1184
1185
|
cwd,
|
|
1185
1186
|
raw,
|
|
1186
|
-
output:
|
|
1187
|
+
output: output,
|
|
1187
1188
|
error,
|
|
1188
1189
|
});
|
|
1189
1190
|
break;
|
|
@@ -1255,12 +1256,12 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1255
1256
|
const configDirIdx = args.indexOf('--config-dir');
|
|
1256
1257
|
if (configDirEqArg) {
|
|
1257
1258
|
const value = configDirEqArg.slice('--config-dir='.length).trim();
|
|
1258
|
-
if (!value) error('Missing value for --config-dir',
|
|
1259
|
+
if (!value) error('Missing value for --config-dir', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1259
1260
|
loopConfigDir = value;
|
|
1260
1261
|
} else if (configDirIdx !== -1) {
|
|
1261
1262
|
const value = args[configDirIdx + 1];
|
|
1262
1263
|
if (!value || value.startsWith('--')) {
|
|
1263
|
-
error('Missing value for --config-dir',
|
|
1264
|
+
error('Missing value for --config-dir', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1264
1265
|
}
|
|
1265
1266
|
loopConfigDir = value;
|
|
1266
1267
|
}
|
|
@@ -1270,12 +1271,12 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1270
1271
|
const activeCapIdx = args.indexOf('--active-cap');
|
|
1271
1272
|
if (activeCapEqArg) {
|
|
1272
1273
|
const value = activeCapEqArg.slice('--active-cap='.length).trim();
|
|
1273
|
-
if (!value) error('Missing value for --active-cap (e.g. --active-cap tdd)',
|
|
1274
|
+
if (!value) error('Missing value for --active-cap (e.g. --active-cap tdd)', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1274
1275
|
loopActiveCap = value;
|
|
1275
1276
|
} else if (activeCapIdx !== -1) {
|
|
1276
1277
|
const value = args[activeCapIdx + 1];
|
|
1277
1278
|
if (!value || value.startsWith('--')) {
|
|
1278
|
-
error('Missing value for --active-cap (e.g. --active-cap tdd)',
|
|
1279
|
+
error('Missing value for --active-cap (e.g. --active-cap tdd)', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1279
1280
|
}
|
|
1280
1281
|
loopActiveCap = value;
|
|
1281
1282
|
}
|
|
@@ -1286,7 +1287,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1286
1287
|
} else {
|
|
1287
1288
|
error(
|
|
1288
1289
|
`Unknown loop subcommand: ${loopSubcommand}. Available: render-hooks`,
|
|
1289
|
-
|
|
1290
|
+
ERROR_REASON ? ERROR_REASON.SDK_UNKNOWN_COMMAND : undefined,
|
|
1290
1291
|
);
|
|
1291
1292
|
}
|
|
1292
1293
|
break;
|
|
@@ -1307,7 +1308,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1307
1308
|
const configDirVal = args[configDirIdx + 1];
|
|
1308
1309
|
// Validate that --config-dir has a following non-flag value.
|
|
1309
1310
|
if (!configDirVal || configDirVal.startsWith('--')) {
|
|
1310
|
-
error('Missing value for --config-dir',
|
|
1311
|
+
error('Missing value for --config-dir', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1311
1312
|
}
|
|
1312
1313
|
configDir = configDirVal;
|
|
1313
1314
|
}
|
|
@@ -1317,7 +1318,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1317
1318
|
// capability set <id> [--on|--off|--enable|--disable] [--gate <key>=<bool>]... [--config-dir <dir>] [--runtime <r>] [--scope <s>]
|
|
1318
1319
|
const capId = args[2];
|
|
1319
1320
|
if (!capId || capId.startsWith('--')) {
|
|
1320
|
-
error('Missing capability id for: capability set <id>',
|
|
1321
|
+
error('Missing capability id for: capability set <id>', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1321
1322
|
}
|
|
1322
1323
|
// Parse --config-dir
|
|
1323
1324
|
const setConfigDirIdx = args.indexOf('--config-dir');
|
|
@@ -1325,7 +1326,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1325
1326
|
if (setConfigDirIdx !== -1) {
|
|
1326
1327
|
const setConfigDirVal = args[setConfigDirIdx + 1];
|
|
1327
1328
|
if (!setConfigDirVal || setConfigDirVal.startsWith('--')) {
|
|
1328
|
-
error('Missing value for --config-dir',
|
|
1329
|
+
error('Missing value for --config-dir', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1329
1330
|
}
|
|
1330
1331
|
setConfigDir = setConfigDirVal;
|
|
1331
1332
|
}
|
|
@@ -1334,7 +1335,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1334
1335
|
const hasOn = args.includes('--on') || args.includes('--enable');
|
|
1335
1336
|
const hasOff = args.includes('--off') || args.includes('--disable');
|
|
1336
1337
|
if (hasOn && hasOff) {
|
|
1337
|
-
error('Conflicting flags: --on/--enable and --off/--disable cannot both be present',
|
|
1338
|
+
error('Conflicting flags: --on/--enable and --off/--disable cannot both be present', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1338
1339
|
}
|
|
1339
1340
|
let setEnabled;
|
|
1340
1341
|
if (hasOn) {
|
|
@@ -1348,16 +1349,16 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1348
1349
|
if (args[gi] === '--gate') {
|
|
1349
1350
|
const gateVal = args[gi + 1];
|
|
1350
1351
|
if (!gateVal || gateVal.startsWith('--')) {
|
|
1351
|
-
error('Missing value for --gate (expected <key>=<true|false>)',
|
|
1352
|
+
error('Missing value for --gate (expected <key>=<true|false>)', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1352
1353
|
}
|
|
1353
1354
|
const eqIdx = gateVal.indexOf('=');
|
|
1354
1355
|
if (eqIdx === -1) {
|
|
1355
|
-
error(`Malformed --gate value "${gateVal}": expected <key>=<true|false>`,
|
|
1356
|
+
error(`Malformed --gate value "${gateVal}": expected <key>=<true|false>`, ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1356
1357
|
}
|
|
1357
1358
|
const gateKey = gateVal.slice(0, eqIdx);
|
|
1358
1359
|
const gateBoolStr = gateVal.slice(eqIdx + 1);
|
|
1359
1360
|
if (gateBoolStr !== 'true' && gateBoolStr !== 'false') {
|
|
1360
|
-
error(`Malformed --gate value "${gateVal}": bool must be true or false`,
|
|
1361
|
+
error(`Malformed --gate value "${gateVal}": bool must be true or false`, ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1361
1362
|
}
|
|
1362
1363
|
setGates[gateKey] = gateBoolStr === 'true';
|
|
1363
1364
|
gi++; // skip consumed value
|
|
@@ -1369,7 +1370,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1369
1370
|
if (runtimeIdx !== -1) {
|
|
1370
1371
|
const runtimeVal = args[runtimeIdx + 1];
|
|
1371
1372
|
if (!runtimeVal || runtimeVal.startsWith('--')) {
|
|
1372
|
-
error('Missing value for --runtime',
|
|
1373
|
+
error('Missing value for --runtime', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1373
1374
|
}
|
|
1374
1375
|
setRuntime = runtimeVal;
|
|
1375
1376
|
}
|
|
@@ -1378,7 +1379,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1378
1379
|
if (scopeIdx !== -1) {
|
|
1379
1380
|
const scopeVal = args[scopeIdx + 1];
|
|
1380
1381
|
if (!scopeVal || scopeVal.startsWith('--')) {
|
|
1381
|
-
error('Missing value for --scope',
|
|
1382
|
+
error('Missing value for --scope', ERROR_REASON ? ERROR_REASON.USAGE : undefined);
|
|
1382
1383
|
}
|
|
1383
1384
|
setScope = scopeVal;
|
|
1384
1385
|
}
|
|
@@ -1392,7 +1393,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1392
1393
|
} else {
|
|
1393
1394
|
error(
|
|
1394
1395
|
`Unknown capability subcommand: ${capSubcommand}. Available: state, set`,
|
|
1395
|
-
|
|
1396
|
+
ERROR_REASON ? ERROR_REASON.SDK_UNKNOWN_COMMAND : undefined,
|
|
1396
1397
|
);
|
|
1397
1398
|
}
|
|
1398
1399
|
break;
|
|
@@ -1484,7 +1485,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1484
1485
|
cwd,
|
|
1485
1486
|
raw,
|
|
1486
1487
|
error,
|
|
1487
|
-
output:
|
|
1488
|
+
output: output,
|
|
1488
1489
|
});
|
|
1489
1490
|
if (!handled) docs.cmdDocsInit(cwd, raw);
|
|
1490
1491
|
break;
|
|
@@ -1810,7 +1811,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1810
1811
|
// ─── Research Store ────────────────────────────────────────────────────
|
|
1811
1812
|
//
|
|
1812
1813
|
// research-store get <key> [--kind <k>]
|
|
1813
|
-
// -> getResearch(cwd, key, { homeDir }); searches both tiers;
|
|
1814
|
+
// -> getResearch(cwd, key, { homeDir }); searches both tiers; output(result, raw)
|
|
1814
1815
|
// (--kind is accepted for backward compatibility but no longer drives tier selection)
|
|
1815
1816
|
// research-store put <key> --content <str> --source <s> --provider <p>
|
|
1816
1817
|
// --confidence <c> --kind <k>
|
|
@@ -1834,7 +1835,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1834
1835
|
}
|
|
1835
1836
|
// --kind is accepted but no longer drives tier selection; getResearch searches both tiers
|
|
1836
1837
|
const result = researchStore.getResearch(cwd, key, { homeDir });
|
|
1837
|
-
|
|
1838
|
+
output(result, raw);
|
|
1838
1839
|
} else if (subcommand === 'put') {
|
|
1839
1840
|
const key = args[2];
|
|
1840
1841
|
if (!key || key.startsWith('--')) {
|
|
@@ -1866,7 +1867,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1866
1867
|
error('Usage: gsd-tools research-store put <key> --content <str> --source <s> --provider <p> --confidence <c> --kind <k>', ERROR_REASON.USAGE);
|
|
1867
1868
|
}
|
|
1868
1869
|
const entry = researchStore.putResearch(cwd, key, { content, source, provider, confidence, kind }, { homeDir });
|
|
1869
|
-
|
|
1870
|
+
output(entry, raw);
|
|
1870
1871
|
} else {
|
|
1871
1872
|
error('Unknown research-store subcommand. Available: get, put', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
1872
1873
|
}
|
|
@@ -1902,14 +1903,14 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1902
1903
|
const { ecosystem = '', config: planConfig = {}, questions } = planInput;
|
|
1903
1904
|
const homeDir = process.env.HOME || require('os').homedir();
|
|
1904
1905
|
const plan = researchProvider.planResearch({ questions, ecosystem, config: planConfig, cwd, homeDir });
|
|
1905
|
-
|
|
1906
|
+
output(plan, raw);
|
|
1906
1907
|
break;
|
|
1907
1908
|
}
|
|
1908
1909
|
|
|
1909
1910
|
// ─── Classify Confidence ──────────────────────────────────────────────
|
|
1910
1911
|
//
|
|
1911
1912
|
// classify-confidence --provider <id> [--package <name> --ecosystem <npm|pypi|crates>] [--verified]
|
|
1912
|
-
// -> classifyConfidence({ provider, verifiedAgainstOfficial, legitimacyVerdict });
|
|
1913
|
+
// -> classifyConfidence({ provider, verifiedAgainstOfficial, legitimacyVerdict }); output(result, raw)
|
|
1913
1914
|
//
|
|
1914
1915
|
// legitimacyVerdict is CODE-COMPUTED via checkPackages — never caller-supplied — so an agent cannot self-assert OK→HIGH.
|
|
1915
1916
|
|
|
@@ -1936,7 +1937,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1936
1937
|
legitimacyVerdict = results[0] ? results[0].verdict : null;
|
|
1937
1938
|
}
|
|
1938
1939
|
const confidence = researchProvider.classifyConfidence({ provider, verifiedAgainstOfficial: verified, legitimacyVerdict });
|
|
1939
|
-
|
|
1940
|
+
output({ provider, package: pkg || null, ecosystem: ecosystem || null, legitimacyVerdict, verified, confidence }, raw);
|
|
1940
1941
|
break;
|
|
1941
1942
|
}
|
|
1942
1943
|
|
|
@@ -1980,7 +1981,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1980
1981
|
} catch (pkgErr) {
|
|
1981
1982
|
error(`package-legitimacy: ${pkgErr && pkgErr.message ? pkgErr.message : String(pkgErr)}`, ERROR_REASON.UNKNOWN);
|
|
1982
1983
|
}
|
|
1983
|
-
|
|
1984
|
+
output(pkgResults, raw);
|
|
1984
1985
|
break;
|
|
1985
1986
|
}
|
|
1986
1987
|
|
|
@@ -2101,7 +2102,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2101
2102
|
}
|
|
2102
2103
|
}
|
|
2103
2104
|
|
|
2104
|
-
|
|
2105
|
+
output({ valid: errors.length === 0, errors, slots }, raw);
|
|
2105
2106
|
break;
|
|
2106
2107
|
}
|
|
2107
2108
|
|
|
@@ -2114,7 +2115,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2114
2115
|
|
|
2115
2116
|
// Read config.json directly for both plan_review.source_grounding_authority
|
|
2116
2117
|
// and intel.enabled. Neither key is in the config-loader.cjs whitelist that
|
|
2117
|
-
//
|
|
2118
|
+
// config-loader.cjs's loadConfig() whitelist does not return; plan_review is only in config.cjs's private
|
|
2118
2119
|
// buildConfig(), and intel is a federated capability config key.
|
|
2119
2120
|
let configuredAuthority = 'grep';
|
|
2120
2121
|
let intelEnabled = false;
|
|
@@ -2138,7 +2139,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2138
2139
|
|
|
2139
2140
|
if (subcommand === 'authority') {
|
|
2140
2141
|
// Pass rawValue as 3rd arg so --raw returns unquoted string (not JSON)
|
|
2141
|
-
|
|
2142
|
+
output(effectiveAuthority, raw, effectiveAuthority);
|
|
2142
2143
|
break;
|
|
2143
2144
|
}
|
|
2144
2145
|
|
|
@@ -2155,7 +2156,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2155
2156
|
? authVal
|
|
2156
2157
|
: effectiveAuthority;
|
|
2157
2158
|
const result = classifyDriftSeverity({ status: statusVal, authority: authorityForClassify });
|
|
2158
|
-
|
|
2159
|
+
output(result, raw);
|
|
2159
2160
|
break;
|
|
2160
2161
|
}
|
|
2161
2162
|
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* from the prior hand-written .cjs; only types are added.
|
|
8
8
|
*/
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
10
|
-
const
|
|
11
|
-
const { output, error, ERROR_REASON } =
|
|
10
|
+
const io = require("./io.cjs");
|
|
11
|
+
const { output, error, ERROR_REASON } = io;
|
|
12
12
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
13
13
|
const QUOTA_SENTINELS = [
|
|
14
14
|
'429',
|