opencode-swarm 7.121.0 → 7.121.2
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/.opencode/skills/commit-pr/SKILL.md +4 -0
- package/.opencode/skills/issue-ingest/SKILL.md +9 -7
- package/dist/cli/{curation-policy-re2kaysb.js → curation-policy-10wnhpwn.js} +2 -2
- package/dist/cli/{curator-llm-factory-jta9tggm.js → curator-llm-factory-vcyvbny0.js} +10 -10
- package/dist/cli/{curator-8m0pf9cz.js → curator-mwvrryf3.js} +10 -10
- package/dist/cli/{evidence-summary-service-jtx5q3r6.js → evidence-summary-service-k14ykm03.js} +2 -2
- package/dist/cli/{guardrail-explain-nsfm5ksb.js → guardrail-explain-tgkk87z5.js} +11 -11
- package/dist/cli/{hive-promoter-8303gnfk.js → hive-promoter-z4tw1gfv.js} +10 -10
- package/dist/cli/{index-rywkdacj.js → index-0f800qg7.js} +3 -3
- package/dist/cli/{index-3je67dcz.js → index-1y03193n.js} +1 -1
- package/dist/cli/{index-3ygv9535.js → index-2ygp3qq4.js} +11 -11
- package/dist/cli/{index-nhgw7de8.js → index-35xyj7gn.js} +1 -1
- package/dist/cli/{index-69ms9ny1.js → index-5a3xsnzg.js} +1 -1
- package/dist/cli/{index-3366gs26.js → index-db82jxt7.js} +2 -2
- package/dist/cli/{index-j5xv8zbp.js → index-emkb0bbe.js} +1 -1
- package/dist/cli/{index-0k4r8111.js → index-ft6jw816.js} +4 -4
- package/dist/cli/{index-0e1v02hq.js → index-j8349ac0.js} +1 -1
- package/dist/cli/{index-0mbmfmt0.js → index-qt2yaghg.js} +2 -1
- package/dist/cli/{index-fndvr7fr.js → index-rbfq77sz.js} +1 -1
- package/dist/cli/{index-78b192v7.js → index-x4fwtd59.js} +3 -3
- package/dist/cli/{index-gmc34yzt.js → index-y0qa3xf0.js} +770 -669
- package/dist/cli/index.js +10 -10
- package/dist/cli/{knowledge-escalator-0ejqs8c9.js → knowledge-escalator-8ajq1fhb.js} +3 -3
- package/dist/cli/{knowledge-events-wx9e37ba.js → knowledge-events-2sjy3aa7.js} +1 -1
- package/dist/cli/{knowledge-store-rnajx33a.js → knowledge-store-27cesthc.js} +1 -1
- package/dist/cli/{knowledge-validator-1f4mkzmc.js → knowledge-validator-9keh3p8j.js} +4 -4
- package/dist/cli/{scan-cursor-qapm0sxj.js → scan-cursor-qmsmmg1b.js} +2 -2
- package/dist/cli/{skill-generator-tkv7s12g.js → skill-generator-hkyxdc3j.js} +5 -5
- package/dist/commands/issue.d.ts +12 -0
- package/dist/config/plan-schema.d.ts +3 -0
- package/dist/hooks/delegation-gate.d.ts +120 -0
- package/dist/hooks/issue-trace-reducer.d.ts +66 -0
- package/dist/hooks/issue-trace-state.d.ts +64 -0
- package/dist/hooks/issue-trace.d.ts +31 -0
- package/dist/index.js +258 -232
- package/dist/tools/save-plan.d.ts +2 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -7,28 +7,28 @@ import {
|
|
|
7
7
|
getPluginLockFilePaths,
|
|
8
8
|
package_default,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-y0qa3xf0.js";
|
|
11
11
|
import"./index-kyvg2cmp.js";
|
|
12
12
|
import"./index-vqcgmy4y.js";
|
|
13
|
-
import"./index-
|
|
13
|
+
import"./index-emkb0bbe.js";
|
|
14
14
|
import"./index-4905hd2m.js";
|
|
15
15
|
import"./index-nprawcc0.js";
|
|
16
|
-
import"./index-
|
|
17
|
-
import"./index-
|
|
18
|
-
import"./index-
|
|
16
|
+
import"./index-x4fwtd59.js";
|
|
17
|
+
import"./index-ft6jw816.js";
|
|
18
|
+
import"./index-j8349ac0.js";
|
|
19
19
|
import"./index-vxv732ex.js";
|
|
20
20
|
import"./index-c8s9a3zh.js";
|
|
21
21
|
import"./index-816rkp4y.js";
|
|
22
22
|
import"./index-22e127jw.js";
|
|
23
|
-
import"./index-
|
|
24
|
-
import"./index-
|
|
23
|
+
import"./index-db82jxt7.js";
|
|
24
|
+
import"./index-5a3xsnzg.js";
|
|
25
25
|
import"./index-rtry5xyf.js";
|
|
26
|
-
import"./index-
|
|
27
|
-
import"./index-
|
|
26
|
+
import"./index-0f800qg7.js";
|
|
27
|
+
import"./index-35xyj7gn.js";
|
|
28
28
|
import"./index-ae75rja9.js";
|
|
29
29
|
import"./index-3jvqw5hy.js";
|
|
30
30
|
import"./index-9xpgytj9.js";
|
|
31
|
-
import"./index-
|
|
31
|
+
import"./index-qt2yaghg.js";
|
|
32
32
|
import"./index-gnp9x6se.js";
|
|
33
33
|
import {
|
|
34
34
|
DEFAULT_AGENT_CONFIGS
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
maybeEscalateOnViolation,
|
|
9
9
|
maybeQuarantineOnContradiction,
|
|
10
10
|
readRecentEscalations
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
13
|
-
import"./index-
|
|
11
|
+
} from "./index-ft6jw816.js";
|
|
12
|
+
import"./index-0f800qg7.js";
|
|
13
|
+
import"./index-35xyj7gn.js";
|
|
14
14
|
import"./index-ae75rja9.js";
|
|
15
15
|
import"./index-3jvqw5hy.js";
|
|
16
16
|
import"./index-4rhcth7a.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveKnowledgeCounterBaselinePath,
|
|
26
26
|
resolveKnowledgeEventsPath,
|
|
27
27
|
resolveLegacyApplicationLogPath
|
|
28
|
-
} from "./index-
|
|
28
|
+
} from "./index-35xyj7gn.js";
|
|
29
29
|
import"./index-ae75rja9.js";
|
|
30
30
|
import"./index-3jvqw5hy.js";
|
|
31
31
|
import"./index-zgwm4ryv.js";
|
|
@@ -23,11 +23,11 @@ import {
|
|
|
23
23
|
validateLesson,
|
|
24
24
|
validateSkillCandidatePath,
|
|
25
25
|
validateSkillPath
|
|
26
|
-
} from "./index-
|
|
27
|
-
import"./index-
|
|
26
|
+
} from "./index-db82jxt7.js";
|
|
27
|
+
import"./index-5a3xsnzg.js";
|
|
28
28
|
import"./index-rtry5xyf.js";
|
|
29
|
-
import"./index-
|
|
30
|
-
import"./index-
|
|
29
|
+
import"./index-0f800qg7.js";
|
|
30
|
+
import"./index-35xyj7gn.js";
|
|
31
31
|
import"./index-ae75rja9.js";
|
|
32
32
|
import"./index-3jvqw5hy.js";
|
|
33
33
|
import"./index-4rhcth7a.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
alreadyCuratedThisGeneration,
|
|
5
5
|
claimNextScanBatch,
|
|
6
6
|
getScanStatus
|
|
7
|
-
} from "./index-
|
|
8
|
-
import"./index-
|
|
7
|
+
} from "./index-j8349ac0.js";
|
|
8
|
+
import"./index-0f800qg7.js";
|
|
9
9
|
import"./index-ae75rja9.js";
|
|
10
10
|
import"./index-3jvqw5hy.js";
|
|
11
11
|
import"./index-4rhcth7a.js";
|
|
@@ -33,12 +33,12 @@ import {
|
|
|
33
33
|
sanitizeSlug,
|
|
34
34
|
selectCandidateEntries,
|
|
35
35
|
writeEvalStub
|
|
36
|
-
} from "./index-
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
36
|
+
} from "./index-x4fwtd59.js";
|
|
37
|
+
import"./index-db82jxt7.js";
|
|
38
|
+
import"./index-5a3xsnzg.js";
|
|
39
39
|
import"./index-rtry5xyf.js";
|
|
40
|
-
import"./index-
|
|
41
|
-
import"./index-
|
|
40
|
+
import"./index-0f800qg7.js";
|
|
41
|
+
import"./index-35xyj7gn.js";
|
|
42
42
|
import"./index-ae75rja9.js";
|
|
43
43
|
import"./index-3jvqw5hy.js";
|
|
44
44
|
import"./index-4rhcth7a.js";
|
package/dist/commands/issue.d.ts
CHANGED
|
@@ -10,4 +10,16 @@
|
|
|
10
10
|
* --no-repro → appends noRepro=true to emitted signal
|
|
11
11
|
* no args → returns usage string (no throw)
|
|
12
12
|
*/
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
/**
|
|
15
|
+
* DI seam for filesystem operations — allows tests to override synchronous fs calls.
|
|
16
|
+
*/
|
|
17
|
+
export declare const _internals: {
|
|
18
|
+
writeFileSync: typeof fs.writeFileSync;
|
|
19
|
+
mkdirSync: typeof fs.mkdirSync;
|
|
20
|
+
renameSync: typeof fs.renameSync;
|
|
21
|
+
unlinkSync: typeof fs.unlinkSync;
|
|
22
|
+
readFileSync: typeof fs.readFileSync;
|
|
23
|
+
existsSync: typeof fs.existsSync;
|
|
24
|
+
};
|
|
13
25
|
export declare function handleIssueCommand(directory: string, args: string[]): string;
|
|
@@ -69,6 +69,7 @@ export declare const TaskSchema: z.ZodObject<{
|
|
|
69
69
|
files_touched: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
70
70
|
evidence_path: z.ZodOptional<z.ZodString>;
|
|
71
71
|
blocked_reason: z.ZodOptional<z.ZodString>;
|
|
72
|
+
fr_refs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
72
73
|
}, z.core.$strip>;
|
|
73
74
|
export type Task = z.infer<typeof TaskSchema>;
|
|
74
75
|
export declare const PhaseSchema: z.ZodObject<{
|
|
@@ -103,6 +104,7 @@ export declare const PhaseSchema: z.ZodObject<{
|
|
|
103
104
|
files_touched: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
104
105
|
evidence_path: z.ZodOptional<z.ZodString>;
|
|
105
106
|
blocked_reason: z.ZodOptional<z.ZodString>;
|
|
107
|
+
fr_refs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
106
108
|
}, z.core.$strip>>>;
|
|
107
109
|
type: z.ZodOptional<z.ZodEnum<{
|
|
108
110
|
code: "code";
|
|
@@ -148,6 +150,7 @@ export declare const PlanSchema: z.ZodObject<{
|
|
|
148
150
|
files_touched: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
149
151
|
evidence_path: z.ZodOptional<z.ZodString>;
|
|
150
152
|
blocked_reason: z.ZodOptional<z.ZodString>;
|
|
153
|
+
fr_refs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
151
154
|
}, z.core.$strip>>>;
|
|
152
155
|
type: z.ZodOptional<z.ZodEnum<{
|
|
153
156
|
code: "code";
|
|
@@ -66,6 +66,20 @@ interface ValidationContext {
|
|
|
66
66
|
/**
|
|
67
67
|
* Validates a DelegationEnvelope against the current plan and agent list.
|
|
68
68
|
* Returns { valid: true } on success, or { valid: false; reason: string } on failure.
|
|
69
|
+
*
|
|
70
|
+
* NOTE (#1687, kept SEPARATE from {@link validateCoderReviewerAcceptanceField}):
|
|
71
|
+
* this validator operates on a *structured* `DelegationEnvelope` object recovered
|
|
72
|
+
* from the OLD `KEY:VALUE` envelope format (`taskId:`/`targetAgent:`/`action:`/
|
|
73
|
+
* `commandType:`/`files:`/`acceptanceCriteria:`) and is consumed ADVISORY-ONLY,
|
|
74
|
+
* POST-execution via {@link appendDelegationEnvelopeAdvisory} in `toolAfter` (it
|
|
75
|
+
* never throws). The free-text coder/reviewer format
|
|
76
|
+
* (`TASK:`/`FILE:`/`ACCEPTANCE:`) does NOT parse into this shape
|
|
77
|
+
* (`parseDelegationEnvelope` returns `null`), so this path never fires on a real
|
|
78
|
+
* coder/reviewer dispatch. The pre-dispatch, BLOCKING acceptance-field gate for
|
|
79
|
+
* the free-text format lives in {@link validateCoderReviewerAcceptanceField};
|
|
80
|
+
* the two are intentionally not merged (advisory-vs-blocking, structured-vs-
|
|
81
|
+
* free-text are different contracts). Do not delete this function — it retains a
|
|
82
|
+
* real purpose for the old envelope format and other delegation types.
|
|
69
83
|
*/
|
|
70
84
|
export declare function validateDelegationEnvelope(envelope: unknown, context: ValidationContext): EnvelopeValidationResult;
|
|
71
85
|
/**
|
|
@@ -87,6 +101,107 @@ export declare function validateDelegationEnvelope(envelope: unknown, context: V
|
|
|
87
101
|
* the side effect (advisory push) is the production purpose.
|
|
88
102
|
*/
|
|
89
103
|
export declare function appendDelegationEnvelopeAdvisory(session: AgentSessionState, promptText: string, context: ValidationContext): EnvelopeValidationResult | null;
|
|
104
|
+
/**
|
|
105
|
+
* FR-003 / SC-003 / SC-004 (issue #1687): pre-dispatch acceptance-criteria
|
|
106
|
+
* enforcement for **coder and reviewer** delegations, operating on the REAL
|
|
107
|
+
* free-text delegation prompt (`TASK:`/`FILE:`/`INPUT:`/`OUTPUT:`/`CONSTRAINT:`/
|
|
108
|
+
* `ACCEPTANCE:`/`SKILLS:`) the architect actually sends via the native Task tool.
|
|
109
|
+
*
|
|
110
|
+
* Deliberately kept SEPARATE from {@link validateDelegationEnvelope} (see the
|
|
111
|
+
* sibling note there), NOT a rename/reuse of it, because the semantics differ on
|
|
112
|
+
* two axes: this function parses the FREE-TEXT `ACCEPTANCE:` line (not a
|
|
113
|
+
* structured envelope object) and is consumed as a BLOCKING, PRE-execution
|
|
114
|
+
* (`toolBefore`) gate (not the advisory, post-execution `toolAfter` path that
|
|
115
|
+
* `validateDelegationEnvelope` feeds via {@link appendDelegationEnvelopeAdvisory}).
|
|
116
|
+
* The two formats never overlap — `parseDelegationEnvelope` returns `null` for
|
|
117
|
+
* the free-text coder/reviewer format — so merging them would conflate
|
|
118
|
+
* advisory-vs-blocking and structured-vs-free-text contracts. M15's advisory
|
|
119
|
+
* mechanism is left fully intact for the old envelope format and other
|
|
120
|
+
* delegation types.
|
|
121
|
+
*
|
|
122
|
+
* A dispatch passes when an `ACCEPTANCE:` line exists AND the field carries
|
|
123
|
+
* non-empty, non-whitespace content — either INLINE on the header line (the
|
|
124
|
+
* architect-instructed same-line format) OR on the lines that FOLLOW a bare
|
|
125
|
+
* `ACCEPTANCE:` header, up to (but excluding) the next INPUT-FORMAT field header
|
|
126
|
+
* (`^[A-Z][A-Z0-9_]*:`, e.g. `SKILLS:`) or end of input. The multi-line form is
|
|
127
|
+
* a plausible way to paste a verbatim FR/SC body that spans lines (PR #1864
|
|
128
|
+
* review feedback), so treating a bare header + following content as EMPTY would
|
|
129
|
+
* false-block a good-faith copy. The next-field-header terminator ensures
|
|
130
|
+
* content belonging to the NEXT field (e.g. `SKILLS: none`) is never miscounted
|
|
131
|
+
* as ACCEPTANCE content — an empty `ACCEPTANCE:` immediately followed by another
|
|
132
|
+
* field is still correctly rejected as empty. Prompts are split on `\r?\n` so a
|
|
133
|
+
* trailing `\r` (CRLF-authored prompts) never leaks into the captured content.
|
|
134
|
+
*
|
|
135
|
+
* Only NON-EMPTINESS is enforced here; verbatim-coverage of the mapped FR/SC
|
|
136
|
+
* bodies is a SEPARATE, later check ({@link checkAcceptanceCoversFrRefs}) that
|
|
137
|
+
* already newline-normalizes the whole prompt, so multi-line ACCEPTANCE content
|
|
138
|
+
* is visible to it regardless.
|
|
139
|
+
*
|
|
140
|
+
* @param promptText the assembled delegation prompt (all text-bearing Task args
|
|
141
|
+
* joined).
|
|
142
|
+
* @returns `{ valid: true }` when the ACCEPTANCE field is present and non-empty;
|
|
143
|
+
* otherwise `{ valid: false, reason }` with a diagnosable reason the caller
|
|
144
|
+
* turns into a blocking, pre-dispatch error.
|
|
145
|
+
*/
|
|
146
|
+
export declare function validateCoderReviewerAcceptanceField(promptText: string): {
|
|
147
|
+
valid: boolean;
|
|
148
|
+
reason?: 'acceptance_field_missing' | 'acceptance_field_empty';
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* FR-001/FR-002/FR-005/SC-001/SC-002/SC-006 (issue #1687): pull the verbatim
|
|
152
|
+
* requirement BODY for a single spec id (`FR-###` / `SC-###`) out of `spec.md`.
|
|
153
|
+
*
|
|
154
|
+
* spec.md requirements are bold-prefixed bullets, one per (possibly wrapped)
|
|
155
|
+
* bullet, e.g.
|
|
156
|
+
* `- **FR-000 — Structured task-to-FR mapping.** The plan task model SHALL ...`
|
|
157
|
+
* `- **SC-000 (FR-000).** Given a plan ..., then ...`
|
|
158
|
+
* The requirement BODY is the text AFTER the FIRST closing `**` of the leading
|
|
159
|
+
* bold span — i.e. everything past the `**...**` id/title prefix. Handles both
|
|
160
|
+
* FR-### and SC-### uniformly (no special-casing) and stitches on any
|
|
161
|
+
* immediately-following continuation lines of a wrapped bullet until the next
|
|
162
|
+
* bullet / next FR-|SC- bullet / a blank line / a markdown heading.
|
|
163
|
+
*
|
|
164
|
+
* @returns the raw (untrimmed) body string, or `null` when the id is not present
|
|
165
|
+
* in the spec (unknown/typo/renamed) — the caller treats null as fail-open skip.
|
|
166
|
+
*/
|
|
167
|
+
export declare function extractSpecRequirementBodyById(specText: string, id: string): string | null;
|
|
168
|
+
/**
|
|
169
|
+
* FR-001/FR-002 (issue #1687): symmetric normalization applied identically to
|
|
170
|
+
* BOTH the extracted spec body AND the ACCEPTANCE prompt text before the
|
|
171
|
+
* substring-coverage compare. Asymmetric normalization would false-block, so this
|
|
172
|
+
* is deliberately the single shared normalizer. Strips markdown emphasis/code
|
|
173
|
+
* markers and leading list markers, folds punctuation the architect's LLM copy
|
|
174
|
+
* routinely substitutes (dash-width, curly-vs-straight quotes) so a good-faith
|
|
175
|
+
* verbatim copy is not false-blocked on a `—`→`--` or `'`→`'` swap, collapses
|
|
176
|
+
* ALL whitespace (incl. newlines) to single spaces, trims, and lowercases. Every
|
|
177
|
+
* fold is symmetric (both sides go through this one function), so it can only
|
|
178
|
+
* REDUCE false-blocks — it never opens a bypass, since covered/uncovered still
|
|
179
|
+
* differ by whole words, not punctuation.
|
|
180
|
+
*/
|
|
181
|
+
export declare function normalizeAcceptanceText(s: string): string;
|
|
182
|
+
/**
|
|
183
|
+
* FR-001/FR-002/FR-005/SC-001/SC-002/SC-006 (issue #1687): mechanical coverage
|
|
184
|
+
* check that the ACCEPTANCE text CONTAINS the verbatim requirement body for each
|
|
185
|
+
* mapped spec id. Fail-open by construction:
|
|
186
|
+
* - an id not present in spec.md (unknown/typo/renamed) is SKIPPED, never blocked;
|
|
187
|
+
* - an id whose body normalizes to empty is SKIPPED (neither trivially covered
|
|
188
|
+
* nor a miss);
|
|
189
|
+
* - each id is checked INDEPENDENTLY (per-id substring), because the architect
|
|
190
|
+
* concatenates multiple requirement bodies with an UNSPECIFIED separator — a
|
|
191
|
+
* whole-string equality compare would false-block multi-FR tasks.
|
|
192
|
+
*
|
|
193
|
+
* @returns `{ covered: true }` when every id is present-and-covered or skipped;
|
|
194
|
+
* `{ covered: false, missingId }` naming the FIRST id whose body is not a
|
|
195
|
+
* substring of the ACCEPTANCE text.
|
|
196
|
+
*/
|
|
197
|
+
export declare function checkAcceptanceCoversFrRefs(params: {
|
|
198
|
+
acceptanceText: string;
|
|
199
|
+
frRefs: string[];
|
|
200
|
+
specText: string;
|
|
201
|
+
}): {
|
|
202
|
+
covered: boolean;
|
|
203
|
+
missingId?: string;
|
|
204
|
+
};
|
|
90
205
|
interface MessageInfo {
|
|
91
206
|
role: string;
|
|
92
207
|
agent?: string;
|
|
@@ -101,6 +216,11 @@ interface MessageWithParts {
|
|
|
101
216
|
info: MessageInfo;
|
|
102
217
|
parts: MessagePart[];
|
|
103
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Returns whether the plan in the given directory has a valid plan-critic
|
|
221
|
+
* approval. Does not throw — returns `false` for any failure (fail-closed).
|
|
222
|
+
*/
|
|
223
|
+
export declare function isPlanCriticApproved(directory: string): Promise<boolean>;
|
|
104
224
|
declare function resolveDelegatedPlanTaskId(args: Record<string, unknown>, knownPlanTaskIds?: ReadonlySet<string>): string | null;
|
|
105
225
|
/**
|
|
106
226
|
* Parses structured per-task verdict lines from agent dispatch output.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue trace reducer — a pure transition function with zero I/O.
|
|
3
|
+
*
|
|
4
|
+
* Determines the next mode transition for an issue-trace workflow
|
|
5
|
+
* based on current trace state and workflow artifacts. Evaluated
|
|
6
|
+
* top-to-bottom (first-match-wins) against an 8-row decision table.
|
|
7
|
+
*/
|
|
8
|
+
export interface IssueReference {
|
|
9
|
+
url: string;
|
|
10
|
+
owner: string;
|
|
11
|
+
repo: string;
|
|
12
|
+
number: number;
|
|
13
|
+
timestamp: string;
|
|
14
|
+
flags: {
|
|
15
|
+
plan?: boolean;
|
|
16
|
+
trace?: boolean;
|
|
17
|
+
noRepro?: boolean;
|
|
18
|
+
};
|
|
19
|
+
noReproWaiver?: {
|
|
20
|
+
waived: boolean;
|
|
21
|
+
reason: string;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface TraceState {
|
|
26
|
+
issueNumber: number;
|
|
27
|
+
lastTransition: string | null;
|
|
28
|
+
completed: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkflowArtifacts {
|
|
31
|
+
specExists: boolean;
|
|
32
|
+
specIssueNumber: number | null;
|
|
33
|
+
planExists: boolean;
|
|
34
|
+
criticApproved: boolean;
|
|
35
|
+
allPhasesComplete: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface TransitionResult {
|
|
38
|
+
nextMode: string | null;
|
|
39
|
+
directive: string | null;
|
|
40
|
+
nextLastTransition: string | null;
|
|
41
|
+
nextCompleted: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface ComputeNextModeParams {
|
|
44
|
+
issueReference: IssueReference | null;
|
|
45
|
+
traceState: TraceState;
|
|
46
|
+
workflowArtifacts: WorkflowArtifacts;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Pure reducer: given trace state + workflow artifacts, return the
|
|
50
|
+
* next mode transition (or a no-op).
|
|
51
|
+
*
|
|
52
|
+
* Decision table (top-to-bottom, first match wins):
|
|
53
|
+
* (a) No issue reference or trace not requested → no-op
|
|
54
|
+
* (b) Trace already completed → no-op
|
|
55
|
+
* (c) Cross-issue guard (spec issue ≠ current issue) → no-op
|
|
56
|
+
* (d) Spec does not exist → no-op
|
|
57
|
+
* (e) Spec exists, no plan, never transitioned → PLAN
|
|
58
|
+
* (f) Plan exists but critic not approved → no-op
|
|
59
|
+
* (g) Critic approved, phases incomplete, not yet PLAN_TO_EXECUTE → EXECUTE
|
|
60
|
+
* (h) All phases complete, not yet EXECUTE_TO_COMMIT → COMMIT directive
|
|
61
|
+
*
|
|
62
|
+
* Idempotency: rows (e), (g), (h) return no-op when
|
|
63
|
+
* `traceState.lastTransition` already equals the target
|
|
64
|
+
* transition value.
|
|
65
|
+
*/
|
|
66
|
+
export declare function computeNextMode(params: ComputeNextModeParams): TransitionResult;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue trace state adapter — reads and writes all artifacts for the
|
|
3
|
+
* issue-trace workflow engine.
|
|
4
|
+
*
|
|
5
|
+
* Uses the `_internals` DI seam pattern (AGENTS.md invariant 7) so
|
|
6
|
+
* tests can override filesystem calls without `mock.module` leakage.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import type { Plan } from '../config/plan-schema';
|
|
10
|
+
import type { IssueReference, TraceState } from './issue-trace-reducer';
|
|
11
|
+
declare function _defaultLoadPlanFromLedger(directory: string): Promise<Plan | null>;
|
|
12
|
+
export declare const _internals: {
|
|
13
|
+
readFileSync: typeof readFileSync;
|
|
14
|
+
writeFileSync: typeof writeFileSync;
|
|
15
|
+
existsSync: typeof existsSync;
|
|
16
|
+
renameSync: typeof renameSync;
|
|
17
|
+
mkdirSync: typeof mkdirSync;
|
|
18
|
+
unlinkSync: typeof unlinkSync;
|
|
19
|
+
loadPlanFromLedger: typeof _defaultLoadPlanFromLedger;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Reads `.swarm/issue-reference.json` and returns the parsed object,
|
|
23
|
+
* or null if the file is absent or malformed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readIssueReference(directory: string): IssueReference | null;
|
|
26
|
+
/**
|
|
27
|
+
* Reads `.swarm/issue-trace-state.json` and returns the parsed state,
|
|
28
|
+
* or a default `{issueNumber:0, lastTransition:null, completed:false}`
|
|
29
|
+
* if the file is absent or malformed.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readTraceState(directory: string): TraceState;
|
|
32
|
+
/**
|
|
33
|
+
* Writes `.swarm/issue-trace-state.json` atomically: creates a temp file
|
|
34
|
+
* inside `.swarm/`, writes JSON, then renames. Cleans up the temp on failure.
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeTraceState(directory: string, state: TraceState): void;
|
|
37
|
+
/**
|
|
38
|
+
* Reads `.swarm/spec.md` and extracts the issue number from the
|
|
39
|
+
* `## Source Issue` section. Looks for `- Number: N` or `- URL: ...issues/N`
|
|
40
|
+
* under the heading. Returns null if the section is absent or the number
|
|
41
|
+
* is unparseable.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readSpecIssueNumber(directory: string): number | null;
|
|
44
|
+
/**
|
|
45
|
+
* Loads the plan from the ledger-aware plan loader.
|
|
46
|
+
* Async because the underlying ledger loader is async.
|
|
47
|
+
*/
|
|
48
|
+
export declare function loadPlanFromLedger(directory: string): Promise<Plan | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Checks whether all phases in the plan have a completed status.
|
|
51
|
+
* Returns `{allComplete: false}` if the plan is null.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readPlanPhaseStatus(directory: string): Promise<{
|
|
54
|
+
allComplete: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns whether `.swarm/spec.md` exists.
|
|
58
|
+
*/
|
|
59
|
+
export declare function specExists(directory: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Returns whether `.swarm/plan.json` exists.
|
|
62
|
+
*/
|
|
63
|
+
export declare function planExists(directory: string): boolean;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue trace hook — the deterministic trace transition engine.
|
|
3
|
+
*
|
|
4
|
+
* Ties together the reducer (issue-trace-reducer), the state adapter
|
|
5
|
+
* (issue-trace-state), and the approval helper (delegation-gate) into
|
|
6
|
+
* a single `messagesTransform` hook that the composeHandlers chain
|
|
7
|
+
* calls on every architect message cycle.
|
|
8
|
+
*
|
|
9
|
+
* Uses the `_internals` DI seam pattern (AGENTS.md invariant 7) so
|
|
10
|
+
* tests can override adapter functions without `mock.module` leakage.
|
|
11
|
+
*/
|
|
12
|
+
import { isPlanCriticApproved } from './delegation-gate';
|
|
13
|
+
import { planExists, readIssueReference, readPlanPhaseStatus, readSpecIssueNumber, readTraceState, specExists, writeTraceState } from './issue-trace-state';
|
|
14
|
+
export declare const _internals: {
|
|
15
|
+
readIssueReference: typeof readIssueReference;
|
|
16
|
+
readTraceState: typeof readTraceState;
|
|
17
|
+
writeTraceState: typeof writeTraceState;
|
|
18
|
+
readSpecIssueNumber: typeof readSpecIssueNumber;
|
|
19
|
+
readPlanPhaseStatus: typeof readPlanPhaseStatus;
|
|
20
|
+
specExists: typeof specExists;
|
|
21
|
+
planExists: typeof planExists;
|
|
22
|
+
isPlanCriticApproved: typeof isPlanCriticApproved;
|
|
23
|
+
};
|
|
24
|
+
export declare function createIssueTraceHook(_config: unknown, directory: string, approvalTimeoutMs?: number): {
|
|
25
|
+
messagesTransform: (input: unknown, output: unknown) => Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Reset the approval cache. Called by tests in afterEach to avoid
|
|
29
|
+
* cross-test pollution from the module-level cache.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resetApprovalCache(): void;
|