@opengsd/gsd-core 1.7.0-rc.3 → 1.7.0-rc.4
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/README.ja-JP.md +4 -3
- package/README.ko-KR.md +4 -3
- package/README.md +4 -3
- package/README.pt-BR.md +4 -3
- package/README.zh-CN.md +4 -3
- package/bin/install.js +33 -15
- package/commands/gsd/map-codebase.md +4 -4
- package/commands/gsd/ns-project.md +2 -1
- package/commands/gsd/onboard.md +46 -0
- package/gsd-core/bin/gsd-tools.cjs +47 -2
- package/gsd-core/bin/lib/capability-registry.cjs +467 -49
- package/gsd-core/bin/lib/capability-state.cjs +117 -18
- package/gsd-core/bin/lib/capability-writer.cjs +11 -1
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +136 -0
- package/gsd-core/bin/lib/claude-orchestration.cjs +404 -0
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/command-aliases.cjs +8 -0
- package/gsd-core/bin/lib/init-command-router.cjs +4 -0
- package/gsd-core/bin/lib/init.cjs +25 -69
- package/gsd-core/bin/lib/install-engine.cjs +8 -5
- package/gsd-core/bin/lib/install-profiles.cjs +2 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +7 -1
- package/gsd-core/bin/lib/model-resolver.cjs +69 -4
- package/gsd-core/bin/lib/onboard-projection.cjs +309 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/surface.cjs +51 -30
- package/gsd-core/bin/shared/model-catalog.json +5 -0
- package/gsd-core/references/gsd-run-resolver.md +8 -0
- package/gsd-core/templates/project.md +1 -1
- package/gsd-core/workflows/do.md +4 -3
- package/gsd-core/workflows/help/modes/brief.md +2 -1
- package/gsd-core/workflows/help/modes/default.md +2 -1
- package/gsd-core/workflows/help/modes/full.md +11 -1
- package/gsd-core/workflows/help/modes/topic.md +1 -1
- package/gsd-core/workflows/onboard.md +277 -0
- package/gsd-core/workflows/quick.md +20 -0
- package/package.json +1 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +77 -0
- package/scripts/run-tests.cjs +5 -3
- package/scripts/sync-runtime-launcher.cjs +20 -2
- package/skills/gsd-map-codebase/SKILL.md +3 -3
- package/skills/gsd-ns-project/SKILL.md +1 -0
- package/skills/gsd-onboard/SKILL.md +46 -0
|
@@ -7,7 +7,8 @@ One-liner refresher for returning users. Output ONLY the `<reference>` content b
|
|
|
7
7
|
|
|
8
8
|
```text
|
|
9
9
|
/gsd:new-project Initialize a project (greenfield)
|
|
10
|
-
/gsd:
|
|
10
|
+
/gsd:onboard Onboard an existing codebase (brownfield)
|
|
11
|
+
/gsd:map-codebase Refresh/map codebase intelligence
|
|
11
12
|
/gsd:plan-phase <N> Create a phase plan
|
|
12
13
|
/gsd:execute-phase <N> Execute a phase
|
|
13
14
|
/gsd:progress Where am I, what's next
|
|
@@ -11,11 +11,12 @@ Plan-driven development for solo agentic work with Claude Code. GSD Core turns a
|
|
|
11
11
|
|
|
12
12
|
```text
|
|
13
13
|
/gsd:new-project # Greenfield: questioning → research → requirements → roadmap
|
|
14
|
+
/gsd:onboard # Existing codebase: map → ingest docs → initialize planning
|
|
14
15
|
/gsd:plan-phase 1 # Create a detailed plan for phase 1
|
|
15
16
|
/gsd:execute-phase 1 # Execute all plans in the phase
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
Existing codebase? Run `/gsd:
|
|
19
|
+
Existing codebase? Run `/gsd:onboard` to map the repo, ingest existing docs, and initialize planning safely.
|
|
19
20
|
|
|
20
21
|
## Common commands
|
|
21
22
|
|
|
@@ -62,6 +62,16 @@ Creates all `.planning/` artifacts:
|
|
|
62
62
|
|
|
63
63
|
Usage: `/gsd:new-project`
|
|
64
64
|
|
|
65
|
+
**`/gsd:onboard [--fast] [--text]`**
|
|
66
|
+
Guide first-time onboarding for an existing codebase.
|
|
67
|
+
|
|
68
|
+
- Detects brownfield code, existing planning docs, and partial `.planning/` state
|
|
69
|
+
- Routes through `/gsd:map-codebase`, `/gsd:ingest-docs`, and `/gsd:new-project` in the safe order
|
|
70
|
+
- Creates `.planning/onboarding/SUMMARY.md` after project setup
|
|
71
|
+
- Idempotent: confirms existing artifacts and does not overwrite planning silently
|
|
72
|
+
|
|
73
|
+
Usage: `/gsd:onboard`
|
|
74
|
+
|
|
65
75
|
**`/gsd:map-codebase [--fast] [--focus <area>] [--query <term>]`**
|
|
66
76
|
Map an existing codebase for brownfield projects.
|
|
67
77
|
|
|
@@ -72,7 +82,7 @@ Map an existing codebase for brownfield projects.
|
|
|
72
82
|
- Analyzes codebase with parallel Explore agents
|
|
73
83
|
- Creates `.planning/codebase/` with 7 focused documents
|
|
74
84
|
- Covers stack, architecture, structure, conventions, testing, integrations, concerns
|
|
75
|
-
-
|
|
85
|
+
- Usually reached through `/gsd:onboard` for first-time existing-codebase setup; run directly to refresh or focus a map
|
|
76
86
|
|
|
77
87
|
Usage: `/gsd:map-codebase`
|
|
78
88
|
|
|
@@ -9,7 +9,7 @@ Emit a section from the full reference for the topic in `$ARGUMENTS`. Read `work
|
|
|
9
9
|
|---|---|
|
|
10
10
|
| `next`, `smart-entry` | `### Smart Entry` |
|
|
11
11
|
| `workflow`, `core`, `core-workflow` | `## Core Workflow` (entire section through end of `### Quick Mode`) |
|
|
12
|
-
| `init`, `new-project` | `### Project Initialization` |
|
|
12
|
+
| `init`, `new-project`, `onboard`, `onboarding`, `brownfield` | `### Project Initialization` |
|
|
13
13
|
| `map`, `map-codebase` | The `/gsd:map-codebase` block under `### Project Initialization` |
|
|
14
14
|
| `discuss`, `discuss-phase` | The `/gsd:discuss-phase` block under `### Phase Planning` |
|
|
15
15
|
| `plan`, `planning`, `plan-phase` | `### Phase Planning` |
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# /gsd:onboard Workflow
|
|
2
|
+
|
|
3
|
+
One-command onboarding for an existing or unknown repo. This workflow is a thin
|
|
4
|
+
renderer around `init onboard`; deterministic routing lives in the CLI projection.
|
|
5
|
+
|
|
6
|
+
@~/.claude/gsd-core/references/gsd-run-resolver.md
|
|
7
|
+
|
|
8
|
+
## 1. Render the Onboarding Projection
|
|
9
|
+
|
|
10
|
+
Parse `$ARGUMENTS`:
|
|
11
|
+
- `--fast` passes `--fast` to `init onboard`. Fast mode accepts the fast map for lightweight onboarding only; `next_action` still decides whether complete map work is required before project setup.
|
|
12
|
+
- `--text` forces text-mode choices for runtimes without `AskUserQuestion`.
|
|
13
|
+
|
|
14
|
+
Run the standard `gsd_run` resolver from the reference above, then run the projection from the runtime root:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# If --fast was parsed from $ARGUMENTS:
|
|
18
|
+
INIT=$(gsd_run --cwd "$_GSD_RUNTIME_ROOT" init onboard --fast --raw)
|
|
19
|
+
# Otherwise:
|
|
20
|
+
INIT=$(gsd_run --cwd "$_GSD_RUNTIME_ROOT" init onboard --raw)
|
|
21
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Parse JSON fields from `INIT`:
|
|
25
|
+
|
|
26
|
+
- `next_action.kind`, `next_action.command`, `next_action.reason`, `next_action.missing`, `next_action.summary_path`
|
|
27
|
+
- `handoff_commands.ingest_docs`, `handoff_commands.manager`, `handoff_commands.new_project`, `handoff_commands.onboard`
|
|
28
|
+
- `map_readiness`, `codebase_map_summary_status`, `codebase_map_final_status`
|
|
29
|
+
- `planning_exists`, `project_exists`, `requirements_exists`, `roadmap_exists`, `state_exists`
|
|
30
|
+
- `is_brownfield`, `fast_mode`, `has_codebase_map`, `has_fast_codebase_map`
|
|
31
|
+
- `missing_codebase_map_files`, `missing_fast_codebase_map_files`
|
|
32
|
+
- `has_docs_candidates`, `doc_candidate_count`, `onboarding_summary_exists`
|
|
33
|
+
- `commit_docs`, `text_mode`, `has_git`, `git_worktree_root`, `in_nested_subdir`
|
|
34
|
+
|
|
35
|
+
Set:
|
|
36
|
+
- `TEXT_MODE=true` if `--text` is present or `text_mode` is true. When `TEXT_MODE` is active, replace every `AskUserQuestion` call below with a plain-text numbered list and ask the user to type their choice number — required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
|
|
37
|
+
- `ONBOARDING_ROOT={git_worktree_root || _GSD_RUNTIME_ROOT}`.
|
|
38
|
+
|
|
39
|
+
If `has_git` and `in_nested_subdir` are true, warn that onboarding artifacts belong to the outer worktree at `git_worktree_root`. Do not run `git init`.
|
|
40
|
+
|
|
41
|
+
## 2. Execute `next_action`
|
|
42
|
+
|
|
43
|
+
### `map-codebase`
|
|
44
|
+
|
|
45
|
+
If `next_action.kind == "map-codebase"`:
|
|
46
|
+
|
|
47
|
+
- If `TEXT_MODE=true`, print:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
{next_action.reason}
|
|
51
|
+
Missing map files: {fast_mode ? missing_fast_codebase_map_files : missing_codebase_map_files}
|
|
52
|
+
|
|
53
|
+
1. Map codebase first — run {next_action.command} from worktree root {ONBOARDING_ROOT} (Recommended)
|
|
54
|
+
2. Skip mapping — continue with weaker onboarding context
|
|
55
|
+
|
|
56
|
+
Enter number:
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Otherwise use AskUserQuestion:
|
|
60
|
+
- header: "Codebase"
|
|
61
|
+
- question: "{next_action.reason} Map it first?"
|
|
62
|
+
- options:
|
|
63
|
+
- "Map codebase first" — Run `{next_action.command}` from worktree root `{ONBOARDING_ROOT}` (Recommended)
|
|
64
|
+
- "Skip mapping" — Continue with weaker onboarding context
|
|
65
|
+
|
|
66
|
+
If the user chooses mapping, do not nest the interactive workflow. Print:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
70
|
+
|
|
71
|
+
{next_action.command}
|
|
72
|
+
|
|
73
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Exit. If the user skips mapping:
|
|
77
|
+
|
|
78
|
+
- If `(project_exists || requirements_exists || roadmap_exists || state_exists) && (!project_exists || !requirements_exists || !roadmap_exists || !state_exists)`, route the skip to the partial planning guard instead:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Skipping codebase mapping may give downstream steps weaker context, but project planning exists and is incomplete.
|
|
82
|
+
|
|
83
|
+
PROJECT.md: {project_exists ? "present" : "missing"}
|
|
84
|
+
REQUIREMENTS.md: {requirements_exists ? "present" : "missing"}
|
|
85
|
+
ROADMAP.md: {roadmap_exists ? "present" : "missing"}
|
|
86
|
+
STATE.md: {state_exists ? "present" : "missing"}
|
|
87
|
+
|
|
88
|
+
Run the appropriate lower-level command to fill the missing planning artifact(s), then rerun {handoff_commands.onboard}.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Exit.
|
|
92
|
+
|
|
93
|
+
- If `has_docs_candidates && !project_exists`, route the skip to docs ingest instead:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
Skipping codebase mapping may give downstream steps weaker context, but existing ADR/PRD/SPEC/RFC documents should still be ingested before {handoff_commands.new_project}.
|
|
97
|
+
|
|
98
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
99
|
+
|
|
100
|
+
{handoff_commands.ingest_docs}
|
|
101
|
+
|
|
102
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Exit.
|
|
106
|
+
|
|
107
|
+
- Otherwise print:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
Skipping codebase mapping may give {handoff_commands.new_project} weaker context.
|
|
111
|
+
|
|
112
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
113
|
+
|
|
114
|
+
{handoff_commands.new_project}
|
|
115
|
+
|
|
116
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Exit.
|
|
120
|
+
|
|
121
|
+
### `ingest-docs`
|
|
122
|
+
|
|
123
|
+
If `next_action.kind == "ingest-docs"`:
|
|
124
|
+
|
|
125
|
+
- If `TEXT_MODE=true`, print:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
{next_action.reason}
|
|
129
|
+
Detected {doc_candidate_count} possible ADR/PRD/SPEC/RFC document(s).
|
|
130
|
+
|
|
131
|
+
1. Ingest docs first — run {next_action.command} from worktree root {ONBOARDING_ROOT} (Recommended)
|
|
132
|
+
2. Skip docs ingest — continue to {handoff_commands.new_project}
|
|
133
|
+
|
|
134
|
+
Enter number:
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- Otherwise use AskUserQuestion:
|
|
138
|
+
- header: "Docs"
|
|
139
|
+
- question: "Detected {doc_candidate_count} possible ADR/PRD/SPEC/RFC document(s). Ingest them first?"
|
|
140
|
+
- options:
|
|
141
|
+
- "Ingest docs first" — Run `{next_action.command}` from worktree root `{ONBOARDING_ROOT}` (Recommended)
|
|
142
|
+
- "Skip docs ingest" — Continue to `{handoff_commands.new_project}`
|
|
143
|
+
|
|
144
|
+
If the user chooses ingest, print:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
148
|
+
|
|
149
|
+
{next_action.command}
|
|
150
|
+
|
|
151
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Exit. If the user skips docs ingest, print:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Skipping docs ingest may omit existing ADR/PRD/SPEC/RFC context from {handoff_commands.new_project}.
|
|
158
|
+
|
|
159
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
160
|
+
|
|
161
|
+
{handoff_commands.new_project}
|
|
162
|
+
|
|
163
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Exit.
|
|
167
|
+
|
|
168
|
+
### `complete-map-before-new-project`
|
|
169
|
+
|
|
170
|
+
If `next_action.kind == "complete-map-before-new-project"`, print:
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
{next_action.reason}
|
|
174
|
+
|
|
175
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
176
|
+
|
|
177
|
+
{next_action.command}
|
|
178
|
+
|
|
179
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Exit.
|
|
183
|
+
|
|
184
|
+
### `new-project`
|
|
185
|
+
|
|
186
|
+
If `next_action.kind == "new-project"`, print:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
{next_action.reason}
|
|
190
|
+
|
|
191
|
+
Run from worktree root {ONBOARDING_ROOT}:
|
|
192
|
+
|
|
193
|
+
{next_action.command}
|
|
194
|
+
|
|
195
|
+
Then rerun {handoff_commands.onboard} from the same worktree root.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Exit.
|
|
199
|
+
|
|
200
|
+
### `partial-planning`
|
|
201
|
+
|
|
202
|
+
If `next_action.kind == "partial-planning"`, print:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
Project planning exists but is incomplete.
|
|
206
|
+
|
|
207
|
+
Missing files: {next_action.missing}
|
|
208
|
+
REQUIREMENTS.md: {requirements_exists ? "present" : "missing"}
|
|
209
|
+
ROADMAP.md: {roadmap_exists ? "present" : "missing"}
|
|
210
|
+
STATE.md: {state_exists ? "present" : "missing"}
|
|
211
|
+
|
|
212
|
+
Run the appropriate lower-level command to fill the missing planning artifact(s), then rerun {handoff_commands.onboard}.
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Exit.
|
|
216
|
+
|
|
217
|
+
### `ready`
|
|
218
|
+
|
|
219
|
+
If `next_action.kind == "ready"`, print the final status section and exit.
|
|
220
|
+
|
|
221
|
+
### `write-summary`
|
|
222
|
+
|
|
223
|
+
If `next_action.kind == "write-summary"`, continue to summary creation.
|
|
224
|
+
|
|
225
|
+
## 3. Create Onboarding Summary
|
|
226
|
+
|
|
227
|
+
Create `{ONBOARDING_ROOT}/{next_action.summary_path}`. Do not overwrite an existing summary; the projection should only route here when the summary is missing.
|
|
228
|
+
|
|
229
|
+
Summary template:
|
|
230
|
+
|
|
231
|
+
```markdown
|
|
232
|
+
# Onboarding Summary
|
|
233
|
+
|
|
234
|
+
## Project State
|
|
235
|
+
- PROJECT.md: {project_exists ? "present" : "missing"}
|
|
236
|
+
- REQUIREMENTS.md: {requirements_exists ? "present" : "missing"}
|
|
237
|
+
- ROADMAP.md: {roadmap_exists ? "present" : "missing"}
|
|
238
|
+
- STATE.md: {state_exists ? "present" : "missing"}
|
|
239
|
+
|
|
240
|
+
## Codebase Context
|
|
241
|
+
- Brownfield repo: {is_brownfield ? "yes" : "no"}
|
|
242
|
+
- Map readiness: {map_readiness}
|
|
243
|
+
- Codebase map: {codebase_map_summary_status}
|
|
244
|
+
- Fast map available: {has_fast_codebase_map ? "yes" : "no"}
|
|
245
|
+
|
|
246
|
+
## Docs Context
|
|
247
|
+
- Existing ADR/PRD/SPEC/RFC candidates: {has_docs_candidates ? doc_candidate_count : 0}
|
|
248
|
+
|
|
249
|
+
## Recommended Next Step
|
|
250
|
+
- {handoff_commands.manager}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
If `commit_docs` is true, commit only the summary path from the onboarding root:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
gsd_run --cwd "$ONBOARDING_ROOT" query commit "docs: create onboarding summary" --files .planning/onboarding/SUMMARY.md
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Continue to final status.
|
|
260
|
+
|
|
261
|
+
## 4. Final Status
|
|
262
|
+
|
|
263
|
+
Print:
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
Onboarding status:
|
|
267
|
+
- PROJECT.md: {project_exists ? "present" : "missing"}
|
|
268
|
+
- REQUIREMENTS.md: {requirements_exists ? "present" : "missing"}
|
|
269
|
+
- ROADMAP.md: {roadmap_exists ? "present" : "missing"}
|
|
270
|
+
- STATE.md: {state_exists ? "present" : "missing"}
|
|
271
|
+
- Codebase map: {codebase_map_final_status}
|
|
272
|
+
- Onboarding summary: present
|
|
273
|
+
|
|
274
|
+
Next recommended command: {handoff_commands.manager}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Do not run implementation execution or shipping from onboarding.
|
|
@@ -671,6 +671,26 @@ fi
|
|
|
671
671
|
|
|
672
672
|
**Step 6: Spawn executor**
|
|
673
673
|
|
|
674
|
+
Auto-degrade to sequential if HEAD has diverged from the worktree fork base (#1941, mirrors
|
|
675
|
+
execute-phase's #683/#1369 guard). Claude Code's `isolation="worktree"` forks new worktrees from
|
|
676
|
+
`origin/HEAD`, not the live local HEAD. If a prior quick task in this session (or the Step 5.6
|
|
677
|
+
pre-dispatch plan commit above) advanced local HEAD without an intervening `git push`,
|
|
678
|
+
`origin/HEAD` stays pinned to a stale ancestor and the executor's `worktree_branch_check` guard
|
|
679
|
+
halts with a base-mismatch fatal — potentially many commits behind, not just one. Run this check
|
|
680
|
+
immediately before capturing `EXPECTED_BASE` so it reflects the most current local state.
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
if [ "$RUNTIME" = "claude" ] && [ "${USE_WORKTREES:-true}" != "false" ]; then
|
|
684
|
+
_QUICK_SHOULD_DEGRADE=$(gsd_run query worktree.base-check --pick shouldDegrade 2>/dev/null || true)
|
|
685
|
+
if [ "$_QUICK_SHOULD_DEGRADE" = "true" ]; then
|
|
686
|
+
_QUICK_DEGRADE_MSG=$(gsd_run query worktree.base-check --pick message 2>/dev/null || true)
|
|
687
|
+
[ -n "$_QUICK_DEGRADE_MSG" ] && printf '%s\n' "$_QUICK_DEGRADE_MSG" >&2
|
|
688
|
+
echo "⚠ [#1941] Worktree fork base diverged from orchestrator HEAD — auto-degrading to sequential mode for this quick task to avoid a base-mismatch halt." >&2
|
|
689
|
+
USE_WORKTREES=false
|
|
690
|
+
fi
|
|
691
|
+
fi
|
|
692
|
+
```
|
|
693
|
+
|
|
674
694
|
Capture current HEAD before spawning (used for worktree branch check):
|
|
675
695
|
```bash
|
|
676
696
|
EXPECTED_BASE=$(git rev-parse HEAD)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/gsd-core",
|
|
3
|
-
"version": "1.7.0-rc.
|
|
3
|
+
"version": "1.7.0-rc.4",
|
|
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": {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* Standalone golden-fixture generator for tests/golden-install-parity.
|
|
5
|
+
*
|
|
6
|
+
* This is a BUILD-TIME generation script — NOT a test run. It replicates the
|
|
7
|
+
* buildParityManifest logic from tests/golden-install-parity.test.cjs and
|
|
8
|
+
* captures the zcode fixture so the parity test (which the gsd-test gate runs)
|
|
9
|
+
* has a committed artifact to compare against. The authoritative test gate
|
|
10
|
+
* remains `gsd-test run`, never a local `node --test`.
|
|
11
|
+
*
|
|
12
|
+
* Usage: node scripts/gen-golden-install-parity-zcode.cjs
|
|
13
|
+
*/
|
|
14
|
+
const fs = require('node:fs');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const crypto = require('node:crypto');
|
|
17
|
+
|
|
18
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
19
|
+
const { walk, runMinimalInstall, RUNTIME_META } = require(path.join(ROOT, 'tests', 'helpers', 'install-shared.cjs'));
|
|
20
|
+
const PKG_VERSION = require(path.join(ROOT, 'package.json')).version;
|
|
21
|
+
const FIXTURE_DIR = path.join(ROOT, 'tests', 'fixtures', 'golden-install-parity');
|
|
22
|
+
|
|
23
|
+
const VOLATILE_FILES = new Set([
|
|
24
|
+
'gsd-file-manifest.json',
|
|
25
|
+
'gsd-install-state.json',
|
|
26
|
+
'.gsd-source',
|
|
27
|
+
'gsd-core/CHANGELOG.md',
|
|
28
|
+
]);
|
|
29
|
+
const HOOK_CONFIG_FILES = new Set(['settings.json', 'hooks.json']);
|
|
30
|
+
const EXCLUDED_PREFIXES = ['gsd-core/bin/lib/'];
|
|
31
|
+
|
|
32
|
+
function buildParityManifest(configDir, root) {
|
|
33
|
+
const allFiles = walk(configDir);
|
|
34
|
+
const unsorted = {};
|
|
35
|
+
for (const full of allFiles) {
|
|
36
|
+
const rel = path.relative(configDir, full).split(path.sep).join('/');
|
|
37
|
+
if (VOLATILE_FILES.has(rel)) continue;
|
|
38
|
+
if (HOOK_CONFIG_FILES.has(path.basename(rel))) continue;
|
|
39
|
+
if (EXCLUDED_PREFIXES.some((p) => rel.startsWith(p))) continue;
|
|
40
|
+
const content = fs.readFileSync(full);
|
|
41
|
+
const normalized = content.toString('utf8').split(root).join('<HOME>').split(PKG_VERSION).join('<VERSION>');
|
|
42
|
+
const hash = crypto.createHash('sha256').update(normalized).digest('hex').slice(0, 16);
|
|
43
|
+
unsorted[rel] = hash;
|
|
44
|
+
}
|
|
45
|
+
const sorted = {};
|
|
46
|
+
for (const key of Object.keys(unsorted).sort()) sorted[key] = unsorted[key];
|
|
47
|
+
return sorted;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function cleanup(root) {
|
|
51
|
+
try { fs.rmSync(root, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Regenerate the fixture for every runtime in RUNTIME_META. Needed when a
|
|
55
|
+
// SHARED gsd-core payload file (e.g. model-catalog.json, capability-registry)
|
|
56
|
+
// changes content — its hash appears in every runtime's manifest, so all
|
|
57
|
+
// fixtures must be recaptured together. Usage:
|
|
58
|
+
// node scripts/gen-golden-install-parity-zcode.cjs [runtime ...]
|
|
59
|
+
// With no args, regenerates ALL runtimes. With args, only the named runtimes.
|
|
60
|
+
const targets = process.argv.slice(2).length > 0 ? process.argv.slice(2) : Object.keys(RUNTIME_META);
|
|
61
|
+
fs.mkdirSync(FIXTURE_DIR, { recursive: true });
|
|
62
|
+
for (const runtime of targets) {
|
|
63
|
+
if (!Object.prototype.hasOwnProperty.call(RUNTIME_META, runtime)) {
|
|
64
|
+
process.stderr.write(`[gen] unknown runtime '${runtime}' (not in RUNTIME_META) — skipping\n`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const { configDir, root } = runMinimalInstall({ runtime, scope: 'global' });
|
|
68
|
+
let actual;
|
|
69
|
+
try {
|
|
70
|
+
actual = buildParityManifest(configDir, root);
|
|
71
|
+
} finally {
|
|
72
|
+
cleanup(root);
|
|
73
|
+
}
|
|
74
|
+
const fixturePath = path.join(FIXTURE_DIR, `${runtime}.json`);
|
|
75
|
+
fs.writeFileSync(fixturePath, JSON.stringify(actual, null, 2) + '\n', 'utf8');
|
|
76
|
+
process.stdout.write(`[gen] ${runtime}: wrote ${Object.keys(actual).length} file hashes -> ${fixturePath}\n`);
|
|
77
|
+
}
|
package/scripts/run-tests.cjs
CHANGED
|
@@ -570,11 +570,13 @@ function main() {
|
|
|
570
570
|
// progress (verified: no leaked handle / hang; --test-force-exit exits leaks
|
|
571
571
|
// cleanly, so the timeout was pure slowness, NOT the leak the kill message guesses).
|
|
572
572
|
// The per-chunk timeout is sized for a "healthy chunk (~4-5 min)"; keep chunks at
|
|
573
|
-
// roughly
|
|
574
|
-
// process (also relieving per-process memory pressure from 170+ files at once).
|
|
573
|
+
// roughly a third of a shard so each gets its own fresh 600s budget and a fresh
|
|
574
|
+
// node process (also relieving per-process memory pressure from 170+ files at once).
|
|
575
|
+
// Lowered from 90 to 60 after #1575 — macOS Node 22 shard 2/3 chunk 2 (~80 files
|
|
576
|
+
// including state.test.cjs, perf-*, worktree-cleanup) exceeded 600s with 90.
|
|
575
577
|
const MAX_FILES_PER_CHUNK = process.env.RUN_TESTS_MAX_FILES_PER_CHUNK
|
|
576
578
|
? Number(process.env.RUN_TESTS_MAX_FILES_PER_CHUNK)
|
|
577
|
-
:
|
|
579
|
+
: 60;
|
|
578
580
|
|
|
579
581
|
// node:test does not exit until the event loop drains. A unit test that leaks
|
|
580
582
|
// an open handle (un-terminated Worker, un-killed child_process, ref'd timer)
|
|
@@ -343,9 +343,12 @@ function transformFile(content, preamble) {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
// Insert preamble into the first gsd_run block only
|
|
346
|
+
// Insert preamble into the first gsd_run block only — UNLESS this file
|
|
347
|
+
// delegates to the shared resolver reference (@-include). Delegating files keep
|
|
348
|
+
// the stripped blocks (any inline preamble removed) but never get one inserted.
|
|
349
|
+
const delegates = delegatesToResolverReference(content);
|
|
347
350
|
const finalBlocks = strippedBlocks.map((stripped, bi) => {
|
|
348
|
-
if (bi === firstGsdRunBlockIdx) {
|
|
351
|
+
if (!delegates && bi === firstGsdRunBlockIdx) {
|
|
349
352
|
return insertPreamble(stripped, preamble);
|
|
350
353
|
}
|
|
351
354
|
return stripped;
|
|
@@ -374,6 +377,21 @@ function escapeRegExp(str) {
|
|
|
374
377
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
375
378
|
}
|
|
376
379
|
|
|
380
|
+
/**
|
|
381
|
+
* A file "delegates to the shared resolver" when it pulls the canonical gsd_run
|
|
382
|
+
* preamble in from gsd-core/references/gsd-run-resolver.md via an @-include
|
|
383
|
+
* instead of inlining the snippet (see onboard.md / issue #1990).
|
|
384
|
+
*
|
|
385
|
+
* These files must NOT carry an inline preamble: the resolver reference ships the
|
|
386
|
+
* one canonical copy, and onboard-command.test.cjs asserts the inline form is
|
|
387
|
+
* absent. transformFile still STRIPS any inline preamble from them (so a stray
|
|
388
|
+
* copy is removed) but never re-inserts one — mirroring the exemption in
|
|
389
|
+
* runtime-launcher-parity.test.cjs (subtest B / B2).
|
|
390
|
+
*/
|
|
391
|
+
function delegatesToResolverReference(content) {
|
|
392
|
+
return content.includes('references/gsd-run-resolver.md');
|
|
393
|
+
}
|
|
394
|
+
|
|
377
395
|
// Main
|
|
378
396
|
function main() {
|
|
379
397
|
const preamble = loadPreamble();
|
|
@@ -42,7 +42,7 @@ Parse the first token of $ARGUMENTS:
|
|
|
42
42
|
Check for .planning/STATE.md - loads context if project already initialized
|
|
43
43
|
|
|
44
44
|
**This command can run:**
|
|
45
|
-
-
|
|
45
|
+
- Via /gsd-onboard for first-time brownfield setup - creates codebase map first
|
|
46
46
|
- After /gsd-new-project (greenfield codebases) - updates codebase map as code evolves
|
|
47
47
|
- Anytime to refresh codebase understanding
|
|
48
48
|
</context>
|
|
@@ -51,7 +51,7 @@ Check for .planning/STATE.md - loads context if project already initialized
|
|
|
51
51
|
**Use map-codebase for:**
|
|
52
52
|
- Brownfield projects before initialization (understand existing code first)
|
|
53
53
|
- Refreshing codebase map after significant changes
|
|
54
|
-
-
|
|
54
|
+
- Refreshing or deepening an onboarded codebase map
|
|
55
55
|
- Before major refactoring (understand current state)
|
|
56
56
|
- When STATE.md references outdated codebase info
|
|
57
57
|
|
|
@@ -71,7 +71,7 @@ Check for .planning/STATE.md - loads context if project already initialized
|
|
|
71
71
|
4. Wait for agents to complete, collect confirmations (NOT document contents)
|
|
72
72
|
5. Verify all 7 documents exist with line counts
|
|
73
73
|
6. Commit codebase map
|
|
74
|
-
7. Offer next steps (typically: /gsd-new-project or /gsd-plan-phase)
|
|
74
|
+
7. Offer next steps (typically: /gsd-onboard, /gsd-new-project, or /gsd-plan-phase)
|
|
75
75
|
</process>
|
|
76
76
|
|
|
77
77
|
<success_criteria>
|
|
@@ -14,6 +14,7 @@ inline as part of `gsd-audit-milestone`'s output.
|
|
|
14
14
|
| User wants | Invoke |
|
|
15
15
|
|---|---|
|
|
16
16
|
| Start a new project | gsd-new-project |
|
|
17
|
+
| Onboard an existing codebase | gsd-onboard |
|
|
17
18
|
| Create a new milestone | gsd-new-milestone |
|
|
18
19
|
| Complete the current milestone | gsd-complete-milestone |
|
|
19
20
|
| Audit a milestone for issues | gsd-audit-milestone |
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd-onboard
|
|
3
|
+
description: "Guide existing codebase onboarding through mapping, doc ingest, and planning setup"
|
|
4
|
+
argument-hint: "[--fast] [--text]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Bash
|
|
8
|
+
- Write
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- Agent
|
|
12
|
+
- AskUserQuestion
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<runtime_note>
|
|
16
|
+
**Copilot (VS Code):** Use `vscode_askquestions` wherever this workflow calls `AskUserQuestion`. They are equivalent — `vscode_askquestions` is the VS Code Copilot implementation of the same interactive question API.
|
|
17
|
+
</runtime_note>
|
|
18
|
+
|
|
19
|
+
<objective>
|
|
20
|
+
Guide brownfield onboarding for an existing codebase by routing through the existing GSD primitives in the safe order: codebase map → docs ingest → project initialization → onboarding summary.
|
|
21
|
+
|
|
22
|
+
**Creates or confirms:**
|
|
23
|
+
- `.planning/codebase/` — evidence-backed codebase map from `/gsd-map-codebase`
|
|
24
|
+
- `.planning/PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md` — project setup from `/gsd-new-project` or `/gsd-ingest-docs`
|
|
25
|
+
- `.planning/onboarding/SUMMARY.md` — lightweight index of what was learned and the next command
|
|
26
|
+
|
|
27
|
+
**Non-goals:** This command does not execute phases, ship work, or overwrite existing planning artifacts without an explicit gate.
|
|
28
|
+
</objective>
|
|
29
|
+
|
|
30
|
+
<execution_context>
|
|
31
|
+
@~/.claude/gsd-core/workflows/onboard.md
|
|
32
|
+
@~/.claude/gsd-core/references/ui-brand.md
|
|
33
|
+
@~/.claude/gsd-core/references/gate-prompts.md
|
|
34
|
+
</execution_context>
|
|
35
|
+
|
|
36
|
+
<context>
|
|
37
|
+
Arguments: $ARGUMENTS
|
|
38
|
+
|
|
39
|
+
Flags:
|
|
40
|
+
- `--fast` — prefer `/gsd-map-codebase --fast` for the mapping handoff; the complete map is still required before `/gsd-new-project`.
|
|
41
|
+
- `--text` — use plain-text numbered lists instead of TUI menus.
|
|
42
|
+
</context>
|
|
43
|
+
|
|
44
|
+
<process>
|
|
45
|
+
Execute the onboard workflow end-to-end. Preserve all safety gates, text-mode fallbacks, idempotency checks, and top-level handoff rules for nested interactive commands.
|
|
46
|
+
</process>
|