@leing2021/super-pi 0.22.1 → 0.23.1

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 (117) hide show
  1. package/README.md +66 -293
  2. package/extensions/ce-core/index.ts +276 -48
  3. package/extensions/ce-core/tools/parallel-subagent.ts +3 -3
  4. package/extensions/ce-core/tools/subagent.ts +2 -2
  5. package/package.json +4 -20
  6. package/rules/common/naming.md +154 -0
  7. package/skills/01-brainstorm/SKILL.md +42 -79
  8. package/skills/01-brainstorm/references/ce-brainstorm-mode.md +47 -0
  9. package/skills/02-plan/SKILL.md +43 -61
  10. package/skills/02-plan/references/solution-search.md +46 -0
  11. package/skills/03-work/SKILL.md +34 -52
  12. package/skills/03-work/references/completion-report.md +51 -0
  13. package/skills/04-review/SKILL.md +44 -51
  14. package/skills/04-review/references/solution-search.md +46 -0
  15. package/skills/06-next/SKILL.md +35 -20
  16. package/skills/06-next/references/recommendation-logic.md +47 -2
  17. package/skills/07-worktree/SKILL.md +21 -20
  18. package/skills/08-help/SKILL.md +46 -0
  19. package/skills/08-help/references/workflow-sequence.md +135 -0
  20. package/skills/references/language-detection.md +44 -0
  21. package/LICENSE +0 -21
  22. package/THIRD-PARTY-NOTICES.md +0 -35
  23. package/extensions/subagent/__tests__/async-job-tracker.test.ts +0 -21
  24. package/extensions/subagent/__tests__/execution-activity.test.ts +0 -15
  25. package/extensions/subagent/__tests__/parallel-render-stress.test.ts +0 -82
  26. package/extensions/subagent/__tests__/render-dedup.test.ts +0 -98
  27. package/extensions/subagent/__tests__/render-widget.test.ts +0 -28
  28. package/extensions/subagent/__tests__/throttle.test.ts +0 -90
  29. package/extensions/subagent/agent-management.ts +0 -596
  30. package/extensions/subagent/agent-manager-chain-detail.ts +0 -163
  31. package/extensions/subagent/agent-manager-detail.ts +0 -232
  32. package/extensions/subagent/agent-manager-edit.ts +0 -391
  33. package/extensions/subagent/agent-manager-list.ts +0 -279
  34. package/extensions/subagent/agent-manager-parallel.ts +0 -305
  35. package/extensions/subagent/agent-manager.ts +0 -706
  36. package/extensions/subagent/agent-scope.ts +0 -9
  37. package/extensions/subagent/agent-selection.ts +0 -26
  38. package/extensions/subagent/agent-serializer.ts +0 -124
  39. package/extensions/subagent/agent-templates.ts +0 -63
  40. package/extensions/subagent/agents/context-builder.md +0 -37
  41. package/extensions/subagent/agents/delegate.md +0 -9
  42. package/extensions/subagent/agents/oracle.md +0 -73
  43. package/extensions/subagent/agents/planner.md +0 -52
  44. package/extensions/subagent/agents/researcher.md +0 -50
  45. package/extensions/subagent/agents/reviewer.md +0 -38
  46. package/extensions/subagent/agents/scout.md +0 -48
  47. package/extensions/subagent/agents/worker.md +0 -52
  48. package/extensions/subagent/agents.ts +0 -762
  49. package/extensions/subagent/artifacts.ts +0 -101
  50. package/extensions/subagent/async-execution.ts +0 -521
  51. package/extensions/subagent/async-job-tracker.ts +0 -240
  52. package/extensions/subagent/async-status.ts +0 -242
  53. package/extensions/subagent/chain-clarify.ts +0 -1365
  54. package/extensions/subagent/chain-execution.ts +0 -854
  55. package/extensions/subagent/chain-serializer.ts +0 -127
  56. package/extensions/subagent/completion-dedupe.ts +0 -66
  57. package/extensions/subagent/doctor.ts +0 -201
  58. package/extensions/subagent/execution.ts +0 -748
  59. package/extensions/subagent/file-coalescer.ts +0 -43
  60. package/extensions/subagent/fork-context.ts +0 -64
  61. package/extensions/subagent/formatters.ts +0 -123
  62. package/extensions/subagent/frontmatter.ts +0 -32
  63. package/extensions/subagent/index.ts +0 -586
  64. package/extensions/subagent/intercom-bridge.ts +0 -241
  65. package/extensions/subagent/jsonl-writer.ts +0 -84
  66. package/extensions/subagent/model-fallback.ts +0 -109
  67. package/extensions/subagent/notify.ts +0 -111
  68. package/extensions/subagent/parallel-utils.ts +0 -109
  69. package/extensions/subagent/pi-args.ts +0 -139
  70. package/extensions/subagent/pi-spawn.ts +0 -101
  71. package/extensions/subagent/post-exit-stdio-guard.ts +0 -88
  72. package/extensions/subagent/prompt-template-bridge.ts +0 -400
  73. package/extensions/subagent/prompts/gather-context-and-clarify.md +0 -13
  74. package/extensions/subagent/prompts/parallel-cleanup.md +0 -42
  75. package/extensions/subagent/prompts/parallel-research.md +0 -50
  76. package/extensions/subagent/prompts/parallel-review.md +0 -40
  77. package/extensions/subagent/render-helpers.ts +0 -83
  78. package/extensions/subagent/render.ts +0 -908
  79. package/extensions/subagent/result-intercom.ts +0 -238
  80. package/extensions/subagent/result-watcher.ts +0 -172
  81. package/extensions/subagent/run-history.ts +0 -58
  82. package/extensions/subagent/run-status.ts +0 -137
  83. package/extensions/subagent/schemas.ts +0 -165
  84. package/extensions/subagent/session-tokens.ts +0 -51
  85. package/extensions/subagent/settings.ts +0 -368
  86. package/extensions/subagent/single-output.ts +0 -98
  87. package/extensions/subagent/skills.ts +0 -627
  88. package/extensions/subagent/slash-bridge.ts +0 -177
  89. package/extensions/subagent/slash-commands.ts +0 -304
  90. package/extensions/subagent/slash-live-state.ts +0 -295
  91. package/extensions/subagent/subagent-control.ts +0 -151
  92. package/extensions/subagent/subagent-executor.ts +0 -1915
  93. package/extensions/subagent/subagent-prompt-runtime.ts +0 -76
  94. package/extensions/subagent/subagent-runner.ts +0 -1471
  95. package/extensions/subagent/subagents-status.ts +0 -473
  96. package/extensions/subagent/text-editor.ts +0 -273
  97. package/extensions/subagent/throttle.ts +0 -77
  98. package/extensions/subagent/top-level-async.ts +0 -16
  99. package/extensions/subagent/types.ts +0 -624
  100. package/extensions/subagent/utils.ts +0 -457
  101. package/extensions/subagent/worktree.ts +0 -580
  102. package/extensions/super-pi-extension/agents/ce-oracle.md +0 -109
  103. package/extensions/super-pi-extension/agents/ce-planner.md +0 -116
  104. package/extensions/super-pi-extension/agents/ce-reviewer.md +0 -99
  105. package/extensions/super-pi-extension/agents/ce-scout.md +0 -80
  106. package/extensions/super-pi-extension/agents/ce-worker.md +0 -78
  107. package/extensions/super-pi-extension/chains/ce-parallel-review.chain.md +0 -34
  108. package/extensions/super-pi-extension/chains/ce-review-only.chain.md +0 -12
  109. package/extensions/super-pi-extension/chains/ce-standard.chain.md +0 -28
  110. package/extensions/super-pi-extension/index.ts +0 -129
  111. package/extensions/super-pi-extension/model-sync.ts +0 -204
  112. package/skills/08-status/SKILL.md +0 -41
  113. package/skills/08-status/references/artifact-locations.md +0 -10
  114. package/skills/09-help/SKILL.md +0 -37
  115. package/skills/09-help/references/workflow-sequence.md +0 -9
  116. package/skills/10-rules/SKILL.md +0 -76
  117. package/skills/pi-subagents/SKILL.md +0 -566
@@ -4,23 +4,25 @@ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"
4
4
  import { Type } from "typebox"
5
5
  import { createArtifactHelperTool, type ArtifactType } from "./tools/artifact-helper"
6
6
  import { createAskUserQuestionTool } from "./tools/ask-user-question"
7
+ import { createSubagentTool } from "./tools/subagent"
7
8
  import { createWorkflowStateTool } from "./tools/workflow-state"
8
9
  import { createWorktreeManagerTool } from "./tools/worktree-manager"
9
10
  import { createReviewRouterTool } from "./tools/review-router"
11
+ import { createParallelSubagentTool } from "./tools/parallel-subagent"
10
12
  import { createSessionCheckpointTool } from "./tools/session-checkpoint"
11
13
  import { createTaskSplitterTool } from "./tools/task-splitter"
12
14
  import { createBrainstormDialogTool } from "./tools/brainstorm-dialog"
13
15
  import { createPlanDiffTool } from "./tools/plan-diff"
14
16
  import { createSessionHistoryTool } from "./tools/session-history"
15
17
  import { createPatternExtractorTool } from "./tools/pattern-extractor"
18
+ import { createContextHandoffTool } from "./tools/context-handoff"
16
19
  import { filterBashOutput } from "./tools/bash-output-filter"
17
20
  import { filterReadOutput } from "./tools/read-output-filter"
18
21
  import { COMPACTION_FOCUS_INSTRUCTIONS } from "./tools/compaction-optimizer"
22
+ import { AsyncMutex } from "./tools/async-mutex"
23
+ import type { SubagentExecOptions, SubagentRunner } from "./tools/subagent"
19
24
 
20
- // NOTE: subagent and parallel_subagent tool registration removed.
21
- // Subagent capabilities are provided by the pi-subagents package.
22
- // super-pi focuses on CE-specific tools only.
23
-
25
+ const _subagentEnvMutex = new AsyncMutex()
24
26
  const PIPELINE_STAGE_KEYS = new Set([
25
27
  "01-brainstorm",
26
28
  "02-plan",
@@ -29,15 +31,46 @@ const PIPELINE_STAGE_KEYS = new Set([
29
31
  "05-learn",
30
32
  ])
31
33
 
32
- interface ModelStrategySettings {
34
+ interface StrategySettings {
33
35
  modelStrategy?: Record<string, string>
36
+ thinkingStrategy?: Record<string, string>
34
37
  }
35
38
 
36
- async function readProjectSettings(cwd: string): Promise<ModelStrategySettings | null> {
37
- const settingsPath = path.join(cwd, ".pi", "settings.json")
39
+ /**
40
+ * Read settings from two locations:
41
+ * 1. Project-level: {cwd}/.pi/settings.json (highest priority)
42
+ * 2. Global-level: ~/.pi/agent/settings.json (fallback)
43
+ *
44
+ * Project-level takes precedence; global-level is used as fallback.
45
+ */
46
+ async function readSettings(cwd: string): Promise<StrategySettings | null> {
47
+ // Try project-level first
48
+ const projectPath = path.join(cwd, ".pi", "settings.json")
38
49
  try {
39
- const content = await readFile(settingsPath, "utf8")
40
- return JSON.parse(content) as ModelStrategySettings
50
+ const content = await readFile(projectPath, "utf8")
51
+ const projectSettings = JSON.parse(content) as StrategySettings
52
+ // If project has modelStrategy or thinkingStrategy, use it
53
+ if (projectSettings.modelStrategy || projectSettings.thinkingStrategy) {
54
+ return projectSettings
55
+ }
56
+ } catch {
57
+ // Project settings not found, continue to global
58
+ }
59
+
60
+ // Fallback to global-level
61
+ const globalPath = path.join(process.env.HOME || "~", ".pi", "agent", "settings.json")
62
+ try {
63
+ const content = await readFile(globalPath, "utf8")
64
+ return JSON.parse(content) as StrategySettings
65
+ } catch {
66
+ // Global settings not found either
67
+ }
68
+
69
+ // Try ~/.pi/settings.json as another fallback
70
+ const altGlobalPath = path.join(process.env.HOME || "~", ".pi", "settings.json")
71
+ try {
72
+ const content = await readFile(altGlobalPath, "utf8")
73
+ return JSON.parse(content) as StrategySettings
41
74
  } catch {
42
75
  return null
43
76
  }
@@ -81,6 +114,47 @@ function parseModelRef(
81
114
  }
82
115
  }
83
116
 
117
+ /**
118
+ * Create a subagent runner that handles env injection with mutex protection
119
+ * for concurrency safety when multiple parallel subagents share the process.
120
+ */
121
+ function createSubagentRunner(
122
+ pi: ExtensionAPI,
123
+ signal?: AbortSignal,
124
+ ): SubagentRunner {
125
+ return async (prompt: string, options?: SubagentExecOptions) => {
126
+ const args = ["--no-session", ...(options?.extraFlags ?? []), "-p", prompt]
127
+ const release = await _subagentEnvMutex.acquire()
128
+ const savedEnv: Record<string, string | undefined> = {}
129
+ const extraEnv = options?.extraEnv ?? {}
130
+ for (const [key, value] of Object.entries(extraEnv)) {
131
+ savedEnv[key] = process.env[key]
132
+ process.env[key] = value
133
+ }
134
+ try {
135
+ const execResult = await pi.exec("pi", args, {
136
+ signal,
137
+ timeout: 10 * 60 * 1000,
138
+ })
139
+
140
+ if (execResult.code !== 0) {
141
+ throw new Error(execResult.stderr || execResult.stdout || `Subagent failed for prompt: ${prompt}`)
142
+ }
143
+
144
+ return (execResult.stdout || "").trim()
145
+ } finally {
146
+ for (const [key, oldValue] of Object.entries(savedEnv)) {
147
+ if (oldValue === undefined) {
148
+ delete process.env[key]
149
+ } else {
150
+ process.env[key] = oldValue
151
+ }
152
+ }
153
+ release()
154
+ }
155
+ }
156
+ }
157
+
84
158
  const artifactHelperParams = Type.Object({
85
159
  repoRoot: Type.String({ description: "Repository root where workflow artifacts should be created" }),
86
160
  artifactType: Type.Union([
@@ -103,6 +177,18 @@ const askUserQuestionParams = Type.Object({
103
177
  allowCustom: Type.Optional(Type.Boolean({ description: "Allow a custom answer when options are present" })),
104
178
  })
105
179
 
180
+ const subagentTaskSchema = Type.Object({
181
+ agent: Type.String({ description: "Skill name to invoke via /skill:<name>" }),
182
+ task: Type.String({ description: "Task text passed to the subagent" }),
183
+ })
184
+
185
+ const subagentParams = Type.Object({
186
+ agent: Type.Optional(Type.String({ description: "Single subagent skill name" })),
187
+ task: Type.Optional(Type.String({ description: "Single subagent task" })),
188
+ chain: Type.Optional(Type.Array(subagentTaskSchema, { description: "Serial subagent chain with optional {previous} placeholder" })),
189
+ inheritSkills: Type.Optional(Type.Boolean({ description: "Whether the subagent should inherit skills. Default: true" })),
190
+ })
191
+
106
192
  const workflowStateParams = Type.Object({
107
193
  repoRoot: Type.String({ description: "Repository root to scan for workflow artifacts" }),
108
194
  })
@@ -125,6 +211,19 @@ const reviewRouterParams = Type.Object({
125
211
  deletions: Type.Number({ description: "Number of lines removed" }),
126
212
  })
127
213
 
214
+ const parallelSubagentTaskSchema = Type.Object({
215
+ agent: Type.String({ description: "Skill name to invoke via /skill:<name>" }),
216
+ task: Type.String({ description: "Task text passed to the subagent" }),
217
+ })
218
+
219
+ const parallelSubagentParams = Type.Object({
220
+ tasks: Type.Union([
221
+ Type.Array(parallelSubagentTaskSchema),
222
+ Type.String({ description: "JSON stringified array of tasks" }),
223
+ ], { description: "Array of independent tasks to run concurrently (can be a JSON string)" }),
224
+ inheritSkills: Type.Optional(Type.Boolean({ description: "Whether subagents should inherit skills. Default: false" })),
225
+ })
226
+
128
227
  const sessionCheckpointParams = Type.Object({
129
228
  operation: Type.Union([
130
229
  Type.Literal("save"),
@@ -205,6 +304,30 @@ const patternSchema = Type.Object({
205
304
  sources: Type.Array(Type.String(), { description: "Artifact sources" }),
206
305
  })
207
306
 
307
+ const contextHandoffParams = Type.Object({
308
+ operation: Type.Union([
309
+ Type.Literal("save"),
310
+ Type.Literal("load"),
311
+ Type.Literal("latest"),
312
+ Type.Literal("status"),
313
+ ], { description: "Handoff operation" }),
314
+ repoRoot: Type.String({ description: "Repository root" }),
315
+ currentStage: Type.Optional(Type.String({ description: "Current pipeline stage (e.g. 02-plan)" })),
316
+ nextStage: Type.Optional(Type.String({ description: "Next pipeline stage" })),
317
+ contextHealth: Type.Optional(Type.Union([
318
+ Type.Literal("good"),
319
+ Type.Literal("watch"),
320
+ Type.Literal("heavy"),
321
+ Type.Literal("critical"),
322
+ ], { description: "Context health assessment" })),
323
+ activeFiles: Type.Optional(Type.Array(Type.String(), { description: "1-5 must-know active file paths" })),
324
+ blocker: Type.Optional(Type.String({ description: "Current blocker description" })),
325
+ verification: Type.Optional(Type.String({ description: "Latest verification command + result" })),
326
+ artifacts: Type.Optional(Type.Record(Type.String(), Type.Optional(Type.String()), { description: "Artifact paths (requirements, plan, checkpoint, proof)" })),
327
+ handoffMarkdown: Type.Optional(Type.String({ description: "Custom handoff markdown content" })),
328
+ handoffPath: Type.Optional(Type.String({ description: "Specific handoff file path to load" })),
329
+ })
330
+
208
331
  const patternExtractorParams = Type.Object({
209
332
  operation: Type.Union([
210
333
  Type.Literal("extract"),
@@ -227,47 +350,61 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
227
350
  return { action: "continue" as const }
228
351
  }
229
352
 
230
- const settings = await readProjectSettings(ctx.cwd)
353
+ const settings = await readSettings(ctx.cwd)
231
354
  const modelStrategy = settings?.modelStrategy
232
- if (!modelStrategy) {
233
- return { action: "continue" as const }
234
- }
235
-
236
- const targetModelRef = modelStrategy[stageKey] ?? modelStrategy.default
237
- if (!targetModelRef) {
238
- return { action: "continue" as const }
239
- }
240
-
241
- const parsed = parseModelRef(targetModelRef, ctx.model?.provider)
242
- if (!parsed) {
243
- if (ctx.hasUI) {
244
- ctx.ui.notify(`Invalid modelStrategy entry for ${stageKey}: ${targetModelRef}`, "warning")
245
- }
246
- return { action: "continue" as const }
247
- }
248
-
249
- if (ctx.model?.provider === parsed.provider && ctx.model?.id === parsed.id) {
250
- return { action: "continue" as const }
251
- }
252
-
253
- const model = ctx.modelRegistry.find(parsed.provider, parsed.id)
254
- if (!model) {
255
- if (ctx.hasUI) {
256
- ctx.ui.notify(`Configured model not found for ${stageKey}: ${targetModelRef}`, "warning")
355
+ const thinkingStrategy = settings?.thinkingStrategy
356
+
357
+ // Model switching
358
+ if (modelStrategy) {
359
+ const targetModelRef = modelStrategy[stageKey] ?? modelStrategy.default
360
+ if (targetModelRef) {
361
+ const parsed = parseModelRef(targetModelRef, ctx.model?.provider)
362
+ if (parsed) {
363
+ // Skip if already using the same model
364
+ if (ctx.model?.provider !== parsed.provider || ctx.model?.id !== parsed.id) {
365
+ const model = ctx.modelRegistry.find(parsed.provider, parsed.id)
366
+ if (model) {
367
+ const switched = await pi.setModel(model)
368
+ if (switched) {
369
+ if (ctx.hasUI) {
370
+ ctx.ui.notify(`Switched model for ${stageKey}: ${model.provider}/${model.id}`, "info")
371
+ }
372
+ } else {
373
+ if (ctx.hasUI) {
374
+ ctx.ui.notify(`No API key for ${stageKey}: ${model.provider}/${model.id}`, "warning")
375
+ }
376
+ }
377
+ } else if (ctx.hasUI) {
378
+ ctx.ui.notify(`Model not found for ${stageKey}: ${targetModelRef}`, "warning")
379
+ }
380
+ }
381
+ } else if (ctx.hasUI) {
382
+ ctx.ui.notify(`Invalid modelStrategy for ${stageKey}: ${targetModelRef}`, "warning")
383
+ }
257
384
  }
258
- return { action: "continue" as const }
259
385
  }
260
386
 
261
- const switched = await pi.setModel(model)
262
- if (switched) {
263
- if (ctx.hasUI) {
264
- ctx.ui.notify(`Switched model for ${stageKey}: ${model.provider}/${model.id}`, "info")
387
+ // Thinking level switching
388
+ if (thinkingStrategy) {
389
+ const targetThinking = thinkingStrategy[stageKey] ?? thinkingStrategy.default
390
+ if (targetThinking) {
391
+ const levelMap: Record<string, "low" | "medium" | "high"> = {
392
+ low: "low",
393
+ medium: "medium",
394
+ high: "high",
395
+ "0": "low",
396
+ "1": "medium",
397
+ "2": "high",
398
+ }
399
+ const normalized = levelMap[targetThinking.toLowerCase()] ?? "medium"
400
+ const currentLevel = ctx.getThinkingLevel?.() ?? "medium"
401
+ if (currentLevel !== normalized) {
402
+ ctx.setThinkingLevel?.(normalized)
403
+ if (ctx.hasUI) {
404
+ ctx.ui.notify(`Switched thinking level for ${stageKey}: ${normalized}`, "info")
405
+ }
406
+ }
265
407
  }
266
- return { action: "continue" as const }
267
- }
268
-
269
- if (ctx.hasUI) {
270
- ctx.ui.notify(`No API key available for configured model: ${model.provider}/${model.id}`, "warning")
271
408
  }
272
409
 
273
410
  return { action: "continue" as const }
@@ -275,15 +412,18 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
275
412
 
276
413
  const artifactHelper = createArtifactHelperTool()
277
414
  const askUserQuestion = createAskUserQuestionTool()
415
+ const subagent = createSubagentTool()
278
416
  const workflowState = createWorkflowStateTool()
279
417
  const worktreeManager = createWorktreeManagerTool()
280
418
  const reviewRouter = createReviewRouterTool()
419
+ const parallelSubagent = createParallelSubagentTool()
281
420
  const sessionCheckpoint = createSessionCheckpointTool()
282
421
  const taskSplitter = createTaskSplitterTool()
283
422
  const brainstormDialog = createBrainstormDialogTool()
284
423
  const planDiff = createPlanDiffTool()
285
424
  const sessionHistory = createSessionHistoryTool()
286
425
  const patternExtractor = createPatternExtractorTool()
426
+ const contextHandoff = createContextHandoffTool()
287
427
 
288
428
  pi.registerTool({
289
429
  name: artifactHelper.name,
@@ -350,6 +490,29 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
350
490
  },
351
491
  })
352
492
 
493
+ pi.registerTool({
494
+ name: subagent.name,
495
+ label: "CE Subagent",
496
+ description: "Run a single CE skill-based subagent or a serial chain in an isolated Pi process.",
497
+ parameters: subagentParams,
498
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
499
+ const result = await subagent.execute(
500
+ {
501
+ agent: params.agent,
502
+ task: params.task,
503
+ chain: params.chain,
504
+ inheritSkills: params.inheritSkills,
505
+ },
506
+ createSubagentRunner(pi, signal),
507
+ )
508
+
509
+ return {
510
+ content: [{ type: "text", text: result.outputs[result.outputs.length - 1] ?? "" }],
511
+ details: result,
512
+ }
513
+ },
514
+ })
515
+
353
516
  pi.registerTool({
354
517
  name: workflowState.name,
355
518
  label: "Workflow State",
@@ -421,6 +584,39 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
421
584
  },
422
585
  })
423
586
 
587
+ pi.registerTool({
588
+ name: parallelSubagent.name,
589
+ label: "CE Parallel Subagent",
590
+ description: "Run multiple CE skill-based subagent tasks concurrently. IMPORTANT: Provide 'tasks' as a clean JSON array object. If the environment forces a string, provide a valid JSON array string.",
591
+ parameters: parallelSubagentParams,
592
+ async execute(_toolCallId, params, signal) {
593
+ let tasks: any[]
594
+ if (typeof params.tasks === "string") {
595
+ try {
596
+ const cleaned = params.tasks.replace(/^```json\s*|```$/g, "").trim()
597
+ tasks = JSON.parse(cleaned)
598
+ } catch (e) {
599
+ throw new Error(`Failed to parse tasks string as JSON: ${e instanceof Error ? e.message : String(e)}`)
600
+ }
601
+ } else {
602
+ tasks = params.tasks
603
+ }
604
+
605
+ const result = await parallelSubagent.execute(
606
+ {
607
+ tasks,
608
+ inheritSkills: params.inheritSkills,
609
+ },
610
+ createSubagentRunner(pi, signal),
611
+ )
612
+
613
+ return {
614
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
615
+ details: result,
616
+ }
617
+ },
618
+ })
619
+
424
620
  pi.registerTool({
425
621
  name: sessionCheckpoint.name,
426
622
  label: "Session Checkpoint",
@@ -544,6 +740,33 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
544
740
  },
545
741
  })
546
742
 
743
+ pi.registerTool({
744
+ name: contextHandoff.name,
745
+ label: "Context Handoff",
746
+ description: "Manage cross-stage context handoffs with evidence-first templates. Supports save (write handoff + state), load (read handoff + state), latest (read latest dated handoff), and status (read current state).",
747
+ parameters: contextHandoffParams,
748
+ async execute(_toolCallId, params) {
749
+ const result = await contextHandoff.execute({
750
+ operation: params.operation,
751
+ repoRoot: params.repoRoot,
752
+ currentStage: params.currentStage,
753
+ nextStage: params.nextStage,
754
+ contextHealth: params.contextHealth,
755
+ activeFiles: params.activeFiles,
756
+ blocker: params.blocker,
757
+ verification: params.verification,
758
+ artifacts: params.artifacts as Record<string, string | undefined> | undefined,
759
+ handoffMarkdown: params.handoffMarkdown,
760
+ handoffPath: params.handoffPath,
761
+ })
762
+
763
+ return {
764
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
765
+ details: result,
766
+ }
767
+ },
768
+ })
769
+
547
770
  // Bash output smart filter — reduces context waste from verbose command output
548
771
  pi.on("tool_result", async (event, _ctx) => {
549
772
  if (event.toolName !== "bash") return undefined
@@ -587,8 +810,8 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
587
810
  if (event.toolName !== "read") return undefined
588
811
 
589
812
  // Extract path from input
590
- const filePath = (event.input as any)?.path ?? ""
591
- if (!filePath) return undefined
813
+ const path = (event.input as any)?.path ?? ""
814
+ if (!path) return undefined
592
815
 
593
816
  // Extract text content from tool result
594
817
  const textBlocks = (event.content as Array<any>)?.filter((b: any) => b.type === "text") ?? []
@@ -598,7 +821,7 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
598
821
  const isImage = (event.content as Array<any>)?.some((b: any) => b.type === "image") ?? false
599
822
 
600
823
  const result = filterReadOutput({
601
- path: filePath,
824
+ path,
602
825
  output,
603
826
  isError: event.isError ?? false,
604
827
  isImage,
@@ -631,15 +854,20 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
631
854
 
632
855
  export { createArtifactHelperTool } from "./tools/artifact-helper"
633
856
  export { createAskUserQuestionTool } from "./tools/ask-user-question"
857
+ export { createSubagentTool } from "./tools/subagent"
858
+ export { checkSubagentDepth, getChildDepthEnv, DEFAULT_MAX_SUBAGENT_DEPTH } from "./tools/subagent-depth-guard"
859
+ export { AsyncMutex } from "./tools/async-mutex"
634
860
  export { createWorkflowStateTool } from "./tools/workflow-state"
635
861
  export { createWorktreeManagerTool } from "./tools/worktree-manager"
636
862
  export { createReviewRouterTool } from "./tools/review-router"
863
+ export { createParallelSubagentTool } from "./tools/parallel-subagent"
637
864
  export { createSessionCheckpointTool } from "./tools/session-checkpoint"
638
865
  export { createTaskSplitterTool } from "./tools/task-splitter"
639
866
  export { createBrainstormDialogTool } from "./tools/brainstorm-dialog"
640
867
  export { createPlanDiffTool } from "./tools/plan-diff"
641
868
  export { createSessionHistoryTool } from "./tools/session-history"
642
869
  export { createPatternExtractorTool } from "./tools/pattern-extractor"
870
+ export { createContextHandoffTool } from "./tools/context-handoff"
643
871
  export {
644
872
  getBrainstormArtifactPath,
645
873
  getPlanArtifactPath,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Parallel subagent tool — runs multiple skill-based subagent tasks concurrently.
2
+ * CE parallel subagent tool — runs multiple CE skill-based subagent tasks concurrently.
3
3
  *
4
4
  * Features:
5
5
  * - Recursion depth guard (PI_SUBAGENT_DEPTH / PI_SUBAGENT_MAX_DEPTH)
@@ -40,7 +40,7 @@ function buildPrompt(agent: string, task: string): string {
40
40
 
41
41
  export function createParallelSubagentTool() {
42
42
  return {
43
- name: "parallel_subagent",
43
+ name: "ce_parallel_subagent",
44
44
  async execute(input: ParallelSubagentInput, runner: SubagentRunner): Promise<ParallelSubagentResult> {
45
45
  // Recursion depth guard
46
46
  const depthCheck = checkSubagentDepth()
@@ -49,7 +49,7 @@ export function createParallelSubagentTool() {
49
49
  }
50
50
 
51
51
  if (!input.tasks || input.tasks.length === 0) {
52
- throw new Error("parallel_subagent requires at least one task")
52
+ throw new Error("ce_parallel_subagent requires at least one task")
53
53
  }
54
54
 
55
55
  // Default: parallel workers get a slim context (no inherited skills)
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Subagent tool — runs a single skill-based subagent or a serial chain.
2
+ * CE subagent tool — runs a single CE skill-based subagent or a serial chain.
3
3
  *
4
4
  * Features:
5
5
  * - Recursion depth guard (PI_SUBAGENT_DEPTH / PI_SUBAGENT_MAX_DEPTH)
@@ -43,7 +43,7 @@ export type SubagentRunner = (
43
43
 
44
44
  export function createSubagentTool() {
45
45
  return {
46
- name: "subagent",
46
+ name: "ce_subagent",
47
47
  async execute(input: SubagentInput, runner: SubagentRunner): Promise<SubagentResult> {
48
48
  // Recursion depth guard
49
49
  const depthCheck = checkSubagentDepth()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leing2021/super-pi",
3
- "version": "0.22.1",
3
+ "version": "0.23.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Pi-native Compound Engineering package for iterative development workflows",
@@ -25,8 +25,6 @@
25
25
  "skills",
26
26
  "extensions",
27
27
  "rules",
28
- "THIRD-PARTY-NOTICES.md",
29
- "LICENSE",
30
28
  "README.md",
31
29
  "package.json"
32
30
  ],
@@ -37,10 +35,8 @@
37
35
  "test": "bun test"
38
36
  },
39
37
  "peerDependencies": {
40
- "@mariozechner/pi-coding-agent": "*"
41
- },
42
- "dependencies": {
43
- "typebox": "^1.1.24"
38
+ "@mariozechner/pi-coding-agent": ">=0.69.0",
39
+ "typebox": ">=1.0.0"
44
40
  },
45
41
  "devDependencies": {
46
42
  "@mariozechner/pi-coding-agent": "0.69.0",
@@ -51,19 +47,7 @@
51
47
  "./skills"
52
48
  ],
53
49
  "extensions": [
54
- "./extensions",
55
- "./extensions/super-pi-extension",
56
- "./extensions/subagent"
57
- ],
58
- "agents": [
59
- "./extensions/super-pi-extension/agents",
60
- "./extensions/subagent/agents"
61
- ],
62
- "prompts": [
63
- "./extensions/subagent/prompts"
64
- ],
65
- "chains": [
66
- "./extensions/super-pi-extension/chains"
50
+ "./extensions"
67
51
  ]
68
52
  }
69
53
  }