@smartmemory/compose 0.1.1-beta → 0.1.2-beta
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/skills/bug-fix/SKILL.md +143 -0
- package/.claude/skills/compose/SKILL.md +604 -0
- package/.compose-deps.json +89 -0
- package/README.md +14 -3
- package/bin/compose.js +473 -0
- package/contracts/comp-obs-contract.schema.json +362 -0
- package/contracts/cross-model-review-result.json +78 -0
- package/contracts/review-result.json +126 -0
- package/dist/assets/{_baseUniq-CQwX6VLz.js → _baseUniq-D-avYfn5.js} +1 -1
- package/dist/assets/{arc-SxJ2J1sh.js → arc-BC4dfQ-X.js} +1 -1
- package/dist/assets/{architectureDiagram-Q4EWVU46-BykunY1F.js → architectureDiagram-Q4EWVU46-BZmFXnGI.js} +1 -1
- package/dist/assets/{blockDiagram-DXYQGD6D-ohAKBOUw.js → blockDiagram-DXYQGD6D-DlfWSuux.js} +1 -1
- package/dist/assets/{c4Diagram-AHTNJAMY-DBDC3ENB.js → c4Diagram-AHTNJAMY-Y__uJrRx.js} +1 -1
- package/dist/assets/channel-LRG9kHqJ.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-Cv93Z7uM.js → chunk-4BX2VUAB-BfMePfTp.js} +1 -1
- package/dist/assets/{chunk-4TB4RGXK-DE0WBDkj.js → chunk-4TB4RGXK-BdlMSdEA.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CE1EXenG.js → chunk-55IACEB6-vrQHZTdv.js} +1 -1
- package/dist/assets/{chunk-EDXVE4YY-DA7Ana6H.js → chunk-EDXVE4YY-B8wioVlW.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-CTDIPA3p.js → chunk-FMBD7UC4-Cd6Hrux2.js} +1 -1
- package/dist/assets/{chunk-OYMX7WX6-uGBaPaTX.js → chunk-OYMX7WX6-CfrhdQXY.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-CYlnXuUO.js → chunk-QZHKN3VN-B9JQerOU.js} +1 -1
- package/dist/assets/{chunk-YZCP3GAM-ojGkzcZK.js → chunk-YZCP3GAM-DFN9X99H.js} +1 -1
- package/dist/assets/classDiagram-6PBFFD2Q-BC9a6pDE.js +1 -0
- package/dist/assets/classDiagram-v2-HSJHXN6E-BC9a6pDE.js +1 -0
- package/dist/assets/clone-dRxgFrBv.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-Bktn9hL-.js → cose-bilkent-S5V4N54A-BAn0ap_E.js} +1 -1
- package/dist/assets/{dagre-KV5264BT-DFaSzuRF.js → dagre-KV5264BT-DyxnVq1g.js} +1 -1
- package/dist/assets/{diagram-5BDNPKRD-DnfmDzEm.js → diagram-5BDNPKRD-XCrzqski.js} +1 -1
- package/dist/assets/{diagram-G4DWMVQ6-Bm8W9YnG.js → diagram-G4DWMVQ6-MBCAXft_.js} +1 -1
- package/dist/assets/{diagram-MMDJMWI5-B5-TSKvp.js → diagram-MMDJMWI5-DbtB2yS6.js} +1 -1
- package/dist/assets/{diagram-TYMM5635-ls4rqlky.js → diagram-TYMM5635-Bb5NzX61.js} +1 -1
- package/dist/assets/{erDiagram-SMLLAGMA-giG6WO-r.js → erDiagram-SMLLAGMA-CpIeCOh2.js} +1 -1
- package/dist/assets/{flowDiagram-DWJPFMVM-XvlUuz-7.js → flowDiagram-DWJPFMVM-CHyoKnhW.js} +1 -1
- package/dist/assets/{ganttDiagram-T4ZO3ILL-hLBV57oV.js → ganttDiagram-T4ZO3ILL-DErKteO_.js} +1 -1
- package/dist/assets/{gitGraphDiagram-UUTBAWPF-BHu3s_Gn.js → gitGraphDiagram-UUTBAWPF-KFVAtj2F.js} +1 -1
- package/dist/assets/{graph-D0Cfv00Y.js → graph-CRnO_ifT.js} +1 -1
- package/dist/assets/index-DKBsEUJ-.css +1 -0
- package/dist/assets/index-DkRKLuNr.js +1144 -0
- package/dist/assets/{infoDiagram-42DDH7IO-DbqRsOo3.js → infoDiagram-42DDH7IO-BZFnuSp5.js} +1 -1
- package/dist/assets/{ishikawaDiagram-UXIWVN3A-DnCdx7zb.js → ishikawaDiagram-UXIWVN3A-4Xe2Szde.js} +1 -1
- package/dist/assets/{journeyDiagram-VCZTEJTY-CfD7eNcP.js → journeyDiagram-VCZTEJTY-CZRByfS-.js} +1 -1
- package/dist/assets/{kanban-definition-6JOO6SKY-BYaO9-mK.js → kanban-definition-6JOO6SKY-B95sk6Fk.js} +1 -1
- package/dist/assets/{layout-Bj72wOEB.js → layout-BqNQzxWT.js} +1 -1
- package/dist/assets/{linear-BRFo114D.js → linear-CUh7qb64.js} +1 -1
- package/dist/assets/{min-GCHnKlJS.js → min-wXgOS3ig.js} +1 -1
- package/dist/assets/{mindmap-definition-QFDTVHPH-n0PMebY4.js → mindmap-definition-QFDTVHPH-DB6iaAbO.js} +1 -1
- package/dist/assets/{pieDiagram-DEJITSTG-pN4CljHF.js → pieDiagram-DEJITSTG-CHkZHrTW.js} +1 -1
- package/dist/assets/{quadrantDiagram-34T5L4WZ-DNoAy8-D.js → quadrantDiagram-34T5L4WZ-DoTEO8e3.js} +1 -1
- package/dist/assets/{requirementDiagram-MS252O5E-BhtY05PT.js → requirementDiagram-MS252O5E-Dn8peXYp.js} +1 -1
- package/dist/assets/{sankeyDiagram-XADWPNL6-B6AD-16A.js → sankeyDiagram-XADWPNL6-DRXs6Ipb.js} +1 -1
- package/dist/assets/{sequenceDiagram-FGHM5R23-DShHM-uk.js → sequenceDiagram-FGHM5R23-wBBYZ0aq.js} +1 -1
- package/dist/assets/{stateDiagram-FHFEXIEX-DMxn7HTo.js → stateDiagram-FHFEXIEX-DPlBNGmf.js} +1 -1
- package/dist/assets/stateDiagram-v2-QKLJ7IA2-BW0ezXb4.js +1 -0
- package/dist/assets/{timeline-definition-GMOUNBTQ-Cdu6uq52.js → timeline-definition-GMOUNBTQ-CbbyTlHk.js} +1 -1
- package/dist/assets/{vennDiagram-DHZGUBPP-CpK29iRe.js → vennDiagram-DHZGUBPP-Bj4GaFfj.js} +1 -1
- package/dist/assets/{wardley-RL74JXVD-BQgSkdcO.js → wardley-RL74JXVD-RtNzq8KU.js} +55 -55
- package/dist/assets/{wardleyDiagram-NUSXRM2D-DJHYev6O.js → wardleyDiagram-NUSXRM2D-CDfE3zSj.js} +1 -1
- package/dist/assets/{xychartDiagram-5P7HB3ND-1d75pbaO.js → xychartDiagram-5P7HB3ND-CZXHHYD5.js} +1 -1
- package/dist/index.html +2 -2
- package/lib/budget-ledger.js +45 -0
- package/lib/bug-bisect.js +292 -0
- package/lib/bug-checkpoint.js +191 -0
- package/lib/bug-escalation.js +306 -0
- package/lib/bug-index-gen.js +136 -0
- package/lib/bug-ledger.js +126 -0
- package/lib/build-stream-schema.js +176 -0
- package/lib/build-stream-writer.js +3 -1
- package/lib/build.js +854 -284
- package/lib/connector-factory-shim.js +167 -0
- package/lib/constants.js +18 -0
- package/lib/debug-discipline.js +176 -27
- package/lib/deps.js +205 -0
- package/lib/health-score.js +4 -4
- package/lib/import.js +26 -13
- package/lib/inject-schema.js +21 -0
- package/lib/new.js +27 -53
- package/lib/result-normalizer.js +160 -144
- package/lib/review-lenses.js +5 -5
- package/lib/review-normalize.js +413 -0
- package/lib/review-prompt.js +163 -0
- package/lib/sections.js +325 -0
- package/lib/step-prompt.js +21 -1
- package/lib/step-validator.js +5 -3
- package/lib/stratum-mcp-client.js +172 -7
- package/package.json +14 -3
- package/pipelines/bug-fix.stratum.yaml +39 -1
- package/pipelines/build.stratum.yaml +28 -45
- package/pipelines/review-fix.stratum.yaml +1 -1
- package/presets/team-review.stratum.yaml +21 -14
- package/server/build-stream-bridge.js +28 -0
- package/server/cc-session-feature-resolver.js +111 -0
- package/server/cc-session-reader.js +327 -0
- package/server/cc-session-watcher.js +318 -0
- package/server/compose-mcp-tools.js +0 -125
- package/server/compose-mcp.js +2 -4
- package/server/contract-diff.js +192 -0
- package/server/decision-event-emit.js +175 -0
- package/server/decision-event-id.js +64 -0
- package/server/decision-events-snapshot.js +166 -0
- package/server/design-routes.js +92 -49
- package/server/drift-axes.js +365 -0
- package/server/drift-emit.js +121 -0
- package/server/gate-log-store.js +102 -0
- package/server/lifecycle-phase-history.js +44 -0
- package/server/open-loops-store.js +102 -0
- package/server/schema-validator.js +49 -0
- package/server/status-emit.js +27 -0
- package/server/status-snapshot.js +218 -0
- package/server/vision-routes.js +332 -4
- package/server/vision-server.js +104 -12
- package/server/vision-store.js +21 -0
- package/dist/assets/channel-DGElom1e.js +0 -1
- package/dist/assets/classDiagram-6PBFFD2Q-KqWP9wWZ.js +0 -1
- package/dist/assets/classDiagram-v2-HSJHXN6E-KqWP9wWZ.js +0 -1
- package/dist/assets/clone-DUJKJXd7.js +0 -1
- package/dist/assets/index-CUd6pFGF.css +0 -1
- package/dist/assets/index-DReRlzZI.js +0 -1144
- package/dist/assets/stateDiagram-v2-QKLJ7IA2-o6PnCs4e.js +0 -1
- package/server/connectors/agent-connector.js +0 -78
- package/server/connectors/claude-sdk-connector.js +0 -198
- package/server/connectors/codex-connector.js +0 -240
- package/server/connectors/connector-discovery.js +0 -18
- package/server/connectors/connector-runtime.js +0 -13
- package/server/connectors/opencode-connector.js +0 -200
|
@@ -69,6 +69,13 @@ contracts:
|
|
|
69
69
|
discipline_score: {type: number}
|
|
70
70
|
summary: {type: string}
|
|
71
71
|
|
|
72
|
+
BisectResult:
|
|
73
|
+
skipped: {type: boolean}
|
|
74
|
+
bisect_commit: {type: string} # nullable; empty string when skipped
|
|
75
|
+
estimate_minutes: {type: number}
|
|
76
|
+
log_path: {type: string} # nullable; empty string when skipped
|
|
77
|
+
summary: {type: string}
|
|
78
|
+
|
|
72
79
|
functions:
|
|
73
80
|
reproduce:
|
|
74
81
|
mode: compute
|
|
@@ -99,6 +106,30 @@ functions:
|
|
|
99
106
|
- "result.scope_hint in ('single', 'cross-layer', 'unknown')"
|
|
100
107
|
retries: 2
|
|
101
108
|
|
|
109
|
+
bisect:
|
|
110
|
+
mode: compute
|
|
111
|
+
intent: >
|
|
112
|
+
Decide whether the bug is a regression worth bisecting; if so,
|
|
113
|
+
classify → estimate cost → gate the human → run git bisect.
|
|
114
|
+
The runtime helper `lib/bug-bisect.js` does the work:
|
|
115
|
+
1. classifyRegression(): repro test exists in main AND files in
|
|
116
|
+
diagnosis.affected_layers were touched in the last 10 commits.
|
|
117
|
+
2. estimateBisectCost(): test_runs = ceil(log2(commits in range));
|
|
118
|
+
seconds_per_run sampled by running the test once.
|
|
119
|
+
3. Gate: "Looks like a regression. Run git bisect? Estimate:
|
|
120
|
+
<test_runs> runs × <seconds_per_run>s = ~<total_minutes> min.
|
|
121
|
+
approve / skip / kill"
|
|
122
|
+
4. On approve: runBisect() drives `git bisect start && bad HEAD
|
|
123
|
+
&& good <baseline> && bisect run <testCmd>`, captures log to
|
|
124
|
+
docs/bugs/<bug-code>/bisect.log, always resets in finally.
|
|
125
|
+
5. On skip OR not-a-regression: return {skipped: true,
|
|
126
|
+
bisect_commit: null, estimate_minutes: 0} and continue.
|
|
127
|
+
input:
|
|
128
|
+
task: {type: string}
|
|
129
|
+
diagnosis: {type: object}
|
|
130
|
+
output: BisectResult
|
|
131
|
+
retries: 1
|
|
132
|
+
|
|
102
133
|
scope_check:
|
|
103
134
|
mode: compute
|
|
104
135
|
intent: >
|
|
@@ -191,12 +222,19 @@ flows:
|
|
|
191
222
|
task: "$.input.task"
|
|
192
223
|
depends_on: [reproduce]
|
|
193
224
|
|
|
225
|
+
- id: bisect
|
|
226
|
+
function: bisect
|
|
227
|
+
inputs:
|
|
228
|
+
task: "$.input.task"
|
|
229
|
+
diagnosis: "$.steps.diagnose.output"
|
|
230
|
+
depends_on: [diagnose]
|
|
231
|
+
|
|
194
232
|
- id: scope_check
|
|
195
233
|
function: scope_check
|
|
196
234
|
inputs:
|
|
197
235
|
task: "$.input.task"
|
|
198
236
|
diagnosis: "$.steps.diagnose.output"
|
|
199
|
-
depends_on: [
|
|
237
|
+
depends_on: [bisect]
|
|
200
238
|
|
|
201
239
|
- id: fix
|
|
202
240
|
function: fix
|
|
@@ -26,10 +26,16 @@ contracts:
|
|
|
26
26
|
outcome: {type: string, values: [complete, skipped, failed]}
|
|
27
27
|
summary: {type: string}
|
|
28
28
|
|
|
29
|
+
# Canonical review output — produced by both review_check (Codex) and parallel_review (Claude).
|
|
30
|
+
# Schema source: compose/contracts/review-result.json (_roadmap: STRAT-CLAUDE-EFFORT-PARITY)
|
|
29
31
|
ReviewResult:
|
|
30
|
-
clean:
|
|
31
|
-
summary:
|
|
32
|
-
findings:
|
|
32
|
+
clean: {type: boolean}
|
|
33
|
+
summary: {type: string}
|
|
34
|
+
findings: {type: array}
|
|
35
|
+
meta: {type: object}
|
|
36
|
+
lenses_run: {type: array}
|
|
37
|
+
auto_fixes: {type: array}
|
|
38
|
+
asks: {type: array}
|
|
33
39
|
|
|
34
40
|
TestResult:
|
|
35
41
|
passing: {type: boolean}
|
|
@@ -39,14 +45,6 @@ contracts:
|
|
|
39
45
|
TaskGraph:
|
|
40
46
|
tasks: {type: array}
|
|
41
47
|
|
|
42
|
-
LensFinding:
|
|
43
|
-
lens: {type: string}
|
|
44
|
-
file: {type: string}
|
|
45
|
-
line: {type: number}
|
|
46
|
-
severity: {type: string, values: [must-fix, should-fix, nit]}
|
|
47
|
-
finding: {type: string}
|
|
48
|
-
confidence: {type: number}
|
|
49
|
-
|
|
50
48
|
LensTask:
|
|
51
49
|
id: {type: string}
|
|
52
50
|
lens_name: {type: string}
|
|
@@ -57,18 +55,6 @@ contracts:
|
|
|
57
55
|
TriageResult:
|
|
58
56
|
tasks: {type: array}
|
|
59
57
|
|
|
60
|
-
LensResult:
|
|
61
|
-
clean: {type: boolean}
|
|
62
|
-
findings: {type: array, items: LensFinding}
|
|
63
|
-
|
|
64
|
-
MergedReviewResult:
|
|
65
|
-
clean: {type: boolean}
|
|
66
|
-
summary: {type: string}
|
|
67
|
-
findings: {type: array, items: LensFinding}
|
|
68
|
-
lenses_run: {type: array}
|
|
69
|
-
auto_fixes: {type: array, items: LensFinding}
|
|
70
|
-
asks: {type: array, items: LensFinding}
|
|
71
|
-
|
|
72
58
|
functions:
|
|
73
59
|
design_gate:
|
|
74
60
|
mode: gate
|
|
@@ -96,12 +82,12 @@ flows:
|
|
|
96
82
|
- id: review
|
|
97
83
|
agent: codex
|
|
98
84
|
intent: >
|
|
99
|
-
Review the implementation against the blueprint
|
|
100
|
-
{ "clean": boolean, "summary": string, "findings": string[] }.
|
|
101
|
-
Set clean=true only if no actionable findings with confidence >= 80 remain.
|
|
85
|
+
Review the implementation against the blueprint and task.
|
|
102
86
|
inputs:
|
|
103
87
|
task: "$.input.task"
|
|
104
88
|
blueprint: "$.input.blueprint"
|
|
89
|
+
review_mode: "true"
|
|
90
|
+
confidence_gate: "7"
|
|
105
91
|
output_contract: ReviewResult
|
|
106
92
|
ensure:
|
|
107
93
|
- "result.clean == True"
|
|
@@ -117,7 +103,7 @@ flows:
|
|
|
117
103
|
blueprint: {type: string}
|
|
118
104
|
diff: {type: string}
|
|
119
105
|
prior_dirty_lenses: {type: array, optional: true}
|
|
120
|
-
output:
|
|
106
|
+
output: ReviewResult
|
|
121
107
|
steps:
|
|
122
108
|
- id: triage
|
|
123
109
|
agent: "claude:orchestrator"
|
|
@@ -150,34 +136,31 @@ flows:
|
|
|
150
136
|
source: "$.steps.triage.output.tasks"
|
|
151
137
|
max_concurrent: 4
|
|
152
138
|
isolation: none
|
|
139
|
+
output_contract: ReviewResult
|
|
153
140
|
intent_template: >
|
|
154
|
-
|
|
155
|
-
Focus: {lens_focus}
|
|
156
|
-
Confidence gate: only report findings with confidence >= {confidence_gate}.
|
|
157
|
-
False-positive exclusions: {exclusions}
|
|
158
|
-
Return JSON: { "clean": boolean, "findings": LensFinding[] }
|
|
159
|
-
where each finding has: lens, file, line, severity (must-fix|should-fix|nit),
|
|
160
|
-
finding (description), confidence (1-10).
|
|
141
|
+
Lens: {lens_name}. Focus: {lens_focus}.
|
|
161
142
|
require: all
|
|
162
143
|
|
|
163
144
|
- id: merge
|
|
164
145
|
agent: "claude:orchestrator"
|
|
165
146
|
intent: >
|
|
166
|
-
Merge
|
|
167
|
-
dispatch aggregate with tasks[].result for each lens.
|
|
168
|
-
1.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
147
|
+
Merge ReviewResult arrays from all lens runs into a single canonical ReviewResult.
|
|
148
|
+
The input contains the parallel dispatch aggregate with tasks[].result for each lens.
|
|
149
|
+
1. Concatenate all findings arrays from completed task results.
|
|
150
|
+
Deduplicate by file+line+lens: keep finding with highest confidence;
|
|
151
|
+
carry over its applied_gate.
|
|
152
|
+
2. Recompute clean: zero must-fix AND zero should-fix findings (post-dedupe, post-gate).
|
|
153
|
+
3. lenses_run = IDs of lenses that produced any must-fix or should-fix finding.
|
|
154
|
+
4. auto_fixes = mechanical fixes (formatting, typos, simple tests).
|
|
155
|
+
5. asks = findings requiring human judgment.
|
|
156
|
+
Return canonical ReviewResult with clean, summary, findings, lenses_run,
|
|
157
|
+
auto_fixes, asks, meta.
|
|
176
158
|
inputs:
|
|
177
159
|
results: "$.steps.review_lenses.output"
|
|
178
160
|
task: "$.input.task"
|
|
179
161
|
blueprint: "$.input.blueprint"
|
|
180
|
-
|
|
162
|
+
reduce_mode: "true"
|
|
163
|
+
output_contract: ReviewResult
|
|
181
164
|
depends_on: [review_lenses]
|
|
182
165
|
|
|
183
166
|
# --- Sub-flow: coverage ---
|
|
@@ -73,7 +73,7 @@ functions:
|
|
|
73
73
|
- the task description
|
|
74
74
|
- the execute_summary (what was implemented)
|
|
75
75
|
- the blueprint content
|
|
76
|
-
- instruction: "List actionable findings with confidence >=
|
|
76
|
+
- instruction: "List actionable findings with confidence >= 7.
|
|
77
77
|
Set clean=true only if no actionable findings remain."
|
|
78
78
|
Pass the schema to agent_run so it returns structured JSON.
|
|
79
79
|
|
|
@@ -17,10 +17,15 @@ contracts:
|
|
|
17
17
|
type: array
|
|
18
18
|
values: [{type: object}]
|
|
19
19
|
diff: {type: string}
|
|
20
|
-
MergedReviewResult
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
summary:
|
|
20
|
+
# Canonical schema — STRAT-CLAUDE-EFFORT-PARITY. Local MergedReviewResult removed.
|
|
21
|
+
ReviewResult:
|
|
22
|
+
clean: {type: boolean}
|
|
23
|
+
summary: {type: string}
|
|
24
|
+
findings: {type: array}
|
|
25
|
+
meta: {type: object}
|
|
26
|
+
lenses_run: {type: array}
|
|
27
|
+
auto_fixes: {type: array}
|
|
28
|
+
asks: {type: array}
|
|
24
29
|
|
|
25
30
|
workflow:
|
|
26
31
|
name: team-review
|
|
@@ -38,7 +43,7 @@ flows:
|
|
|
38
43
|
input:
|
|
39
44
|
featureCode: {type: string}
|
|
40
45
|
description: {type: string}
|
|
41
|
-
output:
|
|
46
|
+
output: ReviewResult
|
|
42
47
|
steps:
|
|
43
48
|
- id: triage
|
|
44
49
|
agent: "claude:orchestrator"
|
|
@@ -76,9 +81,9 @@ flows:
|
|
|
76
81
|
Confidence gate: only report findings with confidence >= {confidence_gate}/10.
|
|
77
82
|
Exclusions: do NOT flag {exclusions}.
|
|
78
83
|
|
|
79
|
-
Return JSON: { "clean": boolean, "findings":
|
|
84
|
+
Return JSON: { "clean": boolean, "findings": <ReviewResult finding items> }
|
|
80
85
|
where each finding has: lens, file, line, severity (must-fix|should-fix|nit),
|
|
81
|
-
finding (description), confidence (1-10).
|
|
86
|
+
finding (description), confidence (1-10), applied_gate (integer).
|
|
82
87
|
|
|
83
88
|
If no issues found, return { "clean": true, "findings": [] }.
|
|
84
89
|
output_fields:
|
|
@@ -92,15 +97,17 @@ flows:
|
|
|
92
97
|
agent: "claude:orchestrator"
|
|
93
98
|
depends_on: [review_lenses]
|
|
94
99
|
intent: >
|
|
95
|
-
Consolidate
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
Consolidate ReviewResult arrays from all review lenses into a single
|
|
101
|
+
canonical ReviewResult. Deduplicate findings (same file:line+lens,
|
|
102
|
+
keep highest confidence; carry over its applied_gate). Rank by
|
|
103
|
+
severity (must-fix first, then should-fix, then nit). Set clean=true
|
|
104
|
+
only if zero must-fix AND zero should-fix findings remain. Write a
|
|
105
|
+
one-sentence summary.
|
|
100
106
|
inputs:
|
|
101
107
|
review_results: "$.steps.review_lenses.output"
|
|
102
|
-
|
|
108
|
+
reduce_mode: "true"
|
|
109
|
+
output_contract: ReviewResult
|
|
103
110
|
ensure:
|
|
104
|
-
- "result.
|
|
111
|
+
- "result.clean == True"
|
|
105
112
|
- "result.summary != ''"
|
|
106
113
|
retries: 2
|
|
@@ -455,6 +455,22 @@ export class BuildStreamBridge {
|
|
|
455
455
|
_source: 'build',
|
|
456
456
|
};
|
|
457
457
|
|
|
458
|
+
// STRAT-PAR-STREAM: typed BuildStreamEvent envelope (schema v0.2.5+) wrapped
|
|
459
|
+
// by build.js as { type: 'build_stream_event', event: {...} }. Pass the
|
|
460
|
+
// inner envelope through to the cockpit unchanged so renderers can
|
|
461
|
+
// discriminate by `kind`.
|
|
462
|
+
case 'build_stream_event': {
|
|
463
|
+
const inner = event.event;
|
|
464
|
+
if (!inner || typeof inner !== 'object' || typeof inner.kind !== 'string') {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
type: 'buildStreamEvent',
|
|
469
|
+
event: inner,
|
|
470
|
+
_source: 'build',
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
458
474
|
// COMP-HEALTH item 118: health score after build completion
|
|
459
475
|
case 'health_score':
|
|
460
476
|
return {
|
|
@@ -465,6 +481,18 @@ export class BuildStreamBridge {
|
|
|
465
481
|
_source: 'build',
|
|
466
482
|
};
|
|
467
483
|
|
|
484
|
+
// COMP-AGENT-CAPS-5: capability violation audit events
|
|
485
|
+
case 'capability_violation':
|
|
486
|
+
return {
|
|
487
|
+
type: 'system', subtype: 'capability_violation',
|
|
488
|
+
stepId: event.stepId,
|
|
489
|
+
agent: event.agent,
|
|
490
|
+
template: event.template,
|
|
491
|
+
detail: event.detail,
|
|
492
|
+
severity: event.severity ?? 'violation',
|
|
493
|
+
_source: 'build',
|
|
494
|
+
};
|
|
495
|
+
|
|
468
496
|
default:
|
|
469
497
|
return null; // unknown event type — skip
|
|
470
498
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC-session → feature_code resolver — COMP-OBS-BRANCH T2.
|
|
3
|
+
*
|
|
4
|
+
* Forge session ids (`session-<ts>-<hex>` from SessionManager) and Claude Code
|
|
5
|
+
* session uuids live in different namespaces. The only join key is
|
|
6
|
+
* `sessions.json[i].transcriptPath` — its basename is `<cc_session_id>.jsonl`.
|
|
7
|
+
*
|
|
8
|
+
* Resolution tiers (per blueprint §5):
|
|
9
|
+
* 1. Primary — sessions.json scan, match basename(transcriptPath)
|
|
10
|
+
* 2. Fallback — probe <featureRoot>/<CODE>/sessions/<cc_session_id>.*
|
|
11
|
+
* 3. Unbound — null (caller skips emission)
|
|
12
|
+
*
|
|
13
|
+
* Results cache per cc_session_id; invalidated on mtime bump of either
|
|
14
|
+
* sessions.json or the matched feature's sessions/ directory.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
|
|
20
|
+
function statMtime(p) {
|
|
21
|
+
try { return fs.statSync(p).mtimeMs; } catch { return null; }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function loadSessionsJson(sessionsFile) {
|
|
25
|
+
try {
|
|
26
|
+
const raw = fs.readFileSync(sessionsFile, 'utf8');
|
|
27
|
+
const arr = JSON.parse(raw);
|
|
28
|
+
return Array.isArray(arr) ? arr : [];
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class CCSessionFeatureResolver {
|
|
35
|
+
constructor({ sessionsFile, featureRoot }) {
|
|
36
|
+
if (!sessionsFile) throw new Error('sessionsFile required');
|
|
37
|
+
if (!featureRoot) throw new Error('featureRoot required');
|
|
38
|
+
this.sessionsFile = sessionsFile;
|
|
39
|
+
this.featureRoot = featureRoot;
|
|
40
|
+
this._cache = new Map(); // cc_session_id → { feature_code, sessionsMtime, featureDirMtime }
|
|
41
|
+
this._sessionsIndex = null;
|
|
42
|
+
this._sessionsMtime = null;
|
|
43
|
+
this.stats = { unbound_count: 0 };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_refreshIndex() {
|
|
47
|
+
const mtime = statMtime(this.sessionsFile);
|
|
48
|
+
if (mtime === this._sessionsMtime && this._sessionsIndex) return;
|
|
49
|
+
this._sessionsMtime = mtime;
|
|
50
|
+
const sessions = loadSessionsJson(this.sessionsFile);
|
|
51
|
+
const idx = new Map();
|
|
52
|
+
for (const s of sessions) {
|
|
53
|
+
const tp = s?.transcriptPath;
|
|
54
|
+
if (!tp || !s?.featureCode) continue;
|
|
55
|
+
const base = path.basename(tp);
|
|
56
|
+
const ccId = base.replace(/\.jsonl$/, '');
|
|
57
|
+
if (!idx.has(ccId)) idx.set(ccId, s.featureCode);
|
|
58
|
+
}
|
|
59
|
+
this._sessionsIndex = idx;
|
|
60
|
+
this._cache.clear();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_fallbackProbe(cc_session_id) {
|
|
64
|
+
let entries;
|
|
65
|
+
try { entries = fs.readdirSync(this.featureRoot, { withFileTypes: true }); }
|
|
66
|
+
catch { return null; }
|
|
67
|
+
for (const ent of entries) {
|
|
68
|
+
if (!ent.isDirectory()) continue;
|
|
69
|
+
const sessionsDir = path.join(this.featureRoot, ent.name, 'sessions');
|
|
70
|
+
let files;
|
|
71
|
+
try { files = fs.readdirSync(sessionsDir); } catch { continue; }
|
|
72
|
+
if (files.some(f => f.startsWith(cc_session_id + '.'))) {
|
|
73
|
+
return ent.name;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
resolve(cc_session_id) {
|
|
80
|
+
if (!cc_session_id) return null;
|
|
81
|
+
this._refreshIndex();
|
|
82
|
+
|
|
83
|
+
const cached = this._cache.get(cc_session_id);
|
|
84
|
+
if (cached && cached.sessionsMtime === this._sessionsMtime) {
|
|
85
|
+
if (cached.feature_code == null) return null;
|
|
86
|
+
const curDirMtime = statMtime(path.join(this.featureRoot, cached.feature_code, 'sessions'));
|
|
87
|
+
if (curDirMtime === cached.featureDirMtime) return cached.feature_code;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let fc = this._sessionsIndex.get(cc_session_id);
|
|
91
|
+
if (!fc) fc = this._fallbackProbe(cc_session_id);
|
|
92
|
+
|
|
93
|
+
if (fc) {
|
|
94
|
+
const dirMtime = statMtime(path.join(this.featureRoot, fc, 'sessions'));
|
|
95
|
+
this._cache.set(cc_session_id, {
|
|
96
|
+
feature_code: fc,
|
|
97
|
+
sessionsMtime: this._sessionsMtime,
|
|
98
|
+
featureDirMtime: dirMtime,
|
|
99
|
+
});
|
|
100
|
+
return fc;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this._cache.set(cc_session_id, {
|
|
104
|
+
feature_code: null,
|
|
105
|
+
sessionsMtime: this._sessionsMtime,
|
|
106
|
+
featureDirMtime: null,
|
|
107
|
+
});
|
|
108
|
+
this.stats.unbound_count++;
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|