@leing2021/super-pi 0.23.1 → 0.23.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.
|
@@ -326,6 +326,11 @@ const contextHandoffParams = Type.Object({
|
|
|
326
326
|
artifacts: Type.Optional(Type.Record(Type.String(), Type.Optional(Type.String()), { description: "Artifact paths (requirements, plan, checkpoint, proof)" })),
|
|
327
327
|
handoffMarkdown: Type.Optional(Type.String({ description: "Custom handoff markdown content" })),
|
|
328
328
|
handoffPath: Type.Optional(Type.String({ description: "Specific handoff file path to load" })),
|
|
329
|
+
currentTruth: Type.Optional(Type.Array(Type.String(), { description: "Known true statements validated during session" })),
|
|
330
|
+
invalidatedAssumptions: Type.Optional(Type.Array(Type.String(), { description: "Assumptions proven wrong during session" })),
|
|
331
|
+
openDecisions: Type.Optional(Type.Array(Type.String(), { description: "Pending decisions that affect next steps" })),
|
|
332
|
+
recentlyAccessedFiles: Type.Optional(Type.Array(Type.String(), { description: "Files recently read or edited (defaults to activeFiles)" })),
|
|
333
|
+
compressionRisk: Type.Optional(Type.Array(Type.String(), { description: "Context compression risks to watch for" })),
|
|
329
334
|
})
|
|
330
335
|
|
|
331
336
|
const patternExtractorParams = Type.Object({
|
|
@@ -758,6 +763,11 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
|
|
|
758
763
|
artifacts: params.artifacts as Record<string, string | undefined> | undefined,
|
|
759
764
|
handoffMarkdown: params.handoffMarkdown,
|
|
760
765
|
handoffPath: params.handoffPath,
|
|
766
|
+
currentTruth: params.currentTruth,
|
|
767
|
+
invalidatedAssumptions: params.invalidatedAssumptions,
|
|
768
|
+
openDecisions: params.openDecisions,
|
|
769
|
+
recentlyAccessedFiles: params.recentlyAccessedFiles,
|
|
770
|
+
compressionRisk: params.compressionRisk,
|
|
761
771
|
})
|
|
762
772
|
|
|
763
773
|
return {
|
|
@@ -17,6 +17,11 @@ export interface ContextHandoffInput {
|
|
|
17
17
|
artifacts?: Record<string, string | undefined>
|
|
18
18
|
handoffMarkdown?: string
|
|
19
19
|
handoffPath?: string
|
|
20
|
+
currentTruth?: string[]
|
|
21
|
+
invalidatedAssumptions?: string[]
|
|
22
|
+
openDecisions?: string[]
|
|
23
|
+
recentlyAccessedFiles?: string[]
|
|
24
|
+
compressionRisk?: string[]
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
export interface ContextStateEntry {
|
|
@@ -29,6 +34,11 @@ export interface ContextStateEntry {
|
|
|
29
34
|
blocker?: string
|
|
30
35
|
verification?: string
|
|
31
36
|
artifacts: Record<string, string | undefined>
|
|
37
|
+
currentTruth: string[]
|
|
38
|
+
invalidatedAssumptions: string[]
|
|
39
|
+
openDecisions: string[]
|
|
40
|
+
recentlyAccessedFiles: string[]
|
|
41
|
+
compressionRisk: string[]
|
|
32
42
|
recommendNewSession: boolean
|
|
33
43
|
updatedAt: string
|
|
34
44
|
}
|
|
@@ -47,6 +57,11 @@ export interface ContextHandoffResult {
|
|
|
47
57
|
artifacts?: Record<string, string | undefined>
|
|
48
58
|
recommendNewSession?: boolean
|
|
49
59
|
handoffMarkdown?: string
|
|
60
|
+
currentTruth?: string[]
|
|
61
|
+
invalidatedAssumptions?: string[]
|
|
62
|
+
openDecisions?: string[]
|
|
63
|
+
recentlyAccessedFiles?: string[]
|
|
64
|
+
compressionRisk?: string[]
|
|
50
65
|
updatedAt?: string
|
|
51
66
|
}
|
|
52
67
|
|
|
@@ -112,6 +127,11 @@ function buildDefaultHandoffMarkdown(input: {
|
|
|
112
127
|
artifacts: Record<string, string | undefined>
|
|
113
128
|
blocker?: string
|
|
114
129
|
verification?: string
|
|
130
|
+
currentTruth: string[]
|
|
131
|
+
invalidatedAssumptions: string[]
|
|
132
|
+
openDecisions: string[]
|
|
133
|
+
recentlyAccessedFiles: string[]
|
|
134
|
+
compressionRisk: string[]
|
|
115
135
|
}): string {
|
|
116
136
|
const currentTask = input.nextStage
|
|
117
137
|
? `Continue from ${input.currentStage} to ${input.nextStage}.`
|
|
@@ -137,12 +157,24 @@ function buildDefaultHandoffMarkdown(input: {
|
|
|
137
157
|
"## Hot Context",
|
|
138
158
|
hotContext,
|
|
139
159
|
"",
|
|
160
|
+
"## Current Truth",
|
|
161
|
+
formatBullets(input.currentTruth),
|
|
162
|
+
"",
|
|
140
163
|
"## Verified Facts",
|
|
141
164
|
verifiedFacts,
|
|
142
165
|
"",
|
|
166
|
+
"## Invalidated Assumptions",
|
|
167
|
+
formatBullets(input.invalidatedAssumptions),
|
|
168
|
+
"",
|
|
169
|
+
"## Open Decisions",
|
|
170
|
+
formatBullets(input.openDecisions),
|
|
171
|
+
"",
|
|
143
172
|
"## Active Files",
|
|
144
173
|
activeFiles,
|
|
145
174
|
"",
|
|
175
|
+
"## Recently Accessed Files",
|
|
176
|
+
formatBullets(input.recentlyAccessedFiles),
|
|
177
|
+
"",
|
|
146
178
|
"## Artifacts",
|
|
147
179
|
artifacts,
|
|
148
180
|
"",
|
|
@@ -152,6 +184,9 @@ function buildDefaultHandoffMarkdown(input: {
|
|
|
152
184
|
"## Verification",
|
|
153
185
|
`- ${verification}`,
|
|
154
186
|
"",
|
|
187
|
+
"## Compression Risk",
|
|
188
|
+
formatBullets(input.compressionRisk),
|
|
189
|
+
"",
|
|
155
190
|
"## Do Not Repeat",
|
|
156
191
|
"- Do not reload full history unless the handoff lacks required evidence.",
|
|
157
192
|
"",
|
|
@@ -161,13 +196,54 @@ function buildDefaultHandoffMarkdown(input: {
|
|
|
161
196
|
].join("\n")
|
|
162
197
|
}
|
|
163
198
|
|
|
199
|
+
function toStringArray(value: unknown): string[] {
|
|
200
|
+
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : []
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function normalizeStateEntry(raw: unknown): ContextStateEntry | null {
|
|
204
|
+
if (!raw || typeof raw !== "object") return null
|
|
205
|
+
|
|
206
|
+
const state = raw as Record<string, unknown>
|
|
207
|
+
const activeFiles = toStringArray(state.activeFiles)
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
currentStage: typeof state.currentStage === "string" ? state.currentStage : "unknown",
|
|
211
|
+
nextStage: typeof state.nextStage === "string" ? state.nextStage : undefined,
|
|
212
|
+
contextHealth: isContextHealth(state.contextHealth) ? state.contextHealth : "watch",
|
|
213
|
+
latestHandoffPath: typeof state.latestHandoffPath === "string" ? state.latestHandoffPath : undefined,
|
|
214
|
+
latestDatedHandoffPath: typeof state.latestDatedHandoffPath === "string" ? state.latestDatedHandoffPath : undefined,
|
|
215
|
+
activeFiles,
|
|
216
|
+
blocker: typeof state.blocker === "string" ? state.blocker : undefined,
|
|
217
|
+
verification: typeof state.verification === "string" ? state.verification : undefined,
|
|
218
|
+
artifacts: isStringRecord(state.artifacts) ? state.artifacts : {},
|
|
219
|
+
currentTruth: toStringArray(state.currentTruth),
|
|
220
|
+
invalidatedAssumptions: toStringArray(state.invalidatedAssumptions),
|
|
221
|
+
openDecisions: toStringArray(state.openDecisions),
|
|
222
|
+
recentlyAccessedFiles: toStringArray(state.recentlyAccessedFiles).length > 0
|
|
223
|
+
? toStringArray(state.recentlyAccessedFiles)
|
|
224
|
+
: activeFiles.slice(0, 5),
|
|
225
|
+
compressionRisk: toStringArray(state.compressionRisk),
|
|
226
|
+
recommendNewSession: typeof state.recommendNewSession === "boolean" ? state.recommendNewSession : false,
|
|
227
|
+
updatedAt: typeof state.updatedAt === "string" ? state.updatedAt : new Date(0).toISOString(),
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function isContextHealth(value: unknown): value is ContextHealth {
|
|
232
|
+
return value === "good" || value === "watch" || value === "heavy" || value === "critical"
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isStringRecord(value: unknown): value is Record<string, string | undefined> {
|
|
236
|
+
if (!value || typeof value !== "object") return false
|
|
237
|
+
return Object.values(value).every(item => item === undefined || typeof item === "string")
|
|
238
|
+
}
|
|
239
|
+
|
|
164
240
|
async function readState(repoRoot: string): Promise<ContextStateEntry | null> {
|
|
165
241
|
const filePath = stateFilePath(repoRoot)
|
|
166
242
|
if (!existsSync(filePath)) return null
|
|
167
243
|
|
|
168
244
|
try {
|
|
169
245
|
const content = await readFile(filePath, "utf8")
|
|
170
|
-
return JSON.parse(content)
|
|
246
|
+
return normalizeStateEntry(JSON.parse(content))
|
|
171
247
|
} catch {
|
|
172
248
|
return null
|
|
173
249
|
}
|
|
@@ -207,6 +283,14 @@ async function save(input: ContextHandoffInput): Promise<ContextHandoffResult> {
|
|
|
207
283
|
const blocker = input.blocker
|
|
208
284
|
const verification = input.verification
|
|
209
285
|
const artifacts = input.artifacts ?? {}
|
|
286
|
+
const currentTruth = input.currentTruth ?? []
|
|
287
|
+
const invalidatedAssumptions = input.invalidatedAssumptions ?? []
|
|
288
|
+
const openDecisions = input.openDecisions ?? []
|
|
289
|
+
const recentlyAccessedFiles = input.recentlyAccessedFiles?.length
|
|
290
|
+
? input.recentlyAccessedFiles
|
|
291
|
+
: activeFiles.slice(0, 5)
|
|
292
|
+
const compressionRisk = input.compressionRisk ?? []
|
|
293
|
+
|
|
210
294
|
const handoffMarkdown = input.handoffMarkdown?.trim().length
|
|
211
295
|
? input.handoffMarkdown
|
|
212
296
|
: buildDefaultHandoffMarkdown({
|
|
@@ -216,6 +300,11 @@ async function save(input: ContextHandoffInput): Promise<ContextHandoffResult> {
|
|
|
216
300
|
artifacts,
|
|
217
301
|
blocker,
|
|
218
302
|
verification,
|
|
303
|
+
currentTruth,
|
|
304
|
+
invalidatedAssumptions,
|
|
305
|
+
openDecisions,
|
|
306
|
+
recentlyAccessedFiles,
|
|
307
|
+
compressionRisk,
|
|
219
308
|
})
|
|
220
309
|
|
|
221
310
|
const recommendNewSession = computeRecommendNewSession(currentStage, nextStage, contextHealth)
|
|
@@ -238,6 +327,11 @@ async function save(input: ContextHandoffInput): Promise<ContextHandoffResult> {
|
|
|
238
327
|
blocker,
|
|
239
328
|
verification,
|
|
240
329
|
artifacts,
|
|
330
|
+
currentTruth,
|
|
331
|
+
invalidatedAssumptions,
|
|
332
|
+
openDecisions,
|
|
333
|
+
recentlyAccessedFiles,
|
|
334
|
+
compressionRisk,
|
|
241
335
|
recommendNewSession,
|
|
242
336
|
updatedAt: new Date().toISOString(),
|
|
243
337
|
}
|
|
@@ -256,6 +350,11 @@ async function save(input: ContextHandoffInput): Promise<ContextHandoffResult> {
|
|
|
256
350
|
blocker,
|
|
257
351
|
verification,
|
|
258
352
|
artifacts,
|
|
353
|
+
currentTruth,
|
|
354
|
+
invalidatedAssumptions,
|
|
355
|
+
openDecisions,
|
|
356
|
+
recentlyAccessedFiles,
|
|
357
|
+
compressionRisk,
|
|
259
358
|
recommendNewSession,
|
|
260
359
|
updatedAt: state.updatedAt,
|
|
261
360
|
}
|
|
@@ -291,6 +390,11 @@ async function load(input: ContextHandoffInput): Promise<ContextHandoffResult> {
|
|
|
291
390
|
blocker: state.blocker,
|
|
292
391
|
verification: state.verification,
|
|
293
392
|
artifacts: state.artifacts,
|
|
393
|
+
currentTruth: state.currentTruth,
|
|
394
|
+
invalidatedAssumptions: state.invalidatedAssumptions,
|
|
395
|
+
openDecisions: state.openDecisions,
|
|
396
|
+
recentlyAccessedFiles: state.recentlyAccessedFiles,
|
|
397
|
+
compressionRisk: state.compressionRisk,
|
|
294
398
|
recommendNewSession: state.recommendNewSession,
|
|
295
399
|
handoffMarkdown: markdown,
|
|
296
400
|
updatedAt: state.updatedAt,
|
|
@@ -320,6 +424,11 @@ async function latest(input: ContextHandoffInput): Promise<ContextHandoffResult>
|
|
|
320
424
|
blocker: state.blocker,
|
|
321
425
|
verification: state.verification,
|
|
322
426
|
artifacts: state.artifacts,
|
|
427
|
+
currentTruth: state.currentTruth,
|
|
428
|
+
invalidatedAssumptions: state.invalidatedAssumptions,
|
|
429
|
+
openDecisions: state.openDecisions,
|
|
430
|
+
recentlyAccessedFiles: state.recentlyAccessedFiles,
|
|
431
|
+
compressionRisk: state.compressionRisk,
|
|
323
432
|
recommendNewSession: state.recommendNewSession,
|
|
324
433
|
updatedAt: state.updatedAt,
|
|
325
434
|
}
|
|
@@ -351,6 +460,11 @@ async function status(input: ContextHandoffInput): Promise<ContextHandoffResult>
|
|
|
351
460
|
blocker: state.blocker,
|
|
352
461
|
verification: state.verification,
|
|
353
462
|
artifacts: state.artifacts,
|
|
463
|
+
currentTruth: state.currentTruth,
|
|
464
|
+
invalidatedAssumptions: state.invalidatedAssumptions,
|
|
465
|
+
openDecisions: state.openDecisions,
|
|
466
|
+
recentlyAccessedFiles: state.recentlyAccessedFiles,
|
|
467
|
+
compressionRisk: state.compressionRisk,
|
|
354
468
|
recommendNewSession: state.recommendNewSession,
|
|
355
469
|
updatedAt: state.updatedAt,
|
|
356
470
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdirSync,
|
|
1
|
+
import { readdirSync, existsSync, readFileSync } from "node:fs"
|
|
2
2
|
import path from "node:path"
|
|
3
3
|
|
|
4
4
|
export interface WorkflowCategoryState {
|
|
@@ -6,6 +6,25 @@ export interface WorkflowCategoryState {
|
|
|
6
6
|
latest: string | null
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export interface WorkflowContextState {
|
|
10
|
+
found: boolean
|
|
11
|
+
currentStage?: string
|
|
12
|
+
nextStage?: string
|
|
13
|
+
contextHealth?: string
|
|
14
|
+
latestHandoffPath?: string
|
|
15
|
+
latestDatedHandoffPath?: string
|
|
16
|
+
activeFiles: string[]
|
|
17
|
+
recentlyAccessedFiles: string[]
|
|
18
|
+
blocker?: string
|
|
19
|
+
verification?: string
|
|
20
|
+
currentTruth: string[]
|
|
21
|
+
invalidatedAssumptions: string[]
|
|
22
|
+
openDecisions: string[]
|
|
23
|
+
compressionRisk: string[]
|
|
24
|
+
recommendNewSession?: boolean
|
|
25
|
+
updatedAt?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
export interface WorkflowStateInput {
|
|
10
29
|
repoRoot: string
|
|
11
30
|
}
|
|
@@ -15,6 +34,7 @@ export interface WorkflowStateResult {
|
|
|
15
34
|
plans: WorkflowCategoryState
|
|
16
35
|
solutions: WorkflowCategoryState
|
|
17
36
|
runs: WorkflowCategoryState
|
|
37
|
+
context: WorkflowContextState
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
function emptyCategory(): WorkflowCategoryState {
|
|
@@ -63,6 +83,52 @@ function collectFiles(dirPath: string): string[] {
|
|
|
63
83
|
return results
|
|
64
84
|
}
|
|
65
85
|
|
|
86
|
+
function emptyContext(): WorkflowContextState {
|
|
87
|
+
return {
|
|
88
|
+
found: false,
|
|
89
|
+
activeFiles: [],
|
|
90
|
+
recentlyAccessedFiles: [],
|
|
91
|
+
currentTruth: [],
|
|
92
|
+
invalidatedAssumptions: [],
|
|
93
|
+
openDecisions: [],
|
|
94
|
+
compressionRisk: [],
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function toStringArray(value: unknown): string[] {
|
|
99
|
+
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : []
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function readContextState(repoRoot: string): WorkflowContextState {
|
|
103
|
+
const statePath = path.join(repoRoot, ".context", "compound-engineering", "context-state.json")
|
|
104
|
+
if (!existsSync(statePath)) return emptyContext()
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const raw = readFileSync(statePath, "utf8")
|
|
108
|
+
const state = JSON.parse(raw) as Record<string, unknown>
|
|
109
|
+
return {
|
|
110
|
+
found: true,
|
|
111
|
+
currentStage: typeof state.currentStage === "string" ? state.currentStage : undefined,
|
|
112
|
+
nextStage: typeof state.nextStage === "string" ? state.nextStage : undefined,
|
|
113
|
+
contextHealth: typeof state.contextHealth === "string" ? state.contextHealth : undefined,
|
|
114
|
+
latestHandoffPath: typeof state.latestHandoffPath === "string" ? state.latestHandoffPath : undefined,
|
|
115
|
+
latestDatedHandoffPath: typeof state.latestDatedHandoffPath === "string" ? state.latestDatedHandoffPath : undefined,
|
|
116
|
+
activeFiles: toStringArray(state.activeFiles),
|
|
117
|
+
recentlyAccessedFiles: toStringArray(state.recentlyAccessedFiles),
|
|
118
|
+
blocker: typeof state.blocker === "string" ? state.blocker : undefined,
|
|
119
|
+
verification: typeof state.verification === "string" ? state.verification : undefined,
|
|
120
|
+
currentTruth: toStringArray(state.currentTruth),
|
|
121
|
+
invalidatedAssumptions: toStringArray(state.invalidatedAssumptions),
|
|
122
|
+
openDecisions: toStringArray(state.openDecisions),
|
|
123
|
+
compressionRisk: toStringArray(state.compressionRisk),
|
|
124
|
+
recommendNewSession: typeof state.recommendNewSession === "boolean" ? state.recommendNewSession : undefined,
|
|
125
|
+
updatedAt: typeof state.updatedAt === "string" ? state.updatedAt : undefined,
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
return emptyContext()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
66
132
|
export function createWorkflowStateTool() {
|
|
67
133
|
return {
|
|
68
134
|
name: "workflow_state",
|
|
@@ -74,6 +140,7 @@ export function createWorkflowStateTool() {
|
|
|
74
140
|
plans: scanDir(path.join(repoRoot, "docs", "plans")),
|
|
75
141
|
solutions: scanDir(path.join(repoRoot, "docs", "solutions")),
|
|
76
142
|
runs: scanDir(path.join(repoRoot, ".context", "compound-engineering")),
|
|
143
|
+
context: readContextState(repoRoot),
|
|
77
144
|
}
|
|
78
145
|
},
|
|
79
146
|
}
|
package/package.json
CHANGED
|
@@ -55,12 +55,24 @@ When a stage produces or updates handoff-lite, use this evidence-first structure
|
|
|
55
55
|
## Hot Context
|
|
56
56
|
- 1-5 must-know facts for the next step
|
|
57
57
|
|
|
58
|
+
## Current Truth
|
|
59
|
+
- validated truths that must survive compression
|
|
60
|
+
|
|
58
61
|
## Verified Facts
|
|
59
62
|
- already validated facts (do not re-prove)
|
|
60
63
|
|
|
64
|
+
## Invalidated Assumptions
|
|
65
|
+
- assumptions proven wrong this session
|
|
66
|
+
|
|
67
|
+
## Open Decisions
|
|
68
|
+
- pending decisions that affect next steps
|
|
69
|
+
|
|
61
70
|
## Active Files
|
|
62
71
|
- 1-5 file paths only
|
|
63
72
|
|
|
73
|
+
## Recently Accessed Files
|
|
74
|
+
- files recently read or edited
|
|
75
|
+
|
|
64
76
|
## Artifacts
|
|
65
77
|
- requirements: <path or N/A>
|
|
66
78
|
- plan: <path or N/A>
|
|
@@ -73,6 +85,9 @@ When a stage produces or updates handoff-lite, use this evidence-first structure
|
|
|
73
85
|
## Verification
|
|
74
86
|
- <latest command + result or Not run>
|
|
75
87
|
|
|
88
|
+
## Compression Risk
|
|
89
|
+
- context compression risks to watch for
|
|
90
|
+
|
|
76
91
|
## Do Not Repeat
|
|
77
92
|
- what should not be re-read/re-run unless needed
|
|
78
93
|
|