@leing2021/super-pi 0.14.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.
Files changed (53) hide show
  1. package/README.md +372 -0
  2. package/extensions/.gitkeep +0 -0
  3. package/extensions/ce-core/index.ts +528 -0
  4. package/extensions/ce-core/tools/artifact-helper.ts +73 -0
  5. package/extensions/ce-core/tools/ask-user-question.ts +53 -0
  6. package/extensions/ce-core/tools/brainstorm-dialog.ts +167 -0
  7. package/extensions/ce-core/tools/parallel-subagent.ts +54 -0
  8. package/extensions/ce-core/tools/pattern-extractor.ts +139 -0
  9. package/extensions/ce-core/tools/plan-diff.ts +136 -0
  10. package/extensions/ce-core/tools/review-router.ts +95 -0
  11. package/extensions/ce-core/tools/session-checkpoint.ts +212 -0
  12. package/extensions/ce-core/tools/session-history.ts +117 -0
  13. package/extensions/ce-core/tools/subagent.ts +59 -0
  14. package/extensions/ce-core/tools/task-splitter.ts +122 -0
  15. package/extensions/ce-core/tools/workflow-state.ts +80 -0
  16. package/extensions/ce-core/tools/worktree-manager.ts +131 -0
  17. package/extensions/ce-core/utils/artifact-paths.ts +23 -0
  18. package/extensions/ce-core/utils/name-utils.ts +8 -0
  19. package/package.json +53 -0
  20. package/skills/.gitkeep +0 -0
  21. package/skills/01-brainstorm/SKILL.md +120 -0
  22. package/skills/01-brainstorm/references/builder-mode.md +39 -0
  23. package/skills/01-brainstorm/references/handoff.md +8 -0
  24. package/skills/01-brainstorm/references/premise-challenge.md +23 -0
  25. package/skills/01-brainstorm/references/requirements-template.md +25 -0
  26. package/skills/01-brainstorm/references/startup-diagnostic.md +108 -0
  27. package/skills/02-plan/SKILL.md +77 -0
  28. package/skills/02-plan/references/ceo-review-mode.md +130 -0
  29. package/skills/02-plan/references/handoff.md +8 -0
  30. package/skills/02-plan/references/implementation-unit-template.md +25 -0
  31. package/skills/02-plan/references/plan-template.md +21 -0
  32. package/skills/03-work/SKILL.md +65 -0
  33. package/skills/03-work/references/handoff.md +8 -0
  34. package/skills/03-work/references/progress-update-format.md +17 -0
  35. package/skills/04-review/SKILL.md +72 -0
  36. package/skills/04-review/references/findings-schema.md +17 -0
  37. package/skills/04-review/references/handoff.md +20 -0
  38. package/skills/04-review/references/qa-test-mode.md +134 -0
  39. package/skills/04-review/references/reviewer-selection.md +24 -0
  40. package/skills/05-compound/SKILL.md +32 -0
  41. package/skills/05-compound/assets/solution-template.md +27 -0
  42. package/skills/05-compound/references/category-map.md +9 -0
  43. package/skills/05-compound/references/overlap-rules.md +7 -0
  44. package/skills/05-compound/references/solution-schema.yaml +27 -0
  45. package/skills/05-compound/references/solution-search-strategy.md +60 -0
  46. package/skills/06-next/SKILL.md +37 -0
  47. package/skills/06-next/references/recommendation-logic.md +46 -0
  48. package/skills/07-worktree/SKILL.md +35 -0
  49. package/skills/07-worktree/references/worktree-lifecycle.md +22 -0
  50. package/skills/08-status/SKILL.md +41 -0
  51. package/skills/08-status/references/artifact-locations.md +10 -0
  52. package/skills/09-help/SKILL.md +37 -0
  53. package/skills/09-help/references/workflow-sequence.md +9 -0
@@ -0,0 +1,212 @@
1
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises"
2
+ import path from "node:path"
3
+ import { normalizeSlug } from "../utils/name-utils"
4
+
5
+ export interface SessionCheckpointInput {
6
+ operation: "save" | "load" | "list" | "fail" | "retry"
7
+ repoRoot: string
8
+ planPath?: string
9
+ completedUnits?: string[]
10
+ failedUnit?: string
11
+ error?: string
12
+ }
13
+
14
+ export interface CheckpointEntry {
15
+ planPath: string
16
+ completedUnits: string[]
17
+ updatedAt: string
18
+ status?: "active" | "failed"
19
+ failedUnit?: string
20
+ error?: string
21
+ }
22
+
23
+ export interface SessionCheckpointResult {
24
+ operation: string
25
+ planPath?: string
26
+ completedUnits?: string[]
27
+ updatedAt?: string
28
+ status?: string
29
+ failedUnit?: string
30
+ error?: string
31
+ strategy?: string
32
+ retryFrom?: string
33
+ checkpoints?: CheckpointEntry[]
34
+ }
35
+
36
+ function checkpointDir(repoRoot: string): string {
37
+ return path.join(repoRoot, ".context", "compound-engineering", "checkpoints")
38
+ }
39
+
40
+ function checkpointPath(repoRoot: string, planPath: string): string {
41
+ const slug = normalizeSlug(planPath.replace(/\//g, "-"))
42
+ return path.join(checkpointDir(repoRoot), `${slug}.json`)
43
+ }
44
+
45
+ export function createSessionCheckpointTool() {
46
+ return {
47
+ name: "session_checkpoint",
48
+ async execute(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
49
+ switch (input.operation) {
50
+ case "save":
51
+ return saveCheckpoint(input)
52
+ case "load":
53
+ return loadCheckpoint(input)
54
+ case "list":
55
+ return listCheckpoints(input)
56
+ case "fail":
57
+ return failCheckpoint(input)
58
+ case "retry":
59
+ return retryCheckpoint(input)
60
+ default:
61
+ throw new Error(`Unknown operation: ${input.operation}`)
62
+ }
63
+ },
64
+ }
65
+ }
66
+
67
+ async function readEntry(repoRoot: string, planPath: string): Promise<CheckpointEntry | null> {
68
+ const filePath = checkpointPath(repoRoot, planPath)
69
+ try {
70
+ const content = await readFile(filePath, "utf8")
71
+ return JSON.parse(content)
72
+ } catch {
73
+ return null
74
+ }
75
+ }
76
+
77
+ async function writeEntry(repoRoot: string, entry: CheckpointEntry): Promise<void> {
78
+ const filePath = checkpointPath(repoRoot, entry.planPath)
79
+ await mkdir(path.dirname(filePath), { recursive: true })
80
+ await writeFile(filePath, JSON.stringify(entry, null, 2), "utf8")
81
+ }
82
+
83
+ async function saveCheckpoint(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
84
+ const planPath = required(input.planPath, "planPath")
85
+ const completedUnits = input.completedUnits ?? []
86
+
87
+ const entry: CheckpointEntry = {
88
+ planPath,
89
+ completedUnits,
90
+ updatedAt: new Date().toISOString(),
91
+ status: "active",
92
+ }
93
+
94
+ await writeEntry(input.repoRoot, entry)
95
+
96
+ return {
97
+ operation: "save",
98
+ planPath,
99
+ completedUnits,
100
+ updatedAt: entry.updatedAt,
101
+ }
102
+ }
103
+
104
+ async function loadCheckpoint(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
105
+ const planPath = required(input.planPath, "planPath")
106
+ const entry = await readEntry(input.repoRoot, planPath)
107
+
108
+ if (!entry) {
109
+ return { operation: "load", planPath, completedUnits: [] }
110
+ }
111
+
112
+ return {
113
+ operation: "load",
114
+ planPath: entry.planPath,
115
+ completedUnits: entry.completedUnits,
116
+ updatedAt: entry.updatedAt,
117
+ }
118
+ }
119
+
120
+ async function listCheckpoints(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
121
+ const dir = checkpointDir(input.repoRoot)
122
+
123
+ try {
124
+ const files = await readdir(dir)
125
+ const checkpoints: CheckpointEntry[] = []
126
+
127
+ for (const file of files) {
128
+ if (file.endsWith(".json")) {
129
+ try {
130
+ const content = await readFile(path.join(dir, file), "utf8")
131
+ checkpoints.push(JSON.parse(content))
132
+ } catch {
133
+ // Skip malformed files
134
+ }
135
+ }
136
+ }
137
+
138
+ return { operation: "list", checkpoints }
139
+ } catch {
140
+ return { operation: "list", checkpoints: [] }
141
+ }
142
+ }
143
+
144
+ async function failCheckpoint(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
145
+ const planPath = required(input.planPath, "planPath")
146
+ const entry = await readEntry(input.repoRoot, planPath)
147
+
148
+ if (!entry) {
149
+ throw new Error("No checkpoint found. Use 'save' first.")
150
+ }
151
+
152
+ entry.status = "failed"
153
+ entry.failedUnit = input.failedUnit ?? ""
154
+ entry.error = input.error ?? ""
155
+ entry.updatedAt = new Date().toISOString()
156
+
157
+ await writeEntry(input.repoRoot, entry)
158
+
159
+ return {
160
+ operation: "fail",
161
+ planPath: entry.planPath,
162
+ status: "failed",
163
+ failedUnit: entry.failedUnit,
164
+ error: entry.error,
165
+ completedUnits: entry.completedUnits,
166
+ updatedAt: entry.updatedAt,
167
+ }
168
+ }
169
+
170
+ async function retryCheckpoint(input: SessionCheckpointInput): Promise<SessionCheckpointResult> {
171
+ const planPath = required(input.planPath, "planPath")
172
+ const entry = await readEntry(input.repoRoot, planPath)
173
+
174
+ if (!entry) {
175
+ throw new Error("No checkpoint found.")
176
+ }
177
+
178
+ if (entry.status !== "failed") {
179
+ throw new Error("Checkpoint is not in a failed state. Nothing to retry.")
180
+ }
181
+
182
+ // Determine retry strategy based on error type
183
+ const errorLower = (entry.error ?? "").toLowerCase()
184
+ let strategy = "retry-unit"
185
+
186
+ if (errorLower.includes("timeout")) {
187
+ strategy = "retry-with-longer-timeout"
188
+ } else if (errorLower.includes("permission") || errorLower.includes("access")) {
189
+ strategy = "check-permissions-then-retry"
190
+ } else if (errorLower.includes("typeerror") || errorLower.includes("syntax")) {
191
+ strategy = "fix-code-then-retry"
192
+ } else if (errorLower.includes("not found") || errorLower.includes("enoent")) {
193
+ strategy = "verify-files-then-retry"
194
+ }
195
+
196
+ return {
197
+ operation: "retry",
198
+ planPath: entry.planPath,
199
+ status: "retry",
200
+ retryFrom: entry.failedUnit,
201
+ completedUnits: entry.completedUnits,
202
+ strategy,
203
+ updatedAt: entry.updatedAt,
204
+ }
205
+ }
206
+
207
+ function required(value: string | undefined, field: string): string {
208
+ if (!value) {
209
+ throw new Error(`session_checkpoint requires ${field}`)
210
+ }
211
+ return value
212
+ }
@@ -0,0 +1,117 @@
1
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"
2
+ import path from "node:path"
3
+ import { normalizeSlug } from "../utils/name-utils"
4
+
5
+ export interface HistoryEntry {
6
+ id: string
7
+ skill: string
8
+ artifactPath: string
9
+ summary: string
10
+ timestamp: string
11
+ }
12
+
13
+ export interface SessionHistoryInput {
14
+ operation: "record" | "query" | "latest"
15
+ repoRoot: string
16
+ skill?: string
17
+ artifactPath?: string
18
+ summary?: string
19
+ }
20
+
21
+ export interface SessionHistoryResult {
22
+ operation: string
23
+ entries: HistoryEntry[]
24
+ }
25
+
26
+ function historyDir(repoRoot: string): string {
27
+ return path.join(repoRoot, ".context", "compound-engineering", "history")
28
+ }
29
+
30
+ let _counter = 0
31
+
32
+ export function _resetCounter() { _counter = 0 }
33
+
34
+ export function createSessionHistoryTool() {
35
+ return {
36
+ name: "session_history",
37
+ async execute(input: SessionHistoryInput): Promise<SessionHistoryResult> {
38
+ switch (input.operation) {
39
+ case "record":
40
+ return recordExecution(input)
41
+ case "query":
42
+ return queryHistory(input)
43
+ case "latest":
44
+ return latestPerSkill(input)
45
+ default:
46
+ throw new Error(`Unknown operation: ${input.operation}`)
47
+ }
48
+ },
49
+ }
50
+ }
51
+
52
+ async function ensureDir(dir: string): Promise<void> {
53
+ await mkdir(dir, { recursive: true })
54
+ }
55
+
56
+ async function readAllEntries(repoRoot: string): Promise<HistoryEntry[]> {
57
+ const dir = historyDir(repoRoot)
58
+ try {
59
+ const files = await readdir(dir)
60
+ const entries: HistoryEntry[] = []
61
+ for (const file of files) {
62
+ if (file.endsWith(".json")) {
63
+ try {
64
+ const content = await readFile(path.join(dir, file), "utf8")
65
+ entries.push(JSON.parse(content))
66
+ } catch {
67
+ // skip malformed
68
+ }
69
+ }
70
+ }
71
+ return entries.sort((a, b) => a.id.localeCompare(b.id))
72
+ } catch {
73
+ return []
74
+ }
75
+ }
76
+
77
+ async function recordExecution(input: SessionHistoryInput): Promise<SessionHistoryResult> {
78
+ const dir = historyDir(input.repoRoot)
79
+ await ensureDir(dir)
80
+
81
+ const id = `${Date.now()}-${String(++_counter).padStart(6, "0")}-${normalizeSlug(input.skill ?? "unknown")}`
82
+ const entry: HistoryEntry = {
83
+ id,
84
+ skill: input.skill ?? "",
85
+ artifactPath: input.artifactPath ?? "",
86
+ summary: input.summary ?? "",
87
+ timestamp: new Date().toISOString(),
88
+ }
89
+
90
+ const filePath = path.join(dir, `${id}.json`)
91
+ await writeFile(filePath, JSON.stringify(entry, null, 2), "utf8")
92
+
93
+ return { operation: "record", entries: [entry] }
94
+ }
95
+
96
+ async function queryHistory(input: SessionHistoryInput): Promise<SessionHistoryResult> {
97
+ const all = await readAllEntries(input.repoRoot)
98
+ const filtered = input.skill
99
+ ? all.filter((e) => e.skill === input.skill)
100
+ : all
101
+
102
+ return { operation: "query", entries: filtered }
103
+ }
104
+
105
+ async function latestPerSkill(input: SessionHistoryInput): Promise<SessionHistoryResult> {
106
+ const all = await readAllEntries(input.repoRoot)
107
+ const latestMap = new Map<string, HistoryEntry>()
108
+
109
+ for (const entry of all) {
110
+ const existing = latestMap.get(entry.skill)
111
+ if (!existing || entry.id > existing.id) {
112
+ latestMap.set(entry.skill, entry)
113
+ }
114
+ }
115
+
116
+ return { operation: "latest", entries: Array.from(latestMap.values()) }
117
+ }
@@ -0,0 +1,59 @@
1
+ export interface SubagentTask {
2
+ agent: string
3
+ task: string
4
+ }
5
+
6
+ export interface SubagentInput {
7
+ agent?: string
8
+ task?: string
9
+ chain?: SubagentTask[]
10
+ }
11
+
12
+ export interface SubagentResult {
13
+ mode: "single" | "chain"
14
+ outputs: string[]
15
+ }
16
+
17
+ export type SubagentRunner = (prompt: string) => Promise<string>
18
+
19
+ export function createSubagentTool() {
20
+ return {
21
+ name: "subagent",
22
+ async execute(input: SubagentInput, runner: SubagentRunner): Promise<SubagentResult> {
23
+ const hasSingle = Boolean(input.agent && input.task)
24
+ const hasChain = Boolean(input.chain && input.chain.length > 0)
25
+
26
+ if (Number(hasSingle) + Number(hasChain) !== 1) {
27
+ throw new Error("Provide exactly one mode: single or chain")
28
+ }
29
+
30
+ if (hasSingle) {
31
+ const prompt = buildPrompt(input.agent!, input.task!)
32
+ const output = await runner(prompt)
33
+ return {
34
+ mode: "single",
35
+ outputs: [output],
36
+ }
37
+ }
38
+
39
+ const outputs: string[] = []
40
+ let previous = ""
41
+
42
+ for (const task of input.chain ?? []) {
43
+ const prompt = buildPrompt(task.agent, task.task.replace(/\{previous\}/g, previous))
44
+ const output = await runner(prompt)
45
+ outputs.push(output)
46
+ previous = output
47
+ }
48
+
49
+ return {
50
+ mode: "chain",
51
+ outputs,
52
+ }
53
+ },
54
+ }
55
+ }
56
+
57
+ function buildPrompt(agent: string, task: string): string {
58
+ return `/skill:${agent} ${task}`
59
+ }
@@ -0,0 +1,122 @@
1
+ export interface SplitterUnit {
2
+ name: string
3
+ files: string[]
4
+ }
5
+
6
+ export interface SplitterGroup {
7
+ units: string[]
8
+ parallelSafe: boolean
9
+ sharedFiles?: string[]
10
+ }
11
+
12
+ export interface TaskSplitterInput {
13
+ units: SplitterUnit[]
14
+ }
15
+
16
+ export interface TaskSplitterResult {
17
+ groups: SplitterGroup[]
18
+ independentUnits: string[]
19
+ dependentUnits: string[]
20
+ }
21
+
22
+ export function createTaskSplitterTool() {
23
+ return {
24
+ name: "task_splitter",
25
+ execute(input: TaskSplitterInput): TaskSplitterResult {
26
+ if (input.units.length === 0) {
27
+ return { groups: [], independentUnits: [], dependentUnits: [] }
28
+ }
29
+
30
+ // Build file → unit names map
31
+ const fileToUnits = new Map<string, string[]>()
32
+ for (const unit of input.units) {
33
+ for (const file of unit.files) {
34
+ const existing = fileToUnits.get(file) ?? []
35
+ existing.push(unit.name)
36
+ fileToUnits.set(file, existing)
37
+ }
38
+ }
39
+
40
+ // Union-Find: merge units that share files
41
+ const parent = new Map<string, string>()
42
+ const sharedFilesMap = new Map<string, Set<string>>()
43
+
44
+ function find(name: string): string {
45
+ if (!parent.has(name)) parent.set(name, name)
46
+ let root = name
47
+ while (parent.get(root) !== root) {
48
+ root = parent.get(root)!
49
+ }
50
+ // Path compression
51
+ let current = name
52
+ while (current !== root) {
53
+ const next = parent.get(current)!
54
+ parent.set(current, root)
55
+ current = next
56
+ }
57
+ return root
58
+ }
59
+
60
+ function union(a: string, b: string) {
61
+ const rootA = find(a)
62
+ const rootB = find(b)
63
+ if (rootA !== rootB) {
64
+ parent.set(rootA, rootB)
65
+ }
66
+ }
67
+
68
+ // Initialize all units
69
+ for (const unit of input.units) {
70
+ find(unit.name)
71
+ }
72
+
73
+ // Merge units sharing files
74
+ for (const [file, unitNames] of fileToUnits) {
75
+ if (unitNames.length > 1) {
76
+ for (let i = 1; i < unitNames.length; i++) {
77
+ union(unitNames[0], unitNames[i])
78
+ }
79
+ // Track shared files per root
80
+ const root = find(unitNames[0])
81
+ if (!sharedFilesMap.has(root)) sharedFilesMap.set(root, new Set())
82
+ sharedFilesMap.get(root)!.add(file)
83
+ }
84
+ }
85
+
86
+ // Build groups by root
87
+ const rootToUnits = new Map<string, string[]>()
88
+ for (const unit of input.units) {
89
+ const root = find(unit.name)
90
+ const group = rootToUnits.get(root) ?? []
91
+ group.push(unit.name)
92
+ rootToUnits.set(root, group)
93
+ }
94
+
95
+ // Build output
96
+ const groups: SplitterGroup[] = []
97
+ const independentUnits: string[] = []
98
+ const dependentUnits: string[] = []
99
+
100
+ for (const [root, unitNames] of rootToUnits) {
101
+ const hasShared = sharedFilesMap.has(root) && sharedFilesMap.get(root)!.size > 0
102
+ const parallelSafe = !hasShared
103
+
104
+ const group: SplitterGroup = {
105
+ units: unitNames,
106
+ parallelSafe,
107
+ }
108
+
109
+ if (!parallelSafe) {
110
+ group.sharedFiles = Array.from(sharedFilesMap.get(root)!)
111
+ dependentUnits.push(...unitNames)
112
+ } else {
113
+ independentUnits.push(...unitNames)
114
+ }
115
+
116
+ groups.push(group)
117
+ }
118
+
119
+ return { groups, independentUnits, dependentUnits }
120
+ },
121
+ }
122
+ }
@@ -0,0 +1,80 @@
1
+ import { readdirSync, statSync, existsSync } from "node:fs"
2
+ import path from "node:path"
3
+
4
+ export interface WorkflowCategoryState {
5
+ count: number
6
+ latest: string | null
7
+ }
8
+
9
+ export interface WorkflowStateInput {
10
+ repoRoot: string
11
+ }
12
+
13
+ export interface WorkflowStateResult {
14
+ brainstorms: WorkflowCategoryState
15
+ plans: WorkflowCategoryState
16
+ solutions: WorkflowCategoryState
17
+ runs: WorkflowCategoryState
18
+ }
19
+
20
+ function emptyCategory(): WorkflowCategoryState {
21
+ return { count: 0, latest: null }
22
+ }
23
+
24
+ function scanDir(dirPath: string): WorkflowCategoryState {
25
+ if (!existsSync(dirPath)) {
26
+ return emptyCategory()
27
+ }
28
+
29
+ const files = collectFiles(dirPath)
30
+
31
+ if (files.length === 0) {
32
+ return emptyCategory()
33
+ }
34
+
35
+ const sorted = files.sort()
36
+ const latest = sorted[sorted.length - 1]
37
+
38
+ return {
39
+ count: files.length,
40
+ latest: path.basename(latest),
41
+ }
42
+ }
43
+
44
+ function collectFiles(dirPath: string): string[] {
45
+ const results: string[] = []
46
+
47
+ try {
48
+ const entries = readdirSync(dirPath, { withFileTypes: true })
49
+
50
+ for (const entry of entries) {
51
+ const fullPath = path.join(dirPath, entry.name)
52
+
53
+ if (entry.isDirectory()) {
54
+ results.push(...collectFiles(fullPath))
55
+ } else if (entry.isFile()) {
56
+ results.push(fullPath)
57
+ }
58
+ }
59
+ } catch {
60
+ // Directory not readable, treat as empty
61
+ }
62
+
63
+ return results
64
+ }
65
+
66
+ export function createWorkflowStateTool() {
67
+ return {
68
+ name: "workflow_state",
69
+ async execute(input: WorkflowStateInput): Promise<WorkflowStateResult> {
70
+ const repoRoot = input.repoRoot
71
+
72
+ return {
73
+ brainstorms: scanDir(path.join(repoRoot, "docs", "brainstorms")),
74
+ plans: scanDir(path.join(repoRoot, "docs", "plans")),
75
+ solutions: scanDir(path.join(repoRoot, "docs", "solutions")),
76
+ runs: scanDir(path.join(repoRoot, ".context", "compound-engineering")),
77
+ }
78
+ },
79
+ }
80
+ }