pi-recurse 0.1.3 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.5] - 2026-08-09
9
+
10
+ ### Fixed
11
+
12
+ - Grey the recurse result summary, child ids, and expanded tree lines (muted) to match pi core's output styling.
13
+
8
14
  ## [0.1.0] - 2025-03-24
9
15
 
10
16
  ### Added
package/index.ts CHANGED
@@ -478,7 +478,7 @@ export default function piRecurseExtension(pi: ExtensionAPI) {
478
478
  const icon = stats.failed === 0 ? theme.fg('success', '✓') : theme.fg('warning', '⚠');
479
479
  const hasChildren = data.results.some((r) => r.children);
480
480
 
481
- let text = `${icon} ${stats.succeeded}/${stats.total} at depth ${depth}${mode ? ` · ${mode}` : ''}`;
481
+ let text = `${icon} ${theme.fg('muted', `${stats.succeeded}/${stats.total} at depth ${depth}${mode ? ` · ${mode}` : ''}`)}`;
482
482
 
483
483
  if (stats.totalCost && stats.totalCost > 0) {
484
484
  text += theme.fg('dim', ` · $${stats.totalCost.toFixed(4)}`);
@@ -493,13 +493,13 @@ export default function piRecurseExtension(pi: ExtensionAPI) {
493
493
  // Render tree view
494
494
  const tree = buildRecurseTree(data, mode);
495
495
  const treeLines = renderRecurseTree(tree, 100);
496
- text += '\n' + treeLines.join('\n');
496
+ text += '\n' + treeLines.map((line) => theme.fg('muted', line)).join('\n');
497
497
  } else {
498
498
  // Simple flat view
499
499
  text += '\n';
500
500
  for (const r of data.results) {
501
501
  const status = r.success ? theme.fg('success', '✓') : theme.fg('error', '✗');
502
- text += ` ${status} ${r.id}`;
502
+ text += ` ${status} ${theme.fg('muted', r.id)}`;
503
503
  if (r.children) {
504
504
  text += theme.fg('accent', ` → ${r.children.stats.total} children`);
505
505
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-recurse",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Recursive agent extension for Pi — spawn subagents programmatically with depth guardrails",
5
5
  "type": "module",
6
6
  "author": "Tom X Nguyen",
@@ -29,12 +29,14 @@
29
29
  "*.d.ts",
30
30
  "lib/**",
31
31
  "tests/**",
32
+ "skills/**",
32
33
  "README.md",
33
34
  "CHANGELOG.md"
34
35
  ],
35
36
  "devDependencies": {
36
37
  "@commitlint/cli": "21.0.1",
37
38
  "@commitlint/config-conventional": "21.0.1",
39
+ "@earendil-works/pi-tui": "0.84.1",
38
40
  "@types/node": "25.9.1",
39
41
  "@vitest/coverage-v8": "4.1.7",
40
42
  "knip": "6.14.1",
@@ -43,8 +45,7 @@
43
45
  "simple-git-hooks": "2.13.1",
44
46
  "standard-version": "9.5.0",
45
47
  "typescript": "6.0.3",
46
- "vitest": "4.1.7",
47
- "@earendil-works/pi-tui": "0.84.0"
48
+ "vitest": "4.1.7"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "@earendil-works/pi-coding-agent": ">=0.74.0",
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: recurse
3
+ description: Use the `recurse` tool for programmatic subagent delegation. Supports single, parallel, and chain modes for large file processing, batch analysis, and sequential pipelines.
4
+ ---
5
+
6
+ # Recurse Skill
7
+
8
+ Use the `recurse` tool for programmatic subagent delegation.
9
+
10
+ ## When to Use
11
+
12
+ - **Large files** that exceed context window → chunk and recurse
13
+ - **Batch analysis** of multiple files → parallel mode
14
+ - **Sequential pipelines** where step N depends on step N-1 → chain mode
15
+ - **Divide-and-conquer** refactoring → parallel tasks per file
16
+
17
+ ## Mode Selection Guide
18
+
19
+ | Situation | Mode | Why |
20
+ |-----------|------|-----|
21
+ | One specific task | `single` | Simplest, direct |
22
+ | 10+ independent file reviews | `parallel` | Concurrent, fastest |
23
+ | Summary → Analysis → Plan | `chain` | Each step needs prior output |
24
+ | Cross-file refactoring | `parallel` with per-file tasks | Divide work, combine results |
25
+
26
+ ## Example Patterns
27
+
28
+ ### Parallel File Analysis
29
+ ```typescript
30
+ const files = await findFiles("src/**/*.ts");
31
+ const results = await recurse({
32
+ mode: "parallel",
33
+ tasks: files.map(f => ({
34
+ id: f,
35
+ prompt: `Review ${f}: identify bugs, suggest improvements. Be concise.`
36
+ })),
37
+ concurrency: 4
38
+ });
39
+
40
+ // Aggregate
41
+ const issues = results.results.filter(r => r.output.includes("BUG"));
42
+ ```
43
+
44
+ ### Chain: Summarize → Analyze → Plan
45
+ ```typescript
46
+ const plan = await recurse({
47
+ mode: "chain",
48
+ chain: [
49
+ { id: "readme", prompt: "Summarize README.md in 3 bullet points" },
50
+ { id: "risks", prompt: "Given this summary: {previous}, what are 3 implementation risks?" },
51
+ { id: "mitigations", prompt: "Given these risks: {previous}, suggest mitigations for each" }
52
+ ]
53
+ });
54
+ ```
55
+
56
+ ### Chunked Large File Processing
57
+ ```typescript
58
+ const totalLines = await getLineCount("huge.log");
59
+ const chunkSize = 500;
60
+ const tasks = [];
61
+
62
+ for (let start = 1; start <= totalLines; start += chunkSize) {
63
+ const end = Math.min(start + chunkSize - 1, totalLines);
64
+ tasks.push({
65
+ id: `lines-${start}-${end}`,
66
+ prompt: `Extract ERROR entries from lines ${start}-${end}`,
67
+ context: await readLines("huge.log", start, end)
68
+ });
69
+ }
70
+
71
+ const errors = await recurse({ mode: "parallel", tasks });
72
+ ```
73
+
74
+ ## Guardrails
75
+
76
+ The extension automatically enforces limits:
77
+ - Max depth (default: 3)
78
+ - Max total calls (default: 100)
79
+ - Timeout (default: 600s)
80
+ - Budget (optional, via RLM_BUDGET)
81
+
82
+ At depth ≥ 3, the recurse tool is disabled. Work directly instead.
83
+
84
+ ## Cost Awareness
85
+
86
+ Check result.stats after recurse calls:
87
+ ```typescript
88
+ const result = await recurse({ mode: "parallel", tasks });
89
+ console.log(`Cost: $${result.stats.totalCost?.toFixed(4) || 'unknown'}`);
90
+ ```