@leing2021/super-pi 0.19.2 → 0.19.3

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/README.md CHANGED
@@ -35,7 +35,7 @@ Super Pi's answers:
35
35
 
36
36
  Each step has a dedicated skill + tool pair. Not just prompts — structured toolchains.
37
37
 
38
- ### New: Stage model routing + optional auto-continue
38
+ ### New: Stage model routing
39
39
 
40
40
  Configure once in `.pi/settings.json`:
41
41
 
@@ -48,24 +48,22 @@ Configure once in `.pi/settings.json`:
48
48
  "04-review": "claude-sonnet-4-20250514",
49
49
  "05-learn": "claude-haiku-4-20250414",
50
50
  "default": "claude-sonnet-4-20250514"
51
- },
52
- "pipeline": {
53
- "autoContinue": false
54
51
  }
55
52
  }
56
53
  ```
57
54
 
58
55
  How it works:
59
- - Each stage picks `modelStrategy[stage]`, or `modelStrategy.default` as fallback.
56
+ - Model switching is handled automatically by the ce-core extension `input` hook — no manual `/model` needed.
57
+ - When you type `/skill:01-brainstorm` through `/skill:05-learn`, the extension reads `modelStrategy[stage]` (or `modelStrategy.default`) and switches before the skill runs.
58
+ - Supported formats: full reference (`"anthropic/claude-opus-4-1"`) or bare model id (`"claude-opus-4-1"`, reuses current provider).
60
59
  - Every stage prints a `📊 Pipeline Status` block with `Current / Output / Next`.
61
- - If `pipeline.autoContinue=true`, super-pi can trigger the next stage automatically.
62
- - Auto-continue is gate-aware: it will NOT skip required approvals (brainstorm approval, plan/review A/B/C choices).
60
+ - A `Switched model for <stage>: <provider>/<model>` notification appears when the model changes.
63
61
 
64
62
  Quick example:
65
- 1. Run `/skill:01-brainstorm`
63
+ 1. Run `/skill:01-brainstorm` — model auto-switches to the configured brainstorm model
66
64
  2. Approve the design
67
- 3. If `autoContinue=true`, it moves to `/skill:02-plan` automatically
68
- 4. If `autoContinue=false`, it stops after status output and waits for your command
65
+ 3. Run `/skill:02-plan` — model auto-switches to the configured plan model
66
+ 4. Continue through each stage model switches automatically at each step
69
67
 
70
68
  ---
71
69
 
@@ -383,6 +381,13 @@ Not a fork. Not a wrapper. Methodologies extracted and rebuilt with Pi's native
383
381
 
384
382
  ## Changelog
385
383
 
384
+ ### 0.19.3 — Terminate fix + runtime model routing + autoContinue removal
385
+ - Fixed 6 ce-core tools (`brainstorm_dialog`, `workflow_state`, `review_router`, `session_checkpoint`, `session_history`, `pattern_extractor`) incorrectly returning `terminate: true`, which caused agent turns to end prematurely (brainstorm questions not shown, "type continue to proceed" interruptions).
386
+ - Implemented runtime stage model routing via ce-core extension `input` hook: reads `.pi/settings.json` `modelStrategy`, auto-switches model before skill execution. Supports full reference (`anthropic/claude-opus-4-1`) and bare model id (`claude-opus-4-1`).
387
+ - Removed `pipeline.autoContinue` configuration (never had runtime implementation; Pi lacks `skill_end` event for auto-continue).
388
+ - Updated `skills/references/pipeline-config.md`, `README.md`, `README_CN.md` to reflect runtime model routing behavior.
389
+ - Added 4 new tests covering terminate regression, input hook model routing, and bare model id parsing.
390
+
386
391
  ### 0.19.2 — Evidence-first handoff-lite + docs tracking rule
387
392
  - Added `context_handoff` with evidence-first default handoff-lite generation when markdown is omitted.
388
393
  - Standardized the shared handoff-lite template across 01-05 workflow handoffs via `skills/references/pipeline-config.md`.
@@ -391,8 +396,7 @@ Not a fork. Not a wrapper. Methodologies extracted and rebuilt with Pi's native
391
396
 
392
397
  ### 0.19.1 — Pipeline config + typecheck baseline fix
393
398
  - Added shared pipeline config (`skills/references/pipeline-config.md`) for stage model routing via `.pi/settings.json`.
394
- - Added gated auto-continue rules (`pipeline.autoContinue`) so automation does not skip required approval/review-choice steps.
395
- - Added explicit README usage examples for `modelStrategy` and `pipeline.autoContinue`.
399
+ - Added runtime stage model routing via ce-core extension `input` hook (reads `modelStrategy` from `.pi/settings.json`, auto-switches model before skill execution).
396
400
  - Fixed TypeScript baseline issues so `bunx tsc --noEmit` passes.
397
401
 
398
402
  ### 0.19.0 — 0.69.0 alignment + learn rename
@@ -1,3 +1,5 @@
1
+ import { readFile } from "node:fs/promises"
2
+ import path from "node:path"
1
3
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"
2
4
  import { Type } from "typebox"
3
5
  import { createArtifactHelperTool, type ArtifactType } from "./tools/artifact-helper"
@@ -20,6 +22,65 @@ import { AsyncMutex } from "./tools/async-mutex"
20
22
  import type { SubagentExecOptions, SubagentRunner } from "./tools/subagent"
21
23
 
22
24
  const _subagentEnvMutex = new AsyncMutex()
25
+ const PIPELINE_STAGE_KEYS = new Set([
26
+ "01-brainstorm",
27
+ "02-plan",
28
+ "03-work",
29
+ "04-review",
30
+ "05-learn",
31
+ ])
32
+
33
+ interface ModelStrategySettings {
34
+ modelStrategy?: Record<string, string>
35
+ }
36
+
37
+ async function readProjectSettings(cwd: string): Promise<ModelStrategySettings | null> {
38
+ const settingsPath = path.join(cwd, ".pi", "settings.json")
39
+ try {
40
+ const content = await readFile(settingsPath, "utf8")
41
+ return JSON.parse(content) as ModelStrategySettings
42
+ } catch {
43
+ return null
44
+ }
45
+ }
46
+
47
+ function parseStageSkillName(text: string): string | null {
48
+ const trimmed = text.trim()
49
+ const match = trimmed.match(/^\/skill:([^\s]+)/)
50
+ if (!match) {
51
+ return null
52
+ }
53
+
54
+ const skillName = match[1]
55
+ return PIPELINE_STAGE_KEYS.has(skillName) ? skillName : null
56
+ }
57
+
58
+ function parseModelRef(
59
+ modelRef: string,
60
+ currentProvider?: string,
61
+ ): { provider: string, id: string } | null {
62
+ const trimmed = modelRef.trim()
63
+ if (!trimmed) {
64
+ return null
65
+ }
66
+
67
+ const slashIndex = trimmed.indexOf("/")
68
+ if (slashIndex > 0 && slashIndex < trimmed.length - 1) {
69
+ return {
70
+ provider: trimmed.slice(0, slashIndex),
71
+ id: trimmed.slice(slashIndex + 1),
72
+ }
73
+ }
74
+
75
+ if (!currentProvider) {
76
+ return null
77
+ }
78
+
79
+ return {
80
+ provider: currentProvider,
81
+ id: trimmed,
82
+ }
83
+ }
23
84
 
24
85
  /**
25
86
  * Create a subagent runner that handles env injection with mutex protection
@@ -223,6 +284,62 @@ const patternExtractorParams = Type.Object({
223
284
  })
224
285
 
225
286
  export default function ceCoreExtension(pi: ExtensionAPI) {
287
+ pi.on("input", async (event, ctx) => {
288
+ if (event.source === "extension") {
289
+ return { action: "continue" as const }
290
+ }
291
+
292
+ const stageKey = parseStageSkillName(event.text)
293
+ if (!stageKey) {
294
+ return { action: "continue" as const }
295
+ }
296
+
297
+ const settings = await readProjectSettings(ctx.cwd)
298
+ const modelStrategy = settings?.modelStrategy
299
+ if (!modelStrategy) {
300
+ return { action: "continue" as const }
301
+ }
302
+
303
+ const targetModelRef = modelStrategy[stageKey] ?? modelStrategy.default
304
+ if (!targetModelRef) {
305
+ return { action: "continue" as const }
306
+ }
307
+
308
+ const parsed = parseModelRef(targetModelRef, ctx.model?.provider)
309
+ if (!parsed) {
310
+ if (ctx.hasUI) {
311
+ ctx.ui.notify(`Invalid modelStrategy entry for ${stageKey}: ${targetModelRef}`, "warning")
312
+ }
313
+ return { action: "continue" as const }
314
+ }
315
+
316
+ if (ctx.model?.provider === parsed.provider && ctx.model?.id === parsed.id) {
317
+ return { action: "continue" as const }
318
+ }
319
+
320
+ const model = ctx.modelRegistry.find(parsed.provider, parsed.id)
321
+ if (!model) {
322
+ if (ctx.hasUI) {
323
+ ctx.ui.notify(`Configured model not found for ${stageKey}: ${targetModelRef}`, "warning")
324
+ }
325
+ return { action: "continue" as const }
326
+ }
327
+
328
+ const switched = await pi.setModel(model)
329
+ if (switched) {
330
+ if (ctx.hasUI) {
331
+ ctx.ui.notify(`Switched model for ${stageKey}: ${model.provider}/${model.id}`, "info")
332
+ }
333
+ return { action: "continue" as const }
334
+ }
335
+
336
+ if (ctx.hasUI) {
337
+ ctx.ui.notify(`No API key available for configured model: ${model.provider}/${model.id}`, "warning")
338
+ }
339
+
340
+ return { action: "continue" as const }
341
+ })
342
+
226
343
  const artifactHelper = createArtifactHelperTool()
227
344
  const askUserQuestion = createAskUserQuestionTool()
228
345
  const subagent = createSubagentTool()
@@ -338,7 +455,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
338
455
  return {
339
456
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
340
457
  details: result,
341
- terminate: true,
342
458
  }
343
459
  },
344
460
  })
@@ -393,7 +509,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
393
509
  return {
394
510
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
395
511
  details: result,
396
- terminate: true,
397
512
  }
398
513
  },
399
514
  })
@@ -449,7 +564,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
449
564
  return {
450
565
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
451
566
  details: result,
452
- terminate: true,
453
567
  }
454
568
  },
455
569
  })
@@ -489,7 +603,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
489
603
  return {
490
604
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
491
605
  details: result,
492
- terminate: true,
493
606
  }
494
607
  },
495
608
  })
@@ -531,7 +644,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
531
644
  return {
532
645
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
533
646
  details: result,
534
- terminate: true,
535
647
  }
536
648
  },
537
649
  })
@@ -553,7 +665,6 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
553
665
  return {
554
666
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
555
667
  details: result,
556
- terminate: true,
557
668
  }
558
669
  },
559
670
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leing2021/super-pi",
3
- "version": "0.19.2",
3
+ "version": "0.19.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Pi-native Compound Engineering package for iterative development workflows",
@@ -4,21 +4,21 @@ Use these rules in all Phase 1 skills: `01-brainstorm` → `02-plan` → `03-wor
4
4
 
5
5
  ## Start of skill: model routing
6
6
 
7
- Run this checklist before normal skill workflow:
8
-
9
- 1. Read `.pi/settings.json` from the project root.
10
- 2. Parse `modelStrategy` (if missing, skip switching).
11
- 3. Resolve current stage key:
12
- - `01-brainstorm`
13
- - `02-plan`
14
- - `03-work`
15
- - `04-review`
16
- - `05-learn`
17
- 4. Pick `targetModel = modelStrategy[stageKey] ?? modelStrategy.default`.
18
- 5. If `targetModel` exists and differs from the current model, run `/model <targetModel>`.
19
- 6. If switching fails, continue with current model and mention the failure once.
20
-
21
- ## End of skill: status + context + optional auto-continue
7
+ Model routing is handled automatically by the ce-core extension's `input` hook.
8
+ When a user types `/skill:01-brainstorm` through `/skill:05-learn`, the extension:
9
+
10
+ 1. Reads `.pi/settings.json` from the project root.
11
+ 2. Parses `modelStrategy[stageKey]` or falls back to `modelStrategy.default`.
12
+ 3. If the target model differs from the current model, calls `pi.setModel()`.
13
+ 4. If switching fails, notifies the user and continues with the current model.
14
+
15
+ No manual `/model` command is needed. The skill itself does not need to handle model switching.
16
+
17
+ Supported `modelStrategy` formats in `.pi/settings.json`:
18
+ - Full reference: `"02-plan": "anthropic/claude-opus-4-1"`
19
+ - Bare model id (reuses current provider): `"02-plan": "claude-opus-4-1"`
20
+
21
+ ## End of skill: status + context
22
22
 
23
23
  Before final completion, always output these blocks (replace placeholders with real values, never output angle-bracket placeholders literally):
24
24
 
@@ -45,16 +45,6 @@ Next step mapping:
45
45
  - `04-review` → `/skill:05-learn`
46
46
  - `05-learn` → `Completed`
47
47
 
48
- Then read `.pi/settings.json` → `pipeline.autoContinue`:
49
- - If `false` or missing, stop after the status block and wait for user input.
50
- - If current stage is `05-learn`, stop after status block.
51
- - If `true` and current stage is not `05-learn`, auto-continue is allowed only after stage-specific gates are satisfied:
52
- - `01-brainstorm`: user has explicitly approved the design handoff.
53
- - `02-plan`: review choice is resolved (A/B/C flow completed) and user confirmed to proceed.
54
- - `04-review`: optional QA choice is resolved (A/B/C flow completed) and user confirmed to proceed.
55
- - Any unclear/ambiguous state: do not auto-continue; stop and ask.
56
- - When gates are satisfied, automatically trigger the mapped next skill command.
57
-
58
48
  ### Handoff-lite template
59
49
 
60
50
  When a stage produces or updates handoff-lite, use this evidence-first structure and keep it concise (target <= 1500 tokens):