@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.3
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-mempalace-curator.md +47 -0
- package/bin/install.js +25 -7
- package/commands/gsd/mempalace-capture.md +71 -0
- package/commands/gsd/mempalace-recall.md +102 -0
- package/commands/gsd/ns-context.md +4 -2
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +110 -92
- package/gsd-core/bin/lib/capability-activation.cjs +86 -0
- package/gsd-core/bin/lib/capability-registry.cjs +1468 -11
- package/gsd-core/bin/lib/capability-state.cjs +31 -18
- package/gsd-core/bin/lib/check-command-router.cjs +328 -1
- package/gsd-core/bin/lib/clusters.cjs +2 -0
- package/gsd-core/bin/lib/command-roster.cjs +19 -0
- package/gsd-core/bin/lib/commands.cjs +33 -10
- package/gsd-core/bin/lib/config-loader.cjs +7 -8
- package/gsd-core/bin/lib/config-schema.cjs +32 -3
- package/gsd-core/bin/lib/config.cjs +1 -2
- package/gsd-core/bin/lib/core.cjs +5 -2
- package/gsd-core/bin/lib/init.cjs +8 -5
- package/gsd-core/bin/lib/install-profiles.cjs +2 -1
- package/gsd-core/bin/lib/loop-resolver.cjs +157 -16
- package/gsd-core/bin/lib/model-resolver.cjs +47 -5
- package/gsd-core/bin/lib/phase.cjs +71 -11
- package/gsd-core/bin/lib/profile-output.cjs +45 -4
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
- package/gsd-core/bin/lib/roadmap.cjs +97 -7
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1700 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +20 -28
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +27 -19
- package/gsd-core/bin/lib/runtime-homes.cjs +26 -20
- package/gsd-core/bin/lib/state-command-router.cjs +15 -3
- package/gsd-core/bin/lib/state-document.cjs +46 -1
- package/gsd-core/bin/lib/state.cjs +221 -35
- package/gsd-core/bin/lib/verify.cjs +19 -4
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -2
- package/gsd-core/bin/shared/config-schema.manifest.json +0 -18
- package/gsd-core/bin/shared/model-catalog.json +1 -0
- package/gsd-core/references/loop-hook-dispatch.md +61 -0
- package/gsd-core/templates/config.json +1 -1
- package/gsd-core/workflows/audit-milestone.md +5 -3
- package/gsd-core/workflows/autonomous.md +10 -5
- package/gsd-core/workflows/code-review-fix.md +9 -7
- package/gsd-core/workflows/code-review.md +8 -6
- package/gsd-core/workflows/discuss-phase.md +14 -0
- package/gsd-core/workflows/execute-phase.md +82 -143
- package/gsd-core/workflows/help/modes/full.md +3 -1
- package/gsd-core/workflows/new-project.md +3 -3
- package/gsd-core/workflows/plan-phase.md +89 -221
- package/gsd-core/workflows/profile-user.md +3 -1
- package/gsd-core/workflows/progress.md +58 -1
- package/gsd-core/workflows/quick.md +9 -6
- package/gsd-core/workflows/review.md +19 -2
- package/gsd-core/workflows/secure-phase.md +4 -2
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/ship.md +57 -0
- package/gsd-core/workflows/validate-phase.md +4 -2
- package/gsd-core/workflows/verify-work.md +27 -11
- package/package.json +3 -2
- package/scripts/affected-tests-lib.cjs +16 -4
- package/scripts/gen-capability-registry.cjs +359 -48
- package/scripts/gen-inventory-manifest.cjs +1 -4
- package/scripts/gen-loop-host-contract.cjs +55 -0
- package/scripts/issue-version-gate.cjs +140 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +326 -0
- package/scripts/lint-allow-test-rule-refs.cjs +162 -0
- package/scripts/lint-test-file-count.allowlist.json +8 -0
- package/scripts/release-tarball-smoke.cjs +7 -1
- package/scripts/run-tests.cjs +74 -14
|
@@ -223,6 +223,16 @@ CODEX_MODEL=$(gsd_run query config-get review.models.codex 2>/dev/null | jq -r '
|
|
|
223
223
|
OPENCODE_MODEL=$(gsd_run query config-get review.models.opencode 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
224
224
|
# review.models.agy is reserved for future model-pinning support; agy selects its model internally
|
|
225
225
|
AGY_MODEL=$(gsd_run query config-get review.models.agy 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
226
|
+
|
|
227
|
+
# #1115: `--dangerously-bypass-hook-trust` only exists on codex-cli >= 0.137.0.
|
|
228
|
+
# Capability-probe it so older installs don't fail with "unexpected argument"
|
|
229
|
+
# (which, with stderr suppressed, produced a silent empty review). The codex
|
|
230
|
+
# invocation works fine without the flag on older versions.
|
|
231
|
+
if codex exec --help 2>/dev/null | grep -q -- '--dangerously-bypass-hook-trust'; then
|
|
232
|
+
CODEX_BYPASS_FLAG="--dangerously-bypass-hook-trust"
|
|
233
|
+
else
|
|
234
|
+
CODEX_BYPASS_FLAG=""
|
|
235
|
+
fi
|
|
226
236
|
```
|
|
227
237
|
|
|
228
238
|
For each selected CLI, invoke in sequence (not parallel — avoid rate limits):
|
|
@@ -247,10 +257,17 @@ fi
|
|
|
247
257
|
|
|
248
258
|
**Codex:**
|
|
249
259
|
```bash
|
|
260
|
+
# $CODEX_BYPASS_FLAG is capability-gated above (#1115). Capture stderr to a .err
|
|
261
|
+
# file (not /dev/null) so a non-zero exit — e.g. a flag the installed codex-cli
|
|
262
|
+
# does not support — is diagnosable instead of a silent empty review.
|
|
250
263
|
if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then
|
|
251
|
-
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral
|
|
264
|
+
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check - 2>/tmp/gsd-review-codex-{phase}.err > /tmp/gsd-review-codex-{phase}.md
|
|
252
265
|
else
|
|
253
|
-
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral
|
|
266
|
+
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check - 2>/tmp/gsd-review-codex-{phase}.err > /tmp/gsd-review-codex-{phase}.md
|
|
267
|
+
fi
|
|
268
|
+
if [ ! -s /tmp/gsd-review-codex-{phase}.md ]; then
|
|
269
|
+
echo "Codex review failed or returned empty output. stderr:" > /tmp/gsd-review-codex-{phase}.md
|
|
270
|
+
cat /tmp/gsd-review-codex-{phase}.err >> /tmp/gsd-review-codex-{phase}.md
|
|
254
271
|
fi
|
|
255
272
|
```
|
|
256
273
|
|
|
@@ -26,10 +26,12 @@ Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
AUDITOR_MODEL=$(gsd_run query resolve-model gsd-security-auditor --raw)
|
|
29
|
-
|
|
29
|
+
VERIFY_POST_HOOKS_JSON=$(gsd_run loop render-hooks verify:post --raw)
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "secure-phase"`.
|
|
33
|
+
|
|
34
|
+
If no active secure-phase step hook exists: exit with "Security enforcement disabled. Enable via /gsd:settings."
|
|
33
35
|
|
|
34
36
|
Display banner: `GSD > SECURE PHASE {N}: {name}`
|
|
35
37
|
|
|
@@ -672,6 +672,8 @@ Canonical tier mappings by provider and budget:
|
|
|
672
672
|
|
|
673
673
|
Look up the selected (provider, budget) row and proceed to Step E to write those values.
|
|
674
674
|
|
|
675
|
+
> **claude runtime note:** On the default `claude` runtime, policy-resolved model IDs (e.g. `claude-fable-5`) are mapped to Claude Code agent aliases (`fable`, `opus`, `sonnet`, `haiku`); an ID with no corresponding alias emits a stderr warning and falls back to the configured tier alias.
|
|
676
|
+
|
|
675
677
|
**Step D — Generic-provider path:**
|
|
676
678
|
|
|
677
679
|
Prompt the user to enter each model ID as a free-text input. An empty input means "keep
|
|
@@ -13,6 +13,11 @@ Create a pull request from completed phase/milestone work, generate a rich PR bo
|
|
|
13
13
|
Read all files referenced by the invoking prompt's execution_context before starting.
|
|
14
14
|
</required_reading>
|
|
15
15
|
|
|
16
|
+
<available_agent_types>
|
|
17
|
+
Valid GSD subagent types (use exact names — do not fall back to 'general-purpose'):
|
|
18
|
+
- gsd-mempalace-curator — Ship-time MemPalace curation (diary, KG mirror, cross-project tunnels, wing-scoped prune); dispatched at ship:post when the mempalace capability is enabled.
|
|
19
|
+
</available_agent_types>
|
|
20
|
+
|
|
16
21
|
<process>
|
|
17
22
|
|
|
18
23
|
<step name="initialize">
|
|
@@ -79,6 +84,32 @@ Verify the work is ready to ship:
|
|
|
79
84
|
which gh && gh auth status 2>&1
|
|
80
85
|
```
|
|
81
86
|
If `gh` not found or not authenticated: provide setup instructions and exit.
|
|
87
|
+
|
|
88
|
+
6. **Security ship gate (capability-driven).**
|
|
89
|
+
|
|
90
|
+
Resolve active `ship:pre` gate hooks from the capability registry — the registry evaluates each hook's `when` condition, so do **not** read `workflow.security_enforcement` directly:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
SHIP_PRE_HOOKS_JSON=$(gsd_run loop render-hooks ship:pre --raw)
|
|
94
|
+
SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Read the `activeHooks` array from `SHIP_PRE_HOOKS_JSON` in-context (do NOT pipe it through a shell parser).
|
|
98
|
+
|
|
99
|
+
If an active entry exists with `kind == "gate"`, `capId == "security"`, and `blocking == true`, enforce its predicate (`SECURITY.md` frontmatter `threats_open == 0`) before shipping:
|
|
100
|
+
|
|
101
|
+
- **`SECURITY_FILE` is empty** → block with `SECURITY_SHIP_GATE_NO_REVIEW`:
|
|
102
|
+
```
|
|
103
|
+
⚠ Security enforcement is enabled but no SECURITY.md exists for this phase.
|
|
104
|
+
Run /gsd:secure-phase {phase} and resolve findings before shipping.
|
|
105
|
+
```
|
|
106
|
+
- **`SECURITY_FILE` exists** → read its frontmatter `threats_open`. The gate passes **only** when `threats_open` is exactly `0`. For any other value — `threats_open` > 0, or a missing / non-numeric / unparsable field — **fail closed and block** with `SECURITY_SHIP_GATE_OPEN_THREATS` (the predicate is strict equality to `0`; never ship on an ambiguous value):
|
|
107
|
+
```
|
|
108
|
+
⚠ Security ship gate: SECURITY.md does not assert threats_open == 0 (found: {threats_open|unset}).
|
|
109
|
+
Resolve open threats (or re-run /gsd:secure-phase {phase}) before shipping.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If no active security `ship:pre` gate hook is present (security enforcement off), skip this check silently.
|
|
82
113
|
</step>
|
|
83
114
|
|
|
84
115
|
<step name="push_branch">
|
|
@@ -371,6 +402,32 @@ gsd_run query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #
|
|
|
371
402
|
```
|
|
372
403
|
</step>
|
|
373
404
|
|
|
405
|
+
<step name="ship_post_capability_dispatch">
|
|
406
|
+
|
|
407
|
+
> Capability-driven dispatch. Resolves active `ship:post` hooks via the capability registry; each hook's `when` is evaluated by the registry — no inline `config-get`. All `ship:post` hooks are post-ship and additive (`onError: skip`); a failure here never affects the already-created PR.
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
SHIP_POST_HOOKS_JSON=$(gsd_run loop render-hooks ship:post --raw)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Read the `activeHooks` array directly from `SHIP_POST_HOOKS_JSON` in-context (do NOT pipe it through a shell parser).
|
|
414
|
+
|
|
415
|
+
**Branch 1 — no active `ship:post` step hooks (`activeHooks` has no entry with `kind == "step"`):** Skip silently to the report.
|
|
416
|
+
|
|
417
|
+
**Generic step hook dispatch contract:** For each active entry where `kind == "step"`:
|
|
418
|
+
- Honor `consumes`: if it lists `UAT.md`, resolve `ls "${PHASE_DIR}"/*-UAT.md 2>/dev/null | head -1` and pass it to the dispatch; if a consumed artifact is absent, skip that hook.
|
|
419
|
+
- If `ref.agent` is set, first show the spawn banner, then dispatch the agent named by `ref.agent` (use the exact `ref.agent` value as the subagent type — e.g. `gsd-mempalace-curator` — never `general-purpose`):
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
◆ Spawning ship:post capability agent... (runs in a subagent — no output until it returns, ~1–2 min; expected, not a freeze)
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
`Agent(subagent_type=ref.agent, prompt="Ship-time capability hook for phase ${PHASE_NUMBER}. Phase dir: ${PHASE_DIR}. Consume: ${consumed_files}. Follow your agent instructions.", model="{balanced_model}")`
|
|
426
|
+
- If `ref.skill` is set, dispatch with `Skill(skill="gsd-${ref.skill}", args="${PHASE_NUMBER} --auto ${GSD_WS}")` (prepend `gsd-` to `ref.skill`).
|
|
427
|
+
|
|
428
|
+
Each dispatch is best-effort: if it errors, record a warning and continue — never re-raise (`onError: skip`).
|
|
429
|
+
</step>
|
|
430
|
+
|
|
374
431
|
<step name="report">
|
|
375
432
|
```
|
|
376
433
|
───────────────────────────────────────────────────────────────
|
|
@@ -26,10 +26,12 @@ Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
AUDITOR_MODEL=$(gsd_run query resolve-model gsd-nyquist-auditor --raw)
|
|
29
|
-
|
|
29
|
+
VERIFY_POST_HOOKS_JSON=$(gsd_run loop render-hooks verify:post --raw)
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "validate-phase"`.
|
|
33
|
+
|
|
34
|
+
If no active validate-phase step hook exists: exit with "Nyquist validation is disabled. Enable via /gsd:settings."
|
|
33
35
|
|
|
34
36
|
Display banner: `GSD > VALIDATE PHASE {N}: {name}`
|
|
35
37
|
|
|
@@ -108,16 +108,17 @@ Continue to `create_uat_file`.
|
|
|
108
108
|
<step name="automated_ui_verification">
|
|
109
109
|
**Automated UI Verification (when Playwright-MCP is available)**
|
|
110
110
|
|
|
111
|
-
Before
|
|
112
|
-
`mcp__playwright__*` or `mcp__puppeteer__*` tools are available in the current session.
|
|
111
|
+
Before UAT, check UI capability activation and whether Playwright/Puppeteer MCP tools are available.
|
|
113
112
|
|
|
114
113
|
```bash
|
|
115
|
-
|
|
114
|
+
PLAN_HOOKS_JSON=$(gsd_run loop render-hooks plan:pre --raw)
|
|
116
115
|
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
|
117
116
|
```
|
|
118
117
|
|
|
118
|
+
Set `UI_PHASE_ACTIVE=true` when `PLAN_HOOKS_JSON.activeHooks` contains an active `ui` step hook.
|
|
119
|
+
|
|
119
120
|
**If Playwright-MCP tools are available in this session (`mcp__playwright__*` tools
|
|
120
|
-
respond to tool calls) AND (`
|
|
121
|
+
respond to tool calls) AND (`UI_PHASE_ACTIVE` is `true` OR `UI_SPEC_FILE` is non-empty):**
|
|
121
122
|
|
|
122
123
|
For each UI checkpoint listed in the phase's UI-SPEC.md (or inferred from SUMMARY.md):
|
|
123
124
|
|
|
@@ -457,16 +458,31 @@ Present summary:
|
|
|
457
458
|
**If issues == 0:**
|
|
458
459
|
|
|
459
460
|
```bash
|
|
460
|
-
|
|
461
|
+
VERIFY_POST_HOOKS_JSON=$(gsd_run loop render-hooks verify:post --raw)
|
|
462
|
+
SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "secure-phase"`.
|
|
466
|
+
|
|
467
|
+
If an active secure-phase step hook exists AND `SECURITY_FILE` is empty, dispatch the registry-provided skill stem:
|
|
468
|
+
|
|
469
|
+
```
|
|
470
|
+
Skill(skill="gsd-${ref.skill}", args="{phase}")
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
After the skill returns, refresh `SECURITY_FILE`:
|
|
474
|
+
|
|
475
|
+
```bash
|
|
461
476
|
SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
|
|
462
477
|
```
|
|
463
478
|
|
|
464
|
-
If `
|
|
479
|
+
If `SECURITY_FILE` is still empty, stop before phase advancement and present:
|
|
480
|
+
|
|
465
481
|
```
|
|
466
|
-
⚠ Security enforcement enabled — /gsd:secure-phase {phase}
|
|
467
|
-
|
|
482
|
+
⚠ Security enforcement enabled — /gsd:secure-phase {phase} did not produce SECURITY.md.
|
|
483
|
+
Resolve the security review failure before advancing to the next phase.
|
|
468
484
|
|
|
469
|
-
All tests passed
|
|
485
|
+
All tests passed, but phase advancement is blocked until security review produces SECURITY.md.
|
|
470
486
|
|
|
471
487
|
- `/gsd:secure-phase {phase}` — security review (required before advancing)
|
|
472
488
|
- `/gsd:plan-phase {next}` — Plan next phase
|
|
@@ -474,13 +490,13 @@ All tests passed. Ready to continue.
|
|
|
474
490
|
- `/gsd:ui-review {phase}` — visual quality audit (if frontend files were modified)
|
|
475
491
|
```
|
|
476
492
|
|
|
477
|
-
If
|
|
493
|
+
If an active secure-phase step hook exists AND `SECURITY_FILE` exists: check frontmatter `threats_open`. If > 0:
|
|
478
494
|
```
|
|
479
495
|
⚠ Security gate: {threats_open} threats open
|
|
480
496
|
/gsd:secure-phase {phase} — resolve before advancing
|
|
481
497
|
```
|
|
482
498
|
|
|
483
|
-
If
|
|
499
|
+
If no active secure-phase step hook exists OR (`SECURITY_FILE` exists AND `threats_open` is `0`):
|
|
484
500
|
|
|
485
501
|
**Auto-transition: mark phase complete in ROADMAP.md and STATE.md**
|
|
486
502
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/gsd-core",
|
|
3
|
-
"version": "1.5.0-rc.
|
|
3
|
+
"version": "1.5.0-rc.3",
|
|
4
4
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"gsd-core": "bin/install.js",
|
|
@@ -92,7 +92,8 @@
|
|
|
92
92
|
"pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
|
|
93
93
|
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
|
|
94
94
|
"lint:fix": "eslint . --fix",
|
|
95
|
-
"lint:ci": "npm run lint && npm run lint:skill-deps && 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 && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs",
|
|
95
|
+
"lint:ci": "npm run lint && npm run lint:skill-deps && 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 && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs",
|
|
96
|
+
"lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
|
|
96
97
|
"lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
|
|
97
98
|
"lint:regression-names": "node scripts/lint-regression-test-names.cjs",
|
|
98
99
|
"lint:descriptions": "node scripts/lint-descriptions.cjs",
|
|
@@ -259,10 +259,21 @@ function shouldRunFullSuite(changedFiles) {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
function listTestFiles(repoRoot) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
const results = [];
|
|
263
|
+
function walk(dir, relBase) {
|
|
264
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
265
|
+
if (entry.isDirectory()) {
|
|
266
|
+
if (entry.name === 'node_modules') continue;
|
|
267
|
+
const nextRel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
268
|
+
walk(path.join(dir, entry.name), nextRel);
|
|
269
|
+
} else if (entry.name.endsWith('.test.cjs')) {
|
|
270
|
+
const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
271
|
+
results.push(`tests/${rel}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
walk(path.join(repoRoot, 'tests'), '');
|
|
276
|
+
return results.sort();
|
|
266
277
|
}
|
|
267
278
|
|
|
268
279
|
/**
|
|
@@ -531,6 +542,7 @@ module.exports = {
|
|
|
531
542
|
buildForwardGraph,
|
|
532
543
|
buildReverseIndex,
|
|
533
544
|
buildTransitiveReverseIndex,
|
|
545
|
+
listTestFiles,
|
|
534
546
|
parseRelativeSpecifiers,
|
|
535
547
|
pickAffectedTests,
|
|
536
548
|
resolveBaseRef,
|