@stdd/plugin 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/runtime/adapters/README.md +23 -12
- package/runtime/cli/check.mjs +1 -1
- package/runtime/cli/generated-files.mjs +37 -13
- package/runtime/cli/init.mjs +5 -59
- package/runtime/cli/status.mjs +14 -4
- package/runtime/cli/stdd.mjs +2 -21
- package/runtime/method/README.md +63 -13
- package/runtime/method/reference-commands.md +7 -1
- package/runtime/method/reference-integration.md +55 -50
- package/runtime/package.json +1 -1
- package/runtime/playbooks/brainstorming.md +56 -37
- package/runtime/playbooks/delegate-slice.md +7 -1
- package/runtime/playbooks/finish-change.md +10 -3
- package/runtime/playbooks/investigation.md +11 -5
- package/runtime/playbooks/planning.md +5 -1
- package/runtime/playbooks/start-change.md +30 -16
- package/runtime/sdk/adapters.mjs +18 -66
- package/runtime/sdk/index.d.ts +0 -9
- package/runtime/sdk/index.mjs +0 -4
- package/skills/stdd-brainstorming/SKILL.md +56 -37
- package/skills/stdd-debugging/SKILL.md +1 -1
- package/skills/stdd-delegate-slice/SKILL.md +8 -2
- package/skills/stdd-finish-change/SKILL.md +11 -4
- package/skills/stdd-implement/SKILL.md +1 -1
- package/skills/stdd-investigation/SKILL.md +11 -5
- package/skills/stdd-planning/SKILL.md +6 -2
- package/skills/stdd-pr-green/SKILL.md +1 -1
- package/skills/stdd-start-change/SKILL.md +30 -16
- package/skills/stdd-worktrees/SKILL.md +1 -1
- package/runtime/templates/github-stdd.yml +0 -42
- package/runtime/templates/gitlab-stdd.yml +0 -72
|
@@ -71,6 +71,15 @@ syntax when both hosts are selected. The append-system file is user-owned;
|
|
|
71
71
|
init maintains only its marked STDD section and saves the generated source as
|
|
72
72
|
`.stdd/PI-snippet.md`.
|
|
73
73
|
|
|
74
|
+
Every host's managed instructions expose five mandatory routes in native
|
|
75
|
+
syntax: Investigation and Brainstorming are direct read-only routes, Start
|
|
76
|
+
Change is the explicit boundary for persisted or repository-changing action,
|
|
77
|
+
and Implement and Finish Change execute and close that action. The router may
|
|
78
|
+
sequence Investigation → Brainstorming only when unknown current facts
|
|
79
|
+
materially affect future design. It never sends read-only work through Start
|
|
80
|
+
Change or treats ordinary code and docs reading during Brainstorming as a
|
|
81
|
+
separate Investigation.
|
|
82
|
+
|
|
74
83
|
## Adoption modes and the universal bundle
|
|
75
84
|
|
|
76
85
|
STDD has three cumulative adoption modes. **Personal plugin** use installs the
|
|
@@ -79,9 +88,9 @@ repository; its lazy skills remain available, while lifecycle integrations stay
|
|
|
79
88
|
dormant outside a checkout containing `.stdd/`.
|
|
80
89
|
**Shared repository contract** use runs `init` once and commits `.stdd/`, native
|
|
81
90
|
agent routing, and repository policy. **Enforced contract** use explicitly adds
|
|
82
|
-
repository-owned hooks or
|
|
83
|
-
CI reads checkout and review-request facts
|
|
84
|
-
agent state.
|
|
91
|
+
repository-owned hooks, or the two CI commands below to a job the repository
|
|
92
|
+
owns; `init` never creates CI, and CI reads checkout and review-request facts
|
|
93
|
+
rather than the private ledger or agent state.
|
|
85
94
|
|
|
86
95
|
Repo-local generated skills remain a valid team contract and need no plugin.
|
|
87
96
|
The optional universal bundle at `plugins/stdd/` distributes one generated set
|
|
@@ -144,51 +153,45 @@ and do not enumerate either kit or project skills. A local recipe that
|
|
|
144
153
|
reuses a kit playbook's `name` replaces it: project knowledge outranks the kit.
|
|
145
154
|
Local recipe names must otherwise be unique; init rejects duplicates before
|
|
146
155
|
writing generated state and names both conflicting source files.
|
|
147
|
-
The
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
never safe in an untrusted fork pipeline. Authentication failure names the
|
|
187
|
-
required setup instead of pretending fork access is automatic.
|
|
188
|
-
`stdd init --ci generic` writes no provider file; it prints and records the
|
|
189
|
-
portable command contract for teams to compose into Jenkins, Buildkite, or an
|
|
190
|
-
existing pipeline. Provider templates are adapters, never dependencies of
|
|
191
|
-
the method or public SDK.
|
|
156
|
+
The five skills named by that router (`stdd-investigation`,
|
|
157
|
+
`stdd-brainstorming`, `stdd-start-change`, `stdd-implement`, and
|
|
158
|
+
`stdd-finish-change`) are mandatory; init rejects a profile or local override
|
|
159
|
+
that would make one inactive. Other inactive local overrides still shadow
|
|
160
|
+
their kit playbook intentionally.
|
|
161
|
+
|
|
162
|
+
## CI
|
|
163
|
+
|
|
164
|
+
CI is read-only enforcement of checkout and PR facts, composed into whatever
|
|
165
|
+
job the repository already runs. stdd writes no provider configuration: a
|
|
166
|
+
workflow is ordinary infrastructure the team owns, and generating one taught
|
|
167
|
+
nothing the two commands below do not already say. CI never attempts to prove
|
|
168
|
+
the agent's reasoning, consume the ignored ledger, dispatch workers, or mutate
|
|
169
|
+
Git — it grades only facts derivable from the checkout and the review request.
|
|
170
|
+
|
|
171
|
+
The contract is two commands:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
stdd check .
|
|
175
|
+
<live review description> | stdd check-pr - --base <base ref>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Three things a hand-written job has to get right, because they are the part
|
|
179
|
+
that is not obvious:
|
|
180
|
+
|
|
181
|
+
- **Fetch the description live from the provider API.** An event payload is
|
|
182
|
+
frozen at trigger time, so a body-only edit is never re-checked and a re-run
|
|
183
|
+
replays the stale text. On GitHub that means the workflow must not read
|
|
184
|
+
`github.event.pull_request.body`, and must re-run on the `edited` trigger;
|
|
185
|
+
`stdd doctor` reports a workflow that validates the frozen payload — a local
|
|
186
|
+
diagnostic, not part of the `stdd check` gate the job itself runs.
|
|
187
|
+
- **Set `pipefail` on the fetch step.** Otherwise a failed fetch feeds
|
|
188
|
+
`check-pr` an empty body, which misreports as a missing evidence line
|
|
189
|
+
instead of as a fetch error.
|
|
190
|
+
- **Check out full history.** `check-pr --base` diffs against the base ref.
|
|
191
|
+
|
|
192
|
+
`stdd doctor` flags the frozen-payload form, and flags a PR template carrying
|
|
193
|
+
an unquoted evidence label at the start of a line, since its placeholder
|
|
194
|
+
residue would pass the gate on every PR.
|
|
192
195
|
|
|
193
196
|
## Local hooks
|
|
194
197
|
|
|
@@ -222,8 +225,10 @@ re-init removes older managed Claude `PostCompact` entries to avoid running the
|
|
|
222
225
|
ritual twice, while preserving unrelated user hooks. Each integration runs
|
|
223
226
|
`stdd status --local`, which never calls a forge or the network, so every fresh
|
|
224
227
|
context opens with local loop state and the next step already in it — recorded
|
|
225
|
-
state instead of recall.
|
|
226
|
-
|
|
228
|
+
state instead of recall. When that state is idle, the injected human or JSON
|
|
229
|
+
output is neutral: it says that discussion and read-only work require no task
|
|
230
|
+
instead of prompting task creation. Hook entries are merged into existing valid
|
|
231
|
+
files without duplication. A conflicting Pi extension or invalid JSON settings are
|
|
227
232
|
left untouched and a manual instruction is printed instead. Codex hooks and
|
|
228
233
|
Pi project extensions remain subject to their host's repository trust review.
|
|
229
234
|
|
package/runtime/package.json
CHANGED
|
@@ -1,46 +1,65 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stdd-brainstorming
|
|
3
|
-
description:
|
|
4
|
-
when:
|
|
3
|
+
description: Explore future behavior and hypothetical approaches without forcing action
|
|
4
|
+
when: Asked for opinions, ideation, future behavior, or a hypothetical implementation approach, with no explicit intent to persist or modify the repository.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Brainstorming
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
The
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
9
|
+
Use Brainstorming as an adaptive conversational stance, not a fixed interview.
|
|
10
|
+
The goal is useful clarity about **what** and **why** before anyone commits to
|
|
11
|
+
action. Clarity, deciding not to act, and continuing later are all successful
|
|
12
|
+
outcomes.
|
|
13
|
+
|
|
14
|
+
## Contract
|
|
15
|
+
|
|
16
|
+
- Stay read-only: create no task, ledger event, persisted artifact, or
|
|
17
|
+
repository mutation.
|
|
18
|
+
- Ground the discussion in current docs or code when materially useful. If
|
|
19
|
+
unknown current facts materially affect the design, invoke
|
|
20
|
+
`stdd-investigation` first; ordinary reading here is not Investigation.
|
|
21
|
+
- A hypothetical plan shown in chat remains Brainstorming. Explicit intent to
|
|
22
|
+
persist an artifact or modify the repository crosses into Start Change when
|
|
23
|
+
no action boundary is active. Within an active change, do not invoke Start
|
|
24
|
+
Change again; proceed to Planning or Implement as the agreed action requires.
|
|
25
|
+
|
|
26
|
+
## Conversation
|
|
27
|
+
|
|
28
|
+
1. **Understand the real need.** Let the user provide context in their own
|
|
29
|
+
shape. Challenge assumptions and decompose ideas that are larger than the
|
|
30
|
+
need; apply YAGNI rather than rewarding scope.
|
|
31
|
+
2. **Ask only decision-bearing questions.** Ask at most one per turn, and only
|
|
32
|
+
when its answer is needed to proceed. Prefer a concise closed choice when
|
|
33
|
+
the answer space is known. Use a question batch only when the user requests
|
|
34
|
+
one.
|
|
35
|
+
3. **Offer useful alternatives.** Once context is sufficient, present two or
|
|
36
|
+
three materially distinct approaches, state the trade-off that matters, and
|
|
37
|
+
lead with a recommendation. Do not manufacture alternatives when only one
|
|
38
|
+
approach is sensible.
|
|
39
|
+
4. **Validate incrementally.** Check substantive decisions as they emerge
|
|
40
|
+
instead of withholding all validation for a final ceremony. An optional
|
|
41
|
+
recap may state the problem, preferred approach, and unresolved questions.
|
|
42
|
+
|
|
43
|
+
## Outcomes
|
|
44
|
+
|
|
45
|
+
Follow the user's intent without forcing a three-option menu:
|
|
46
|
+
|
|
47
|
+
- **No action:** summarize if useful, then stop. Do not pressure the user to
|
|
48
|
+
formalize or implement anything.
|
|
49
|
+
- **Defer:** leave a portable backlog note in chat. Persist it only when the
|
|
50
|
+
user explicitly chooses a destination; if no action boundary is active,
|
|
51
|
+
invoke `stdd-start-change` before writing it.
|
|
52
|
+
- **Act now:** when the user explicitly chooses persisted or
|
|
53
|
+
repository-changing action, invoke `stdd-start-change` if no action boundary
|
|
54
|
+
is active. Within an active change, proceed directly to Planning or Implement
|
|
55
|
+
as appropriate.
|
|
40
56
|
|
|
41
57
|
## Anti-patterns
|
|
42
58
|
|
|
43
|
-
-
|
|
44
|
-
- Asking
|
|
45
|
-
-
|
|
46
|
-
-
|
|
59
|
+
- Turning exploration into a mandatory interview or checklist.
|
|
60
|
+
- Asking stacked questions when one decision would unlock progress.
|
|
61
|
+
- Jumping into code or artifact creation without explicit action intent.
|
|
62
|
+
- Treating every conversation as a change that must converge on docs, a plan,
|
|
63
|
+
or a PR.
|
|
64
|
+
- Presenting options without an opinion, or inventing options to satisfy a
|
|
65
|
+
quota.
|
|
@@ -19,11 +19,17 @@ compaction, its recorded events do.
|
|
|
19
19
|
sandbox when the worker does not need Git authority:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
|
|
22
|
+
mkdir -p ../.stdd-workers
|
|
23
|
+
stdd worker create ../.stdd-workers/billing \
|
|
23
24
|
--frozen "docs/**,migrations/**" \
|
|
24
25
|
--allowed "src/billing/**,test/billing/**"
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
A sandbox cannot live inside the checkout or inside any Git repository, so
|
|
29
|
+
it goes beside the project — in one hidden container, not as a visible
|
|
30
|
+
sibling per slice. A directory of projects collects one `.stdd-workers/`
|
|
31
|
+
however many slices you delegate, and deleting it removes every sandbox.
|
|
32
|
+
|
|
27
33
|
Use `stdd slice new --frozen ... --allowed ...` only when the worker must
|
|
28
34
|
operate in an existing isolated checkout. `--frozen` names globs the worker
|
|
29
35
|
must not touch. `--allowed` names the only paths it may change. At least one
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stdd-finish-change
|
|
3
|
-
description: Close an implemented change with
|
|
3
|
+
description: Close an implemented change with the review, PR evidence, terminal CI, and runtime verification its delivery boundary requires
|
|
4
4
|
when: Implementation is locally verified and the change is ready for review, delivery, or handoff.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -9,8 +9,10 @@ when: Implementation is locally verified and the change is ready for review, del
|
|
|
9
9
|
Close the current checkout in this order:
|
|
10
10
|
|
|
11
11
|
1. Run the complete affected local verification.
|
|
12
|
-
2. Finish every plan item
|
|
13
|
-
|
|
12
|
+
2. Finish every plan item. Run the independent closing review when the plan
|
|
13
|
+
carries a `[review:]` item or a slice was delegated, and the capability
|
|
14
|
+
profile supports it; a single slice makes no review claim and is not asked
|
|
15
|
+
for one.
|
|
14
16
|
<!-- cap:crossCli -->
|
|
15
17
|
`stdd review --via {{STDD_CROSS_CLI_REVIEW_VIA}}` dispatches the other CLI
|
|
16
18
|
read-only and records the verdict in the ledger.
|
|
@@ -29,6 +31,11 @@ Close the current checkout in this order:
|
|
|
29
31
|
6. Run `stdd task finish` only after the requested delivery boundary is
|
|
30
32
|
actually complete.
|
|
31
33
|
|
|
34
|
+
Steps 3 and 4 apply when that delivery boundary is a PR. A change the user
|
|
35
|
+
asked for as a local edit is complete after step 2 and closes at step 6 —
|
|
36
|
+
opening a PR for it is work nobody requested. Step 5 is not a PR step: any
|
|
37
|
+
delivery carrying a runtime effect gets that verification, PR or not.
|
|
38
|
+
|
|
32
39
|
<!-- cap:subagents|crossCli -->
|
|
33
40
|
An `approved` verdict freezes the checkout. Anything you notice afterwards —
|
|
34
41
|
a stale comment, a better name, one more edge case — is deferred with
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stdd-investigation
|
|
3
|
-
description: Read-only diagnosis — evidence-backed findings, no changes
|
|
4
|
-
when: Asked
|
|
3
|
+
description: Read-only current-state diagnosis — evidence-backed findings, no changes
|
|
4
|
+
when: Asked a factual question about current behavior, or to diagnose or triage it, WITHOUT changing anything.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Investigation
|
|
@@ -13,9 +13,12 @@ it.
|
|
|
13
13
|
|
|
14
14
|
## Contract
|
|
15
15
|
|
|
16
|
-
- No file
|
|
16
|
+
- No task, ledger event, persisted artifact, file edit, or state-changing side
|
|
17
|
+
effect — reads only.
|
|
17
18
|
- Every claim in the report is backed by evidence you actually observed,
|
|
18
19
|
or labeled as unverified with the blocker named.
|
|
20
|
+
- Opinions, future behavior, and hypothetical implementation approaches belong
|
|
21
|
+
in Brainstorming, not Investigation.
|
|
19
22
|
|
|
20
23
|
## Process
|
|
21
24
|
|
|
@@ -29,5 +32,8 @@ it.
|
|
|
29
32
|
you could not test, report as an explicitly unverified hypothesis with
|
|
30
33
|
the blocker that prevented the test.
|
|
31
34
|
3. **Deliver the report**: the diagnosis (or ranked hypotheses) with its
|
|
32
|
-
evidence, the blockers, and the narrowest next step
|
|
33
|
-
|
|
35
|
+
evidence, the blockers, and the narrowest useful next step.
|
|
36
|
+
4. **Hand off only when the prompt needs design.** If unknown current facts
|
|
37
|
+
materially affect requested future behavior, finish the factual diagnosis
|
|
38
|
+
and then invoke `stdd-brainstorming`. Merely reading docs or code during
|
|
39
|
+
Brainstorming does not require a separate Investigation.
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stdd-planning
|
|
3
3
|
description: Turn an agreed behavior contract into an executable, verifiable sequence of work
|
|
4
|
-
when: The behavior contract is agreed (docs edit drafted or committed) and the change is
|
|
4
|
+
when: The behavior contract is agreed (docs edit drafted or committed) and the change is more than one slice — a second independent outcome, an ordering dependency between parts, work to hand to another session, or an unresolved design decision — before the first implementation edit, to fix the execution mode and delivery boundary.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Planning
|
|
8
8
|
|
|
9
|
+
A single-slice change does not come here: it goes straight to
|
|
10
|
+
`stdd-implement`. Planning starts when a second slice appears, which is
|
|
11
|
+
usually mid-work rather than at classification time.
|
|
12
|
+
|
|
9
13
|
A plan is a disposable working artifact: it guides one execution and is thrown
|
|
10
14
|
away. It is never committed as a file — its home is the PR description (for
|
|
11
15
|
the durable summary) and `.stdd/plan.md` (for the working copy: per checkout,
|
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stdd-start-change
|
|
3
|
-
description:
|
|
4
|
-
when:
|
|
3
|
+
description: Open durable task state and route work after explicit intent to persist or modify the repository
|
|
4
|
+
when: The user explicitly wants a persisted work artifact or repository change.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Start change
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- known defect without a diagnosis → invoke `stdd-debugging`;
|
|
16
|
-
- small agreed change → invoke `stdd-implement` directly.
|
|
9
|
+
Start Change is the action boundary. Invoke it only after explicit intent to
|
|
10
|
+
persist a work artifact or modify the repository. Read-only factual diagnosis
|
|
11
|
+
routes directly to `stdd-investigation`; opinions, future behavior, and
|
|
12
|
+
hypothetical implementation approaches route directly to `stdd-brainstorming`.
|
|
13
|
+
Neither needs a task. A hypothetical plan shown only in chat remains
|
|
14
|
+
Brainstorming.
|
|
17
15
|
|
|
18
16
|
Run `stdd policy show` before asking anything: it may already answer which
|
|
19
17
|
agent owns this area, which standing permission covers the work, and what this
|
|
20
18
|
repository treats as routine rather than a decision. Read it through the
|
|
21
19
|
command, never as raw markdown — the command is where the rules are applied.
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
carrying state across prompts:
|
|
21
|
+
Open one task boundary before carrying action state across prompts:
|
|
25
22
|
|
|
26
23
|
```bash
|
|
27
24
|
stdd task start "<short change name>"
|
|
@@ -31,7 +28,24 @@ stdd status --local
|
|
|
31
28
|
If another task is active, do not reset it silently. Finish it, continue it,
|
|
32
29
|
or ask the user which task owns the checkout.
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
Then route. The default is one slice: invoke `stdd-implement` directly. A
|
|
32
|
+
change is one slice when, at the moment of deciding, it has one agreed
|
|
33
|
+
observable outcome, one coherent implementation boundary, one acceptance check,
|
|
34
|
+
and no known dependency on another independently verifiable change.
|
|
35
|
+
|
|
36
|
+
Escalate from that default only on a named trigger:
|
|
37
|
+
|
|
38
|
+
- a second independent outcome or an ordering dependency between parts →
|
|
39
|
+
invoke `stdd-planning`;
|
|
40
|
+
- work to hand to another session → invoke `stdd-planning`, then
|
|
41
|
+
`stdd-delegate-slice`;
|
|
42
|
+
- a design decision nobody has made yet → invoke `stdd-brainstorming` within
|
|
43
|
+
the active change boundary;
|
|
44
|
+
- a known defect without a diagnosis → invoke `stdd-debugging`.
|
|
45
|
+
|
|
46
|
+
Any of them may appear mid-work. Escalating then is the normal case, not a
|
|
47
|
+
failed classification.
|
|
48
|
+
|
|
49
|
+
Read `.stdd/method.md` and the canonical docs governing the touched behavior.
|
|
50
|
+
The classification is a routing decision, not ceremony: skip workflows that do
|
|
51
|
+
not apply, but never skip a mechanical contract that does.
|
package/runtime/sdk/adapters.mjs
CHANGED
|
@@ -3,9 +3,6 @@ import { assertPrintableSingleLine } from "./text.mjs";
|
|
|
3
3
|
|
|
4
4
|
const SEMVER_PATTERN =
|
|
5
5
|
/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
|
|
6
|
-
const CI_STAMP_PLACEHOLDER = "__STAMP__";
|
|
7
|
-
const CI_VERSION_PLACEHOLDER = "__VERSION__";
|
|
8
|
-
const CI_PLACEHOLDER_PATTERN = /__[A-Z][A-Z0-9_]*__/u;
|
|
9
6
|
export const CROSS_CLI_REVIEW_VIA_TOKEN = "{{STDD_CROSS_CLI_REVIEW_VIA}}";
|
|
10
7
|
const CROSS_CLI_REVIEW_VIAS = new Set(["claude", "codex"]);
|
|
11
8
|
|
|
@@ -17,6 +14,8 @@ const deepFreeze = (value) => {
|
|
|
17
14
|
};
|
|
18
15
|
|
|
19
16
|
export const MANDATORY_ROUTING_SKILLS = deepFreeze([
|
|
17
|
+
"stdd-investigation",
|
|
18
|
+
"stdd-brainstorming",
|
|
20
19
|
"stdd-start-change",
|
|
21
20
|
"stdd-implement",
|
|
22
21
|
"stdd-finish-change",
|
|
@@ -90,23 +89,6 @@ export function defineAgentAdapter(adapter) {
|
|
|
90
89
|
return deepFreeze(copy);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
export function defineCiAdapter(adapter) {
|
|
94
|
-
const id = assertSkillName(adapter?.id, "CI adapter id");
|
|
95
|
-
const outputIsNull = adapter?.outputFile === null;
|
|
96
|
-
const templateIsNull = adapter?.templateFile === null;
|
|
97
|
-
if (outputIsNull !== templateIsNull) {
|
|
98
|
-
throw new TypeError("CI adapter outputFile and templateFile must both be null or both be paths");
|
|
99
|
-
}
|
|
100
|
-
const copy = {
|
|
101
|
-
id,
|
|
102
|
-
outputFile: outputIsNull ? null : requireRepoPath(adapter?.outputFile, "CI adapter outputFile"),
|
|
103
|
-
templateFile: templateIsNull
|
|
104
|
-
? null
|
|
105
|
-
: requireRepoPath(adapter?.templateFile, "CI adapter templateFile"),
|
|
106
|
-
};
|
|
107
|
-
return deepFreeze(copy);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
92
|
export const AGENT_ADAPTERS = deepFreeze({
|
|
111
93
|
claude: defineAgentAdapter({
|
|
112
94
|
id: "claude",
|
|
@@ -137,24 +119,6 @@ export const AGENT_ADAPTERS = deepFreeze({
|
|
|
137
119
|
}),
|
|
138
120
|
});
|
|
139
121
|
|
|
140
|
-
export const CI_ADAPTERS = deepFreeze({
|
|
141
|
-
github: defineCiAdapter({
|
|
142
|
-
id: "github",
|
|
143
|
-
outputFile: ".github/workflows/stdd.yml",
|
|
144
|
-
templateFile: "github-stdd.yml",
|
|
145
|
-
}),
|
|
146
|
-
gitlab: defineCiAdapter({
|
|
147
|
-
id: "gitlab",
|
|
148
|
-
outputFile: ".gitlab/stdd.gitlab-ci.yml",
|
|
149
|
-
templateFile: "gitlab-stdd.yml",
|
|
150
|
-
}),
|
|
151
|
-
generic: defineCiAdapter({
|
|
152
|
-
id: "generic",
|
|
153
|
-
outputFile: null,
|
|
154
|
-
templateFile: null,
|
|
155
|
-
}),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
122
|
export function getAgentAdapter(id) {
|
|
159
123
|
if (!Object.hasOwn(AGENT_ADAPTERS, id)) {
|
|
160
124
|
throw new Error(`unknown agent adapter ${JSON.stringify(id)}`);
|
|
@@ -162,13 +126,6 @@ export function getAgentAdapter(id) {
|
|
|
162
126
|
return AGENT_ADAPTERS[id];
|
|
163
127
|
}
|
|
164
128
|
|
|
165
|
-
export function getCiAdapter(id) {
|
|
166
|
-
if (!Object.hasOwn(CI_ADAPTERS, id)) {
|
|
167
|
-
throw new Error(`unknown CI adapter ${JSON.stringify(id)}`);
|
|
168
|
-
}
|
|
169
|
-
return CI_ADAPTERS[id];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
129
|
function resolveAgentAdapter(adapter) {
|
|
173
130
|
return typeof adapter === "string" ? getAgentAdapter(adapter) : defineAgentAdapter(adapter);
|
|
174
131
|
}
|
|
@@ -212,16 +169,27 @@ export function renderAgentInstructions({
|
|
|
212
169
|
throw new TypeError("agent instructions projectLogEnabled must be a boolean");
|
|
213
170
|
}
|
|
214
171
|
const invoke = (name) => `\`${adapter.explicitPrefix}${name}\``;
|
|
215
|
-
const [startChange, implement, finishChange] = MANDATORY_ROUTING_SKILLS;
|
|
172
|
+
const [investigation, brainstorming, startChange, implement, finishChange] = MANDATORY_ROUTING_SKILLS;
|
|
216
173
|
return [
|
|
217
174
|
`<!-- ${safeStamp} -->`,
|
|
218
175
|
"",
|
|
219
176
|
"## STDD",
|
|
220
177
|
"",
|
|
221
|
-
"This repository follows `.stdd/method.md`.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
`
|
|
178
|
+
"This repository follows `.stdd/method.md`. Route read-only current-state",
|
|
179
|
+
`factual or diagnostic questions directly to Investigation with ${invoke(investigation)}.`,
|
|
180
|
+
"Route opinions, future behavior, and hypothetical implementation approaches",
|
|
181
|
+
`directly to Brainstorming with ${invoke(brainstorming)}.`,
|
|
182
|
+
"",
|
|
183
|
+
"Use Investigation → Brainstorming only when unknown current facts materially affect future design.",
|
|
184
|
+
"Reading docs or code during Brainstorming does not by itself require Investigation.",
|
|
185
|
+
"",
|
|
186
|
+
"Start Change is the action boundary. Invoke it only after explicit intent to",
|
|
187
|
+
`persist a work artifact or modify the repository, using ${invoke(startChange)}.`,
|
|
188
|
+
"A hypothetical plan shown only in chat remains Brainstorming.",
|
|
189
|
+
"",
|
|
190
|
+
"Before any repository change (behavior, implementation-only work, fixes, or",
|
|
191
|
+
`refactors), invoke ${invoke(startChange)}; use ${invoke(implement)} for the`,
|
|
192
|
+
`docs/red/green/verify slice and ${invoke(finishChange)} to close it.`,
|
|
225
193
|
"",
|
|
226
194
|
...(projectLogEnabled
|
|
227
195
|
? [
|
|
@@ -261,19 +229,3 @@ export function renderAgentInstructions({
|
|
|
261
229
|
"",
|
|
262
230
|
].join("\n");
|
|
263
231
|
}
|
|
264
|
-
|
|
265
|
-
export function renderCiTemplate(template, { stamp, version }) {
|
|
266
|
-
const safeTemplate = requireString(template, "CI template");
|
|
267
|
-
const safeStamp = assertPrintableSingleLine(stamp, "CI stamp");
|
|
268
|
-
const safeVersion = assertSemanticVersion(version, "CI version");
|
|
269
|
-
if (!safeTemplate.includes(CI_STAMP_PLACEHOLDER) || !safeTemplate.includes(CI_VERSION_PLACEHOLDER)) {
|
|
270
|
-
throw new TypeError("CI template must contain __STAMP__ and __VERSION__ placeholders");
|
|
271
|
-
}
|
|
272
|
-
const rendered = safeTemplate.replace(/__STAMP__|__VERSION__/gu, (placeholder) =>
|
|
273
|
-
placeholder === CI_STAMP_PLACEHOLDER ? safeStamp : safeVersion,
|
|
274
|
-
);
|
|
275
|
-
if (CI_PLACEHOLDER_PATTERN.test(rendered)) {
|
|
276
|
-
throw new TypeError("CI template contains an unresolved placeholder");
|
|
277
|
-
}
|
|
278
|
-
return rendered;
|
|
279
|
-
}
|
package/runtime/sdk/index.d.ts
CHANGED
|
@@ -49,17 +49,9 @@ export interface AgentAdapter {
|
|
|
49
49
|
readonly hooksFile: string;
|
|
50
50
|
readonly crossCliReviewVia?: "codex" | "claude" | null;
|
|
51
51
|
}
|
|
52
|
-
export interface CiAdapter {
|
|
53
|
-
readonly id: string;
|
|
54
|
-
readonly outputFile: string | null;
|
|
55
|
-
readonly templateFile: string | null;
|
|
56
|
-
}
|
|
57
52
|
export const AGENT_ADAPTERS: DeepReadonly<Record<"claude" | "codex" | "pi", AgentAdapter>>;
|
|
58
|
-
export const CI_ADAPTERS: DeepReadonly<Record<"github" | "gitlab" | "generic", CiAdapter>>;
|
|
59
53
|
export function defineAgentAdapter(adapter: AgentAdapter): DeepReadonly<AgentAdapter>;
|
|
60
|
-
export function defineCiAdapter(adapter: CiAdapter): DeepReadonly<CiAdapter>;
|
|
61
54
|
export function getAgentAdapter(id: string): AgentAdapter;
|
|
62
|
-
export function getCiAdapter(id: string): CiAdapter;
|
|
63
55
|
export function renderAgentSkill(input: {
|
|
64
56
|
adapter?: string | AgentAdapter;
|
|
65
57
|
name: string;
|
|
@@ -75,7 +67,6 @@ export function renderAgentInstructions(input: {
|
|
|
75
67
|
crossCli: boolean;
|
|
76
68
|
projectLogEnabled?: boolean;
|
|
77
69
|
}): string;
|
|
78
|
-
export function renderCiTemplate(template: string, input: { stamp: string; version: string }): string;
|
|
79
70
|
export function assertSkillName(name: string, label?: string): string;
|
|
80
71
|
export function isPrintableSingleLine(value: unknown): value is string;
|
|
81
72
|
export function assertPrintableSingleLine(value: unknown, label?: string): string;
|
package/runtime/sdk/index.mjs
CHANGED
|
@@ -12,14 +12,10 @@ export {
|
|
|
12
12
|
} from "../cli/lib.mjs";
|
|
13
13
|
export {
|
|
14
14
|
AGENT_ADAPTERS,
|
|
15
|
-
CI_ADAPTERS,
|
|
16
15
|
defineAgentAdapter,
|
|
17
|
-
defineCiAdapter,
|
|
18
16
|
getAgentAdapter,
|
|
19
|
-
getCiAdapter,
|
|
20
17
|
renderAgentInstructions,
|
|
21
18
|
renderAgentSkill,
|
|
22
|
-
renderCiTemplate,
|
|
23
19
|
} from "./adapters.mjs";
|
|
24
20
|
export { assertSkillName, resolveRepoPath, resolveWritableRepoPath } from "./path.mjs";
|
|
25
21
|
export { assertPrintableSingleLine, isPrintableSingleLine } from "./text.mjs";
|