@mstar-harness/engine 3.6.3 → 3.7.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/dist/audit.d.ts +11 -12
- package/dist/compound.d.ts +10 -10
- package/dist/core.d.ts +2 -3
- package/dist/dispatch.d.ts +57 -64
- package/dist/engine.js +467 -30
- package/dist/index.d.ts +6 -6
- package/dist/iteration.d.ts +3 -3
- package/dist/lint.d.ts +49 -49
- package/dist/migrate.d.ts +22 -22
- package/dist/path.d.ts +35 -25
- package/dist/project.d.ts +24 -26
- package/dist/prreview.d.ts +98 -99
- package/dist/roles.d.ts +22 -12
- package/dist/sdd.d.ts +198 -8
- package/dist/skill-authoring.d.ts +36 -9
- package/dist/status.d.ts +10 -11
- package/dist/store.d.ts +9 -12
- package/dist/workflow.d.ts +11 -11
- package/dist/worktree.d.ts +1 -2
- package/package.json +1 -1
package/dist/prreview.d.ts
CHANGED
|
@@ -57,8 +57,7 @@ export type PrTallyResult = {
|
|
|
57
57
|
*/
|
|
58
58
|
export declare function computePrTally(input: PrTallyInput): PrTallyResult;
|
|
59
59
|
/**
|
|
60
|
-
* One accepted PR-review finding in the `mstar.review/v1` envelope (
|
|
61
|
-
* Schema). `mergeClass` is harness vocab (MERGE_CLASSES); `title`/`body`
|
|
60
|
+
* One accepted PR-review finding in the `mstar.review/v1` envelope (the review envelope schema). `mergeClass` is harness vocab (MERGE_CLASSES); `title`/`body`
|
|
62
61
|
* are non-empty strings; the rest are optional.
|
|
63
62
|
*/
|
|
64
63
|
export type MstarReviewFinding = {
|
|
@@ -72,7 +71,7 @@ export type MstarReviewFinding = {
|
|
|
72
71
|
fingerprint_hint?: string;
|
|
73
72
|
};
|
|
74
73
|
/**
|
|
75
|
-
* The `mstar.review/v1` envelope (
|
|
74
|
+
* The `mstar.review/v1` envelope (the review envelope schema) — a parseable review
|
|
76
75
|
* document with harness vocab, sibling to the Markdown pr-review report.
|
|
77
76
|
* `verdict` is PR_VERDICTS; `tally` (when present) must be a full
|
|
78
77
|
* `PrTallyResult` (shape-checked) whose `verdict` must equal the top-level
|
|
@@ -92,7 +91,7 @@ export type MstarReviewV1 = {
|
|
|
92
91
|
};
|
|
93
92
|
};
|
|
94
93
|
/**
|
|
95
|
-
* Validate a `mstar.review/v1` envelope (
|
|
94
|
+
* Validate a `mstar.review/v1` envelope (the review envelope schema). Fail-loud sibling
|
|
96
95
|
* of {@link validatePrReviewReport} (the Markdown report validator) —
|
|
97
96
|
* shares PR_VERDICTS / MERGE_CLASSES only, never reuses the Markdown
|
|
98
97
|
* parser. Inspector M1 vocab (`comment|request_changes|approve`,
|
|
@@ -108,7 +107,7 @@ export type MstarReviewV1 = {
|
|
|
108
107
|
export declare function validateMstarReviewV1(doc: unknown): GateResult;
|
|
109
108
|
/**
|
|
110
109
|
* Fold already-vetted findings into a complete `mstar.review/v1` envelope
|
|
111
|
-
*
|
|
110
|
+
* . Pure and synchronous — verdict/tally come ONLY
|
|
112
111
|
* from {@link computePrTally}; no I/O, no GitHub, no store, no seat
|
|
113
112
|
* dispatch. `findings` pass through untouched; `target` is carried when
|
|
114
113
|
* provided. When `summary_md` is omitted, {@link defaultReviewSummary}
|
|
@@ -126,11 +125,11 @@ export declare function synthesizeReview(input: {
|
|
|
126
125
|
*
|
|
127
126
|
* - `pr` — reviewed PR number `n`.
|
|
128
127
|
* - `branch` — bare branch, `slug` is the pre-slugged `<branch-slug>`
|
|
129
|
-
*
|
|
128
|
+
* (caller slugs; the resolver only guards path safety).
|
|
130
129
|
* - `diff` — arbitrary changeset. When `headSha` is a non-empty string its
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
130
|
+
* short form (first 7 hex chars) lands in the filename; when absent or an
|
|
131
|
+
* empty string the bare `-diff` stem is used — a missing SHA is **never
|
|
132
|
+
* fabricated** (pr-review.md § Local report archive, Filename bullet).
|
|
134
133
|
*/
|
|
135
134
|
export type PrReportTarget = {
|
|
136
135
|
kind: "pr";
|
|
@@ -148,16 +147,16 @@ export type PrReportTarget = {
|
|
|
148
147
|
* never writes and never overwrites):
|
|
149
148
|
*
|
|
150
149
|
* - `<YYYY-MM-DD>-pr<N>.md` for PR targets; bare branch →
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
150
|
+
* `<YYYY-MM-DD>-<branch-slug>.md`; diff with head SHA →
|
|
151
|
+
* `<YYYY-MM-DD>-diff-<short-head-sha>.md`; diff without →
|
|
152
|
+
* `<YYYY-MM-DD>-diff.md` (never fabricate a SHA).
|
|
154
153
|
* - `stage: 1 | 2` requires `slug` (the seat Assignment's `<domain>-<seat>`
|
|
155
|
-
*
|
|
156
|
-
*
|
|
154
|
+
* slug) and produces the Stage 1/2 evidence-file stem
|
|
155
|
+
* `<stem>-stage<1|2>-<slug>.md`.
|
|
157
156
|
* - Same day, same target (same final stem): scans ALL existing files in
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
157
|
+
* `reportsDir` with that stem and appends `-r2`, `-r3`, ... on collision —
|
|
158
|
+
* a prior report is never overwritten. Report files and evidence files
|
|
159
|
+
* escalate independently (different stems).
|
|
161
160
|
* - `date` defaults to the local calendar date and must be `YYYY-MM-DD`.
|
|
162
161
|
*/
|
|
163
162
|
export declare function prReviewReportPath(opts: {
|
|
@@ -174,22 +173,22 @@ export declare function prReviewReportPath(opts: {
|
|
|
174
173
|
*
|
|
175
174
|
* - `type: pr-review` required.
|
|
176
175
|
* - `verdict` exactly one of the three verdict tokens (§ Verdict synthesis)
|
|
177
|
-
*
|
|
178
|
-
*
|
|
176
|
+
* and CONSISTENT with the tally (any must_fix -> blocked; else any
|
|
177
|
+
* should_fix -> needs fixes; else ship it).
|
|
179
178
|
* - `score_pct` integer 0-100 and equal to the locked-formula recompute
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
179
|
+
* from the document's own tally via {@link computePrTally}
|
|
180
|
+
* (mismatch = hand-arithmetic drift — the exact defect class this gate
|
|
181
|
+
* exists to catch).
|
|
183
182
|
* - `tally` flow map with the four classes.
|
|
184
183
|
* - `comments` tri-state: `posted` (alias `yes`) | `n/a-no-pr` | `failed`.
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
184
|
+
* The states are distinct: a FAILED POST IS `FAILED`, never
|
|
185
|
+
* `n/a-no-pr`; `review_url` must pair accordingly (`http(s)://` for
|
|
186
|
+
* posted, `n/a` for n/a-no-pr, a `failed: <gh error summary>` for failed).
|
|
188
187
|
* - `generated_at` must be `YYYY-MM-DD` (DATE_RE).
|
|
189
188
|
* - `tier` optional: `quick | default | deep`; absent is valid (legacy
|
|
190
|
-
*
|
|
189
|
+
* reports without tier still pass — SP-A amendment).
|
|
191
190
|
* - `elapsed` optional: non-negative integer minutes; absent is valid
|
|
192
|
-
*
|
|
191
|
+
* (legacy reports without elapsed still pass).
|
|
193
192
|
*/
|
|
194
193
|
export declare function validatePrReviewReport(text: string): GateResult;
|
|
195
194
|
/** One inline review comment: `path` + `line` in the three-dot diff, RIGHT
|
|
@@ -221,14 +220,14 @@ export type ReviewPostPlan = {
|
|
|
221
220
|
* 422 fallback stay with the CLI, which owns the network):
|
|
222
221
|
*
|
|
223
222
|
* - Resolves the target from `gh pr view --json url,headRefOid` output:
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
223
|
+
* parse `owner/repo` from `url` ONLY — the BASE repo that owns the PR
|
|
224
|
+
* number. `headRepository` (fork head-repo data) is IGNORED: fork PRs
|
|
225
|
+
* are legal, and a fork's owner/name must never leak into the API path.
|
|
226
|
+
* It is never used as a fallback either.
|
|
228
227
|
* - Missing/invalid `headRefOid` throws — there is no commit_id without
|
|
229
|
-
*
|
|
228
|
+
* it.
|
|
230
229
|
* - `event` is always the literal `"COMMENT"`; no other value exists in
|
|
231
|
-
*
|
|
230
|
+
* this contract.
|
|
232
231
|
* - Inline comments validated per-entry (path / positive line / RIGHT).
|
|
233
232
|
*/
|
|
234
233
|
export declare function planReviewPost(prView: {
|
|
@@ -256,13 +255,13 @@ export type ReviewChangesetMode = "pr" | "branch" | "diff" | "working-tree" | "c
|
|
|
256
255
|
* (pr-review.md § Worktree isolation Pre-flight bullet, all modes):
|
|
257
256
|
*
|
|
258
257
|
* - Named refs must resolve in modes that HAVE refs (pr / branch / commit);
|
|
259
|
-
*
|
|
258
|
+
* establish them with explicit refspecs first.
|
|
260
259
|
* - The changeset must be NON-empty in ALL modes — an empty changeset
|
|
261
|
-
*
|
|
260
|
+
* reports "no changes to review" and stops before any lens fan-out.
|
|
262
261
|
* - For working-tree input, untracked-only changes ARE a non-empty
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
262
|
+
* changeset: the caller folds `git ls-files --others
|
|
263
|
+
* --exclude-standard` output into `changesetEmpty: false` when anything
|
|
264
|
+
* is listed.
|
|
266
265
|
*/
|
|
267
266
|
export declare function preflightChangeset(mode: ReviewChangesetMode, probe: {
|
|
268
267
|
refsResolve: boolean;
|
|
@@ -277,12 +276,12 @@ export type PrReviewSizing = {
|
|
|
277
276
|
/** True for too-large (>~1000) — advise a split, never auto-blocked. */
|
|
278
277
|
adviseSplit: boolean;
|
|
279
278
|
/** Stage 1 collect seats (§ Scale-driven fan-out table). Kept-wave
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
* qualifier: these seats apply only when the deep collect wave is KEPT —
|
|
280
|
+
* by default (pinned diff pack present) the fold dispatches none
|
|
281
|
+
* (pr-review.md § Review pipeline fold default). */
|
|
283
282
|
collectSeats: 2 | 3;
|
|
284
283
|
/** File-size watch fired → advise extract/decompose ("decompose, then
|
|
285
|
-
|
|
284
|
+
* add"). Independent of the diff size. */
|
|
286
285
|
fileDecomposeAdvice: boolean;
|
|
287
286
|
};
|
|
288
287
|
/**
|
|
@@ -290,13 +289,13 @@ export type PrReviewSizing = {
|
|
|
290
289
|
* (pr-review.md § Sizing & change shape + § Scale-driven fan-out):
|
|
291
290
|
*
|
|
292
291
|
* - ≤~300 reviewable/acceptable → band `small`; >~300 → `large`;
|
|
293
|
-
*
|
|
294
|
-
*
|
|
292
|
+
* >~1000 → `too-large` + split advice (a should-fix finding with split
|
|
293
|
+
* advice or a verdict note — never auto-`blocked`).
|
|
295
294
|
* - Stage 1 collect seats: small → 2 (code + security); large/too-large →
|
|
296
|
-
*
|
|
295
|
+
* 3 by domain.
|
|
297
296
|
* - `largestTouchedFileTotal` drives `fileDecomposeAdvice` INDEPENDENTLY
|
|
298
|
-
*
|
|
299
|
-
*
|
|
297
|
+
* of the diff size — a small diff materially growing a file past ~1000
|
|
298
|
+
* total lines gets "decompose, then add".
|
|
300
299
|
*/
|
|
301
300
|
export declare function prReviewSizing(input: {
|
|
302
301
|
changedLines: number;
|
|
@@ -310,23 +309,23 @@ export declare function prReviewSizing(input: {
|
|
|
310
309
|
* includes everything. */
|
|
311
310
|
export type PrReviewTier = "quick" | "default" | "deep";
|
|
312
311
|
/**
|
|
313
|
-
* Per-tier time budget for the `amazing-pr-review` pipeline (
|
|
312
|
+
* Per-tier time budget for the `amazing-pr-review` pipeline (tier
|
|
314
313
|
* time-budget). Prose SSOT: pr-review.md § Review depth — its Budget column
|
|
315
314
|
* carries the wall-clock minutes; the per-seat caps below are the engine
|
|
316
315
|
* contract, rendered into seat prompts, never duplicated as numbers in prose.
|
|
317
316
|
*
|
|
318
317
|
* - `wallClockMinutes`: prompt-discipline target for the whole review,
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
318
|
+
* measured worktree-setup → local report saved by the main agent.
|
|
319
|
+
* Overruns are declared in the report `- notes:` — budgets are never a
|
|
320
|
+
* host-level hard kill.
|
|
322
321
|
* - `maxSeats`: review seats only — Stage 2 domain seats + the independent
|
|
323
|
-
*
|
|
324
|
-
*
|
|
322
|
+
* cross-domain security seat; NOT Stage 1 collect seats (collect fan-out
|
|
323
|
+
* stays governed by pr-review.md § Scale-driven fan-out).
|
|
325
324
|
* - `perSeatFindingsCap` / `evidenceTokensCap` / `fileOpenCap`: per-seat
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
325
|
+
* expansion stops (findings / evidence payload tokens / file opens; the
|
|
326
|
+
* pinned diff snapshot read does not count). Baseline assumption: 100
|
|
327
|
+
* tok/s output — wall-clock is dominated by reads/tool latency, which
|
|
328
|
+
* `fileOpenCap` bounds.
|
|
330
329
|
*
|
|
331
330
|
* No new sizing bands: the table references tiers only (pr-review.md
|
|
332
331
|
* § Sizing & change shape stays the only sizing SSOT). */
|
|
@@ -349,18 +348,18 @@ export type PrReviewSeatPromptOptions = {
|
|
|
349
348
|
securitySeat?: boolean;
|
|
350
349
|
tier?: PrReviewTier;
|
|
351
350
|
/** Absolute path to the pinned diff snapshot written by `worktree-setup`
|
|
352
|
-
|
|
353
|
-
|
|
351
|
+
* (review artifact beside the sidecar). Non-empty → the prompt gains a
|
|
352
|
+
* read-first ingredient line pointing at it. */
|
|
354
353
|
diffFile?: string;
|
|
355
354
|
/** Stage-2 only (`true` + `stage: 1` throws): the collect wave was folded
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
355
|
+
* onto this domain seat — the deep-tier fold default (pinned diff pack
|
|
356
|
+
* present; SSOT pr-review.md § Review pipeline; prose "collection folded
|
|
357
|
+
* in = seat reuse" = § Review depth default-tier row). Kept-wave
|
|
358
|
+
* exceptions dispatch collect seats instead. Requires a non-empty
|
|
359
|
+
* `diffFile`, and the independent cross-domain security seat is never
|
|
360
|
+
* folded — either contradiction throws. The prompt gains one bullet after
|
|
361
|
+
* the `## Budget` block telling the seat to do its own collection, staying
|
|
362
|
+
* within the budget block. Omitted/`false` → no line. */
|
|
364
363
|
collectFolded?: boolean;
|
|
365
364
|
};
|
|
366
365
|
/**
|
|
@@ -370,30 +369,30 @@ export type PrReviewSeatPromptOptions = {
|
|
|
370
369
|
* Ingredients:
|
|
371
370
|
*
|
|
372
371
|
* - Absolute path to `references/pr-review.md` under `skillRoot` + the
|
|
373
|
-
*
|
|
374
|
-
* - Per-seat budget block (`## Budget`,
|
|
375
|
-
*
|
|
376
|
-
*
|
|
372
|
+
* sections to read; absolute review `worktreePath`.
|
|
373
|
+
* - Per-seat budget block (`## Budget`, tier time budget): findings /
|
|
374
|
+
* evidence-token / file-open caps interpolated from `PR_REVIEW_TIER_BUDGETS`
|
|
375
|
+
* — expansion stops for the seat, never a host-level hard stop.
|
|
377
376
|
* - `collectFolded: true` (stage 2 only; stage 1, a missing `diffFile`, or
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
377
|
+
* the security seat throws): one bullet after the `## Budget` block — the
|
|
378
|
+
* collect wave folded onto this seat, so it collects itself (pinned diff
|
|
379
|
+
* snapshot/pack first, then in-domain changed files) within the budget
|
|
380
|
+
* block.
|
|
382
381
|
* - Recon facts + decided tradeoffs.
|
|
383
382
|
* - Hard Rules 4/5 VERBATIM.
|
|
384
383
|
* - Payload-return contract (write-blocked-safe; main agent writes files).
|
|
385
384
|
* - No-verdict / never-post clauses.
|
|
386
385
|
* - Slug mandate `<domain>-<seat>`.
|
|
387
386
|
* - Stage 2 adds finding-format.md (+ security-review.md for security
|
|
388
|
-
*
|
|
387
|
+
* seats) and the Merge-class instruction.
|
|
389
388
|
* - Tier cuts (SP-A amendment): quick drops the cross-domain /
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
389
|
+
* independent-security block, the collect-wave wording AND shrinks the
|
|
390
|
+
* lens/prompt-ingredient set; default drops the same blocks (SSOT
|
|
391
|
+
* pr-review.md § Review depth, default-tier row: "collection folded in =
|
|
392
|
+
* seat reuse" — no separate Stage-1 wave, so collect-wave wording is
|
|
393
|
+
* deep-only); deep keeps everything.
|
|
394
|
+
* Tier omitted → `default` (pr-review.md § Review depth: the no-flag
|
|
395
|
+
* landing tier).
|
|
397
396
|
*/
|
|
398
397
|
export declare function prReviewSeatPrompt(opts: PrReviewSeatPromptOptions): string;
|
|
399
398
|
/** Options for {@link validateFindingDoc}: `prVariant` gates the Merge
|
|
@@ -407,18 +406,18 @@ export type ValidateFindingDocOptions = {
|
|
|
407
406
|
* PR-only Merge class contract (pr-review.md § Merge class):
|
|
408
407
|
*
|
|
409
408
|
* - Every finding opens with `### [CATEGORY-NN] Title`; CATEGORY ∈
|
|
410
|
-
*
|
|
411
|
-
*
|
|
409
|
+
* `AUDIT_CATEGORIES` (case-insensitive read, canonical uppercase forms
|
|
410
|
+
* per category codes), NN numeric.
|
|
412
411
|
* - Required fields: Evidence / Impact / Effort / Risk / Confidence —
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
412
|
+
* Effort / Risk / Confidence each validated as their LEADING token
|
|
413
|
+
* (Effort via `AUDIT_EFFORTS`, Risk via `AUDIT_RISKS`, Confidence via
|
|
414
|
+
* HIGH | MED | LOW with `MEDIUM` tolerated as the MED alias); free-text
|
|
415
|
+
* gloss after a separator is allowed and ignored.
|
|
417
416
|
* - Each Evidence citation matches `path:line` (`\S+:\d+` — the path may
|
|
418
|
-
*
|
|
417
|
+
* but need not carry an extension).
|
|
419
418
|
* - `prVariant` (default false): every finding additionally carries
|
|
420
|
-
*
|
|
421
|
-
*
|
|
419
|
+
* **Merge class** ∈ {must-fix, should-fix, nit} placed IMMEDIATELY after
|
|
420
|
+
* Confidence.
|
|
422
421
|
*/
|
|
423
422
|
export declare function validateFindingDoc(text: string, opts?: ValidateFindingDocOptions): GateResult;
|
|
424
423
|
/** Tier keywords the CLI may have matched from argv — the three explicit
|
|
@@ -441,16 +440,16 @@ export type ResolvePrReviewTierInput = {
|
|
|
441
440
|
* (SP-A amendment; first hit wins):
|
|
442
441
|
*
|
|
443
442
|
* 1. Explicit keyword → that tier (user intent beats heuristics; a lone
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
443
|
+
* `default` returns `default` BEFORE the band/sensitive heuristics).
|
|
444
|
+
* Any two DISTINCT keywords (quick / default / deep) → hard-stop
|
|
445
|
+
* conflict error — never silently take a priority. (Empty/omitted =
|
|
446
|
+
* no flag.)
|
|
448
447
|
* 2. Too large (>~1000 / band too-large) → advise split; review anyway →
|
|
449
|
-
*
|
|
448
|
+
* deep.
|
|
450
449
|
* 3. Sensitive surface (auth / LLM / supply chain / data) → deep at any
|
|
451
|
-
*
|
|
450
|
+
* size.
|
|
452
451
|
* 4. Large (>~300 / band large) → deep.
|
|
453
452
|
* 5. Small: tiny-mechanical shape (docs-only / rename / formatting / pure
|
|
454
|
-
*
|
|
453
|
+
* deletion) → quick; anything else (real code change) → default.
|
|
455
454
|
*/
|
|
456
455
|
export declare function resolvePrReviewTier(input: ResolvePrReviewTierInput): PrReviewTier;
|
package/dist/roles.d.ts
CHANGED
|
@@ -47,14 +47,14 @@ export type RoleMappingOptions = {
|
|
|
47
47
|
* layout (mstar-roles § Role Reference Mapping / § Parameter Table (SSOT)
|
|
48
48
|
* / § Maintenance Rules):
|
|
49
49
|
* - every mapped agent id resolves to `references/<role>.md` under
|
|
50
|
-
*
|
|
50
|
+
* `rolesDir`;
|
|
51
51
|
* - shared families (`fullstack-dev*`, `qc-specialist*`) resolve to ONE
|
|
52
|
-
*
|
|
52
|
+
* shared reference file each;
|
|
53
53
|
* - every parameter row references a mapped role, exactly once;
|
|
54
54
|
* - dev track values are `primary` / `parallel_secondary`;
|
|
55
55
|
* - the QC parameter table contract holds: reviewer_index is exactly
|
|
56
|
-
*
|
|
57
|
-
*
|
|
56
|
+
* {1, 2, 3} across the three seats, each seat has a focus, and
|
|
57
|
+
* `report_suffix === qc<reviewer_index>`.
|
|
58
58
|
*
|
|
59
59
|
* Violations:
|
|
60
60
|
* - `roles.mapping.reference.missing` — mapped reference file not on disk
|
|
@@ -70,18 +70,28 @@ export type RoleMappingOptions = {
|
|
|
70
70
|
export declare function validateRoleMapping(rolesDir: string, options?: RoleMappingOptions): GateResult;
|
|
71
71
|
/**
|
|
72
72
|
* Lint load-order declarations across skill texts (mstar-harness-core
|
|
73
|
-
* §
|
|
74
|
-
*
|
|
75
|
-
* First action section).
|
|
73
|
+
* § 与其它 `mstar-*` skill 的加载契约 + mstar-roles § Load Order; Spec A2 —
|
|
74
|
+
* single load-selection authority).
|
|
76
75
|
*
|
|
77
76
|
* Input: `skillTexts` maps skill name → full SKILL.md text. `mstar-harness-
|
|
78
|
-
* core` itself and non-`mstar-*` skills are exempt.
|
|
79
|
-
*
|
|
80
|
-
* `mstar
|
|
81
|
-
*
|
|
77
|
+
* core` itself and non-`mstar-*` skills are exempt.
|
|
78
|
+
*
|
|
79
|
+
* - Every `mstar-*` topic skill (reached by direct invocation) must have a
|
|
80
|
+
* Load Order / First action section (heading Load Order / Load order /
|
|
81
|
+
* First action) that names `mstar-harness-core` as its first dependency
|
|
82
|
+
* (mentions in later sections do not count).
|
|
83
|
+
* - The `mstar-roles` hub bootstrap is the ONE exception (narrow, keyed on
|
|
84
|
+
* the skill name — broad exemptions are rejected): it does not declare
|
|
85
|
+
* core-first; instead its Load Order section must declare the preset
|
|
86
|
+
* decision matrix (`roles.loadorder.hub.bootstrap.missing` when tokens
|
|
87
|
+
* are missing) and keep the conditional `mstar-harness-core`
|
|
88
|
+
* conflict-authority pointer (`roles.loadorder.core.missing`).
|
|
82
89
|
*
|
|
83
90
|
* Violations:
|
|
84
91
|
* - `roles.loadorder.section.missing` — no Load Order / First action section
|
|
85
|
-
* - `roles.loadorder.core.missing` — section
|
|
92
|
+
* - `roles.loadorder.core.missing` — topic section without the core-first
|
|
93
|
+
* declaration, or hub section without the core conflict-authority pointer
|
|
94
|
+
* - `roles.loadorder.hub.bootstrap.missing` — hub section missing the
|
|
95
|
+
* identity→none/standard/methods/unknown-preset decision matrix
|
|
86
96
|
*/
|
|
87
97
|
export declare function lintLoadOrder(skillTexts: Record<string, string>): GateResult;
|
package/dist/sdd.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type GateResult } from "./core.js";
|
|
1
2
|
/**
|
|
2
3
|
* Error carrying the ported script exit code so the CLI can map validation
|
|
3
4
|
* failures to identical non-zero exits.
|
|
@@ -18,17 +19,41 @@ export type SddWorkspaceOptions = {
|
|
|
18
19
|
/** Working directory for git probes; default `process.cwd()`. */
|
|
19
20
|
cwd?: string;
|
|
20
21
|
};
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Options for `taskBrief` (mirrors `$SDD_DIR` for the default out path).
|
|
24
|
+
*
|
|
25
|
+
* Bound mode (spec A3): passing
|
|
26
|
+
* `context` makes the destination an artifact gate check (before any
|
|
27
|
+
* mkdir/write), defaults the destination to `{context.sddDir}/task-N-brief.md`
|
|
28
|
+
* and returns/emits an absolute path. Without `context` the legacy helper
|
|
29
|
+
* stays explicitly UNBOUND — a context-less call has no protection claim
|
|
30
|
+
* (A3: "context-less legacy helper calls remain explicitly unbound").
|
|
31
|
+
*/
|
|
22
32
|
export type TaskBriefOptions = {
|
|
23
33
|
sddDir?: string;
|
|
34
|
+
/** Resolved SDD execution context — binds the artifact write (A3). */
|
|
35
|
+
context?: SddExecutionContext;
|
|
36
|
+
/** Observed invocation cwd for the artifact gate; default `process.cwd()`. */
|
|
37
|
+
cwd?: string;
|
|
24
38
|
};
|
|
25
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Options for `reviewPackage` (mirrors `$SDD_DIR` + git probe cwd).
|
|
41
|
+
*
|
|
42
|
+
* Bound mode (spec A3): passing `context` makes the destination an artifact
|
|
43
|
+
* gate check (before any mkdir/write), defaults the git probe cwd to the
|
|
44
|
+
* context's feature worktree ("feature Git cwd, control artifact out") and
|
|
45
|
+
* returns/emits an absolute path. Without `context` the legacy helper stays
|
|
46
|
+
* explicitly UNBOUND — no protection claim.
|
|
47
|
+
*/
|
|
26
48
|
export type ReviewPackageOptions = {
|
|
27
49
|
sddDir?: string;
|
|
50
|
+
/** Git probe cwd; bound mode defaults to `context.featureCwd`. */
|
|
28
51
|
cwd?: string;
|
|
52
|
+
/** Resolved SDD execution context — binds the artifact write (A3). */
|
|
53
|
+
context?: SddExecutionContext;
|
|
29
54
|
};
|
|
30
55
|
/**
|
|
31
|
-
* Git capture ceiling for `gitOut` / `reviewPackage`
|
|
56
|
+
* Git capture ceiling for `gitOut` / `reviewPackage` : Node's
|
|
32
57
|
* default 1 MiB `maxBuffer` ENOBUFS'd on large review ranges. 64 MiB keeps
|
|
33
58
|
* realistic iteration-close ranges working while bounding memory; captures
|
|
34
59
|
* beyond that fail as SddScriptError via the CLI.
|
|
@@ -39,13 +64,13 @@ export declare const GIT_CAPTURE_MAX_BYTES: number;
|
|
|
39
64
|
* the absolute path). Resolution order:
|
|
40
65
|
*
|
|
41
66
|
* 1. fail-closed FIRST: a linked worktree without a control root never
|
|
42
|
-
*
|
|
43
|
-
*
|
|
67
|
+
* resolves or creates any SDD tree under the feature checkout (refuses a
|
|
68
|
+
* second SDD tree; no override or probe may bypass this guard);
|
|
44
69
|
* 2. explicit harness-root override (`opts.harnessDir` / `MSTAR_HARNESS_DIR`)
|
|
45
|
-
*
|
|
46
|
-
*
|
|
70
|
+
* — plan finding 2026-08-08: covers repos the status.json probe misses;
|
|
71
|
+
* resolved relative to the established root;
|
|
47
72
|
* 3. `.mstarc` `[config] harness_dir` at `root` (repo-declared root;
|
|
48
|
-
*
|
|
73
|
+
* resolved against the config file's directory);
|
|
49
74
|
* 4. `status.json` probe at root (`.mstar` → `.agents`);
|
|
50
75
|
* 5. fallback: existing `.mstar`/`.agents` dir, else `.mstar`.
|
|
51
76
|
*
|
|
@@ -61,6 +86,14 @@ export declare function sddWorkspace(planId: string, opts?: SddWorkspaceOptions)
|
|
|
61
86
|
* EOF for the last task) — a later Task heading resets the section. A
|
|
62
87
|
* missing task writes an empty file then fails with exit-3
|
|
63
88
|
* (`SddScriptError.exitCode === 3`).
|
|
89
|
+
*
|
|
90
|
+
* Bound mode (`opts.context`, spec A3): the artifact destination is gated
|
|
91
|
+
* with `checkSddAction` BEFORE any mkdir/write — a refused destination
|
|
92
|
+
* writes nothing — and the returned path is absolute. The INPUT is bound
|
|
93
|
+
* too: the plan file must canonicalize to the context's `planFile`, and a
|
|
94
|
+
* mismatch is refused (exit 1) before any read or write — a foreign plan's
|
|
95
|
+
* content must never land in this plan's SDD dir. Context-less calls
|
|
96
|
+
* keep the legacy unbound behavior (no protection claim).
|
|
64
97
|
*/
|
|
65
98
|
export declare function taskBrief(planFile: string, taskN: number, outFile?: string, opts?: TaskBriefOptions): string;
|
|
66
99
|
/**
|
|
@@ -69,6 +102,14 @@ export declare function taskBrief(planFile: string, taskN: number, outFile?: str
|
|
|
69
102
|
* Both refs are validated with `git rev-parse --verify --quiet` (any ref
|
|
70
103
|
* the original accepted is accepted here; the SHA-only guard is
|
|
71
104
|
* `assertBaseSha`).
|
|
105
|
+
*
|
|
106
|
+
* Bound mode (`opts.context`, spec A3): the review range is probed in the
|
|
107
|
+
* context's feature worktree (feature Git cwd) while the package lands in
|
|
108
|
+
* the plan's control artifacts — gated with `checkSddAction` BEFORE any
|
|
109
|
+
* mkdir/write (a refused destination writes nothing). The returned path is
|
|
110
|
+
* absolute. Context-less calls keep the legacy unbound behavior (no
|
|
111
|
+
* protection claim); an explicit `opts.cwd` still overrides the git probe
|
|
112
|
+
* cwd in both modes.
|
|
72
113
|
*/
|
|
73
114
|
export declare function reviewPackage(base: string, head: string, outFile?: string, opts?: ReviewPackageOptions): string;
|
|
74
115
|
/**
|
|
@@ -130,3 +171,152 @@ export type StickyRulesResult = {
|
|
|
130
171
|
* resume — that rule lives in the PM flow, not the session ledger.
|
|
131
172
|
*/
|
|
132
173
|
export declare function implementerSessionStickyRules(input: StickyRulesInput): StickyRulesResult;
|
|
174
|
+
/**
|
|
175
|
+
* Resolved SDD execution context (spec A3): where control artifacts live,
|
|
176
|
+
* where feature source edits happen, and which branch the feature checkout
|
|
177
|
+
* must be on. All paths normalized absolute (canonicalized on resolve);
|
|
178
|
+
* `planFile` / `sddDir` must resolve within the control harness and match
|
|
179
|
+
* `planId`; the feature branch/worktree must match the verified lease when
|
|
180
|
+
* an active workflow supplies one (standalone non-iteration contexts remain
|
|
181
|
+
* possible under the existing branch policy — no new global lease mandate).
|
|
182
|
+
* A declared control root is authoritative: it is never re-inferred from
|
|
183
|
+
* the feature cwd (mstar-branch-worktree «Harness path SSOT»).
|
|
184
|
+
*/
|
|
185
|
+
export type SddExecutionContext = {
|
|
186
|
+
planId: string;
|
|
187
|
+
/** Control harness dir (`<control-worktree>/{HARNESS_DIR}`), absolute. */
|
|
188
|
+
controlHarnessRoot: string;
|
|
189
|
+
/** Feature worktree — the required cwd for product/source edits, absolute. */
|
|
190
|
+
featureCwd: string;
|
|
191
|
+
/** Assignment Working branch checked out at `featureCwd`. */
|
|
192
|
+
workingBranch: string;
|
|
193
|
+
/** Control plan file (`{PLAN_DIR}/<plan-id>.md`), absolute. */
|
|
194
|
+
planFile: string;
|
|
195
|
+
/** Control `{SDD_DIR}` = `{HARNESS_DIR}/sdd/<plan-id>/`, absolute. */
|
|
196
|
+
sddDir: string;
|
|
197
|
+
};
|
|
198
|
+
/** One action seam to gate with `checkSddAction` (spec A3). */
|
|
199
|
+
export type SddAction = {
|
|
200
|
+
/**
|
|
201
|
+
* Observed invocation cwd — the real cwd at the seam, never an Assignment
|
|
202
|
+
* echo. Relative `target` values resolve from this cwd.
|
|
203
|
+
*/
|
|
204
|
+
cwd: string;
|
|
205
|
+
/** Path the action would touch; optional for source/launch, required for artifact. */
|
|
206
|
+
target?: string;
|
|
207
|
+
kind: SddActionKind;
|
|
208
|
+
};
|
|
209
|
+
/** Action seam kinds (spec A3): feature source write, control artifact write, child-process launch. */
|
|
210
|
+
export type SddActionKind = "source" | "artifact" | "launch";
|
|
211
|
+
/**
|
|
212
|
+
* Resolve and validate a declared SDD execution context (spec A3) into a
|
|
213
|
+
* canonical context. Read-only — resolves/validates, never writes.
|
|
214
|
+
*
|
|
215
|
+
* Validation (reusing the existing machinery — never duplicated here):
|
|
216
|
+
* - shape: all paths absolute, `planId` a single safe path component
|
|
217
|
+
* (`assertSafePathComponent`);
|
|
218
|
+
* - `controlHarnessRoot` exists (declared root is authoritative — never
|
|
219
|
+
* re-inferred from the feature cwd);
|
|
220
|
+
* - `planFile` identity (basename stem = `planId`) + placement via
|
|
221
|
+
* `assertPlanWritingPath` (inside `{PLAN_DIR}` of the control harness,
|
|
222
|
+
* symlink escape checked against the canonical path);
|
|
223
|
+
* - `sddDir` canonicalizes (nearest existing ancestor on BOTH sides) to the
|
|
224
|
+
* same path as `resolveSddDir(controlHarnessRoot, planId)` — the path
|
|
225
|
+
* SSOT composition, `.mstarc` overrides included; equivalent string forms
|
|
226
|
+
* of one physical destination are valid. Composition equality on the
|
|
227
|
+
* canonical pair subsumes the escape case — a declared sddDir cannot
|
|
228
|
+
* equal the canonical composition and escape at the same time — so
|
|
229
|
+
* divergence is classified at one decision point: divergence because the
|
|
230
|
+
* declared path physically canonicalizes OUTSIDE the control harness
|
|
231
|
+
* (symlinked sdd segment routing out) is environmental →
|
|
232
|
+
* `sdd.context.sdd-dir-escape` gate fail (exit 1); any other divergence
|
|
233
|
+
* (wrong declaration) is usage (exit 2). A context matching a
|
|
234
|
+
* `.mstarc`-declared sdd base is honored wherever the repo's own path
|
|
235
|
+
* SSOT composes it — the engine never second-guesses a composition it
|
|
236
|
+
* would itself produce (`resolveSddDir` is authoritative);
|
|
237
|
+
* - `featureCwd` exists and never nests with the control checkout
|
|
238
|
+
* (`featureCwd` inside the control checkout, or the control harness
|
|
239
|
+
* inside the feature checkout, are both refused — L1 hard rules);
|
|
240
|
+
* - branch/lease: when the control harness's workflow snapshots supply a
|
|
241
|
+
* plan row from a REGISTERED ACTIVE workflow (v2 root `status.json`
|
|
242
|
+
* `workflows[]`; a retained terminal snapshot never satisfies lease
|
|
243
|
+
* enforcement, and a plan claimed by multiple active workflows fails
|
|
244
|
+
* closed), its lease is verified (`verifyPlanExecutionLease`) and the
|
|
245
|
+
* L1 checklist runs (`l1PreDispatchCheck` with the control checkout);
|
|
246
|
+
* the context must then match the verified lease exactly. Without an
|
|
247
|
+
* active lease (no row, or a non-InProgress row without lease), the
|
|
248
|
+
* standalone branch policy applies (`assertBranchAlignment`) — an
|
|
249
|
+
* InProgress row without lease is the orphan refusal.
|
|
250
|
+
*
|
|
251
|
+
* Throws `SddScriptError` — exit 2 when the declared context itself is
|
|
252
|
+
* malformed (non-absolute path, identity/composition mismatch, missing plan
|
|
253
|
+
* file), exit 1 when the environment fails the gate (missing dirs, branch
|
|
254
|
+
* mismatch, lease/orphan refusal, symlink escape). A rejected context never
|
|
255
|
+
* reaches an action check.
|
|
256
|
+
*/
|
|
257
|
+
export declare function resolveSddExecutionContext(input: SddExecutionContext): SddExecutionContext;
|
|
258
|
+
/**
|
|
259
|
+
* Gate one action seam against a resolved context (spec A3). Read-only —
|
|
260
|
+
* a refused action performs no write and the check itself never writes.
|
|
261
|
+
*
|
|
262
|
+
* - `kind: "source"` — the observed `cwd` must sit inside the feature
|
|
263
|
+
* worktree (nested directories allowed); a relative `target` resolves from
|
|
264
|
+
* that actual cwd. Targets outside the feature — traversal, absolute
|
|
265
|
+
* elsewhere, wrong-cwd, or symlink escape — are refused before mutation.
|
|
266
|
+
* - `kind: "artifact"` — the `target` must stay inside the plan's control
|
|
267
|
+
* `sddDir` or equal the declared `planFile`; legitimate control artifact
|
|
268
|
+
* edits are allowed while arbitrary control source edits are not. A
|
|
269
|
+
* nonexistent leaf canonicalizes through its nearest existing ancestor
|
|
270
|
+
* (`canonicalizeNearestExisting`); symlink escapes are refused.
|
|
271
|
+
* - `kind: "launch"` — verifies the resolved launch destination
|
|
272
|
+
* `featureCwd` (exists + on `workingBranch` via the reused
|
|
273
|
+
* `assertBranchAlignment`); the parent's own cwd is not gated, because a
|
|
274
|
+
* launch may legitimately run from control/main — its purpose is to bind
|
|
275
|
+
* the child's starting cwd to the feature worktree. An optional `target`
|
|
276
|
+
* is checked as a source target relative to `featureCwd` (where the child
|
|
277
|
+
* will start).
|
|
278
|
+
*
|
|
279
|
+
* Violations minted here carry the `sdd.context.*` prefix; violations from
|
|
280
|
+
* the reused branch/lease helpers keep their own codes (`worktree.*`,
|
|
281
|
+
* `lease.*`, `plan-path.*`) — the rules stay single-sourced. A3 limits
|
|
282
|
+
* apply: this is a snapshot check, not a future-write lock, and offers no
|
|
283
|
+
* protection against a concurrent hostile symlink swap.
|
|
284
|
+
*
|
|
285
|
+
* API contract (task-1 review Minor 2): `context` must be a
|
|
286
|
+
* `resolveSddExecutionContext`-produced (or equivalently already-validated)
|
|
287
|
+
* context. This function gates the action seam only and does NOT
|
|
288
|
+
* re-validate the context declaration — identity, branch, lease and
|
|
289
|
+
* control/feature nesting checks run at resolve time — so a hand-assembled
|
|
290
|
+
* structurally-valid context gets no protection claim from this check
|
|
291
|
+
* alone.
|
|
292
|
+
*/
|
|
293
|
+
export declare function checkSddAction(context: SddExecutionContext, action: SddAction): GateResult;
|
|
294
|
+
/**
|
|
295
|
+
* Bound argv launcher (spec A3):
|
|
296
|
+
* resolve + gate the context, then spawn a DIRECT executable argv — never
|
|
297
|
+
* a shell (no command-string interpolation; the argv array reaches the
|
|
298
|
+
* child literally, spaces/`$()`/backticks unchanged) — with
|
|
299
|
+
* cwd = the resolved feature worktree, inherited stdio and the inherited
|
|
300
|
+
* process environment unchanged (no HOME/CODEX_HOME edits, no credential
|
|
301
|
+
* copies). The parent's own cwd is deliberately not gated: a launch may
|
|
302
|
+
* run from control/main, and the `launch` seam validates the resolved
|
|
303
|
+
* launch destination (featureCwd + workingBranch) instead.
|
|
304
|
+
*
|
|
305
|
+
* Exit contract (Task 2 CLI mapping):
|
|
306
|
+
* - empty/invalid argv → `SddScriptError` exit 2 (usage);
|
|
307
|
+
* - context/gate failure → `SddScriptError` exit 1 (usage-class declaration
|
|
308
|
+
* errors from resolution keep their own exit 2);
|
|
309
|
+
* - spawn-not-found (ENOENT) → resolves 127;
|
|
310
|
+
* - numeric child exit → resolved unchanged (exit 7 returns 7);
|
|
311
|
+
* - child killed by signal n → resolves 128+n (SIGTERM → 143, SIGINT → 130).
|
|
312
|
+
*
|
|
313
|
+
* SIGINT/SIGTERM are forwarded to the running child; the listeners are
|
|
314
|
+
* removed once the child settles — the launcher leaves no handlers behind.
|
|
315
|
+
*
|
|
316
|
+
* A3 limits apply unchanged: the launcher binds the child's STARTING cwd;
|
|
317
|
+
* it is not a sandbox — a child can later chdir, pass an overriding cwd
|
|
318
|
+
* flag, write absolute paths elsewhere, or use host edit tooling. Other
|
|
319
|
+
* spawn errors (e.g. EACCES) reject; the CLI maps them to exit 1 with the
|
|
320
|
+
* cause in the message.
|
|
321
|
+
*/
|
|
322
|
+
export declare function runInSddContext(context: SddExecutionContext, argv: readonly string[]): Promise<number>;
|