@maestria/pi 0.4.0 → 0.5.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.
- package/README.md +28 -4
- package/{prompts → agents}/adventurer.md +11 -0
- package/{prompts → agents}/architect.md +11 -0
- package/{prompts → agents}/builder.md +10 -0
- package/{prompts → agents}/diagnose.md +11 -0
- package/{prompts → agents}/planner.md +11 -0
- package/{prompts → agents}/reviewer.md +11 -0
- package/{prompts → agents}/writer.md +11 -0
- package/dist/extension.mjs +11 -10
- package/dist/extension.mjs.map +1 -1
- package/package.json +6 -11
- package/skills/global-rules/.gitkeep +0 -0
- package/{rules/AGENTS.md → skills/global-rules/SKILL.md} +9 -0
- package/skills/orchestrator/.gitkeep +0 -0
- package/{prompts/orchestrator.md → skills/orchestrator/SKILL.md} +17 -3
package/README.md
CHANGED
|
@@ -4,21 +4,45 @@ A [Pi coding agent](https://pi.software/) extension that brings Maestria's struc
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
7
|
+
- **4 Methodology Skills** - Orchestrator dispatcher, global agent rules, handoff contract, and iteration limits - automatically injected into every session via Pi's standard skill system (`SKILL.md` files registered in `pi.skills`)
|
|
8
8
|
- **3 Workflow Modes** - `fein` (full pipeline), `sonar` (research only), `blitz` (fast implementation)
|
|
9
|
-
- **
|
|
9
|
+
- **Skill-Based Prompt Injection** - Behavioral instructions injected via Pi's native skill mechanism, not custom event hooks. Skills are auto-discovered from the package manifest and loaded into the system prompt by Pi's resource loader - the standard pattern used by all major Pi extensions.
|
|
10
10
|
- **Compaction Preservation** - Session state survives compaction with structured summaries
|
|
11
11
|
- **Subagent Dispatch** - Delegation via `@gotgenes/pi-subagents` with 6-field handoff validation
|
|
12
12
|
- **Maker/Checker Split** - Review mode blocks destructive tools. Dangerous bash patterns flagged.
|
|
13
|
-
- **2 Methodology Skills** - Handoff contract + iteration limits
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
16
|
+
### Recommended: via maestria CLI
|
|
17
|
+
|
|
17
18
|
```bash
|
|
19
|
+
pnpx maestria@latest install pi
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The CLI automatically installs both `@gotgenes/pi-subagents` (required peer dependency for subagent dispatch) and `@maestria/pi` in the correct order.
|
|
23
|
+
|
|
24
|
+
### Alternative: manual Pi CLI
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Install required peer dependency first
|
|
28
|
+
pi install npm:@gotgenes/pi-subagents
|
|
29
|
+
|
|
30
|
+
# Install the extension
|
|
18
31
|
pi install npm:@maestria/pi
|
|
19
32
|
```
|
|
20
33
|
|
|
21
|
-
|
|
34
|
+
### Uninstall
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Via maestria CLI (removes @maestria/pi)
|
|
38
|
+
pnpx maestria@latest uninstall pi
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Note: `@gotgenes/pi-subagents` is a shared dependency that other Pi extensions may use. Only remove it if no other extensions need it:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pi uninstall @gotgenes/pi-subagents
|
|
45
|
+
```
|
|
22
46
|
|
|
23
47
|
## Commands
|
|
24
48
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Codebase reconnaissance specialist. Maps unknown territory, traces
|
|
4
|
+
call chains and dependencies, discovers module relationships, and
|
|
5
|
+
produces structured recon reports for downstream specialists.
|
|
6
|
+
tools: read, bash, grep, find, ls, glob
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Architecture decision specialist. Evaluates implementation approaches
|
|
4
|
+
with trade-off analysis, produces Architecture Decision Records (ADRs),
|
|
5
|
+
and documents technical decisions with business context.
|
|
6
|
+
tools: read, bash, grep, find, ls
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Focused implementation specialist. Executes one atomic, verifiable
|
|
4
|
+
unit of work per invocation with minimal context and clean diffs.
|
|
5
|
+
tools: read, bash, grep, find, ls, write, edit
|
|
6
|
+
prompt_mode: append
|
|
7
|
+
inherit_context: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
12
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
13
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Systematic bug tracing specialist. Follows a 6-step regression protocol
|
|
4
|
+
from error message to root cause to prevention, covering blast radius
|
|
5
|
+
and similar-problem scanning.
|
|
6
|
+
tools: read, bash, grep, find, ls
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Implementation planning specialist. Breaks complex features into
|
|
4
|
+
phased milestones with dependencies, timelines, verification criteria,
|
|
5
|
+
and rollback points.
|
|
6
|
+
tools: read, bash, grep, find, ls
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Code review specialist. Reviews for correctness, edge cases, security,
|
|
4
|
+
performance, and maintainability. Supports multi-lens review swarms
|
|
5
|
+
with fix/dismiss/escalate triage.
|
|
6
|
+
tools: read, bash, grep, find, ls, glob
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Documentation specialist. Creates clear, structured documentation
|
|
4
|
+
following progressive disclosure patterns for READMEs, API docs,
|
|
5
|
+
changelogs, and Architecture Decision Records.
|
|
6
|
+
tools: read, bash, grep, find, ls, write, edit
|
|
7
|
+
prompt_mode: append
|
|
8
|
+
inherit_context: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
13
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
14
|
|
package/dist/extension.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import{fileURLToPath as o}from"node:url";import{homedir as s}from"node:os";import{Type as c}from"typebox";import{SUBAGENT_EVENTS as l}from"@gotgenes/pi-subagents";import{isToolCallEventType as u}from"@earendil-works/pi-coding-agent";function d(){return{mode:null,activeTask:``,completionPromise:``,specialistsDelegated:[],blockers:[],filesModified:[],filesRead:[],handoffHistory:[],reviewMode:!1,originalModel:null,originalTools:null,subagentStatus:{},reviewModel:null}}function f(e,t,n,r){let i=[{from:t,to:n,task:r,timestamp:Date.now()},...e.handoffHistory].slice(0,5);return{...e,handoffHistory:i}}function p(e){return{state:{...e,reviewMode:!1,originalModel:null,originalTools:null},originalModel:e.originalModel,originalTools:e.originalTools}}async function m(e,t,n){let{state:r,originalModel:i,originalTools:a}=p(n);if(a&&a.length>0&&e.setActiveTools(a),i)try{let n=t.modelRegistry.getAll().find(e=>e.id===i);n&&await e.setModel(n)}catch{}Object.assign(n,r)}function h(e,t){e.appendEntry(`maestria_state`,{...t})}async function g(e,t,n){let r=n.reviewModel;if(!r)return null;try{let n=t.modelRegistry.getAll().find(e=>e.id===r);return n?(await e.setModel(n),r):(t.ui.notify(`Review model "${r}" not found in registry, staying on current.`),null)}catch{return t.ui.notify(`Could not switch to review model "${r}", staying on current.`),null}}function _(e){let t=[];if(e.mode&&t.push(`**Mode:** ${e.mode.toUpperCase()}`),e.reviewModel&&t.push(`**Review Model:** ${e.reviewModel}`),e.activeTask&&t.push(`**Goal:** ${e.activeTask}`),e.completionPromise&&t.push(`**Completion Promise:** ${e.completionPromise}`),e.specialistsDelegated.length>0&&t.push(`**Specialists Delegated:** ${e.specialistsDelegated.join(`, `)}`),e.blockers.length>0){t.push(`**Blockers:**`);for(let n of e.blockers)t.push(`- ${n}`)}let n=[];if(e.filesModified.length>0&&n.push(`**Modified:** ${e.filesModified.join(`, `)}`),e.filesRead.length>0&&n.push(`**Read:** ${e.filesRead.join(`, `)}`),n.length>0&&t.push(`**Files:** ${n.join(`; `)}`),e.handoffHistory.length>0){t.push(`**Recent Handoffs:**`);for(let n of e.handoffHistory)t.push(`- ${n.from} → ${n.to}: ${n.task}`)}return t.join(`
|
|
2
2
|
|
|
3
|
-
`)}const
|
|
3
|
+
`)}const v=a(i(o(import.meta.url)),`..`,`agents`),y=a(s(),`.pi`,`agent`,`agents`),b=[`adventurer`,`architect`,`builder`,`diagnose`,`planner`,`reviewer`,`writer`];function x(i){let o=v;if(!e(o)){console.warn(`[maestria] Agents source directory not found:`,o);return}try{t(y,{recursive:!0})}catch{console.warn(`[maestria] Could not create agents directory:`,y);return}let s=0;for(let t of b){let i=a(o,`${t}.md`),c=a(y,`${t}.md`);if(!e(i)){console.warn(`[maestria] Agent source not found: ${t}.md`);continue}if(!e(c))try{r(c,n(i,`utf-8`),`utf-8`),s++}catch(e){console.warn(`[maestria] Failed to deploy agent ${t}:`,e)}}s>0&&console.log(`[maestria] Deployed ${s} specialist agents to ${y}`)}const S=[`fein`,`sonar`,`blitz`],C={fein:[`## MODE: fein (Full Pipeline)`,``,`Execute the complete fein pipeline: mandatory reconnaissance`,`(/adventurer) → design/plan (/architect or /planner) →`,`implementation (/builder) → review (/reviewer).`,`Do NOT skip any phase unless the user explicitly overrides`,`in the same turn.`].join(`
|
|
4
4
|
`),sonar:[`## MODE: sonar (Research Only)`,``,`Execute research only: /adventurer (recon) →`,`/architect or /planner (design/plan) → STOP.`,`Do NOT implement anything. Return findings.`].join(`
|
|
5
5
|
`),blitz:[`## MODE: blitz (Fast Implementation)`,``,`Execute fast implementation via /builder directly.`,`Skip reconnaissance and design unless the codebase`,`is genuinely unknown. Skip review unless the result`,`needs validation.`].join(`
|
|
6
|
-
`)},
|
|
7
|
-
`);e.sendUserMessage(t,{deliverAs:`steer`})}else i.ui.notify(`Mode set to ${n}. Describe what you'd like to work on.`)}})}
|
|
8
|
-
`)}}}function
|
|
6
|
+
`)},w={fein:`[MODE: fein]`,sonar:`[MODE: sonar]`,blitz:`[MODE: blitz]`};function T(e){return`${w[e]}\n\n${C[e]}`}function E(e,t){for(let n of S)e.registerCommand(n,{description:`Set workflow mode to ${n}`,handler:async(r,i)=>{if(t.reviewMode&&await m(e,i,t),t.mode=n,h(e,t),r.trim()){let t=[T(n),``,`Run the maestria default pipeline on: ${r}`].join(`
|
|
7
|
+
`);e.sendUserMessage(t,{deliverAs:`steer`})}else i.ui.notify(`Mode set to ${n}. Describe what you'd like to work on.`)}})}function D(e){return(t,n)=>{if(e.mode)return{systemPrompt:[t.systemPrompt,``,T(e.mode),``,`The user has set workflow mode to "${e.mode}". Honor this mode throughout the session until changed via /command.`].join(`
|
|
8
|
+
`)}}}function O(e,t){e.on(`session_before_compact`,e=>({compaction:{summary:_(t),details:{...t},firstKeptEntryId:e.preparation.firstKeptEntryId,tokensBefore:e.preparation.tokensBefore}})),e.on(`session_before_tree`,e=>{if(e.preparation.userWantsSummary)return{summary:{summary:_(t)}}})}const k={REVIEW_ACTIVATED:`maestria:review:activated`,REVIEW_DEACTIVATED:`maestria:review:deactivated`,SUBAGENT_STARTED:`maestria:subagent:started`,SUBAGENT_COMPLETED:`maestria:subagent:completed`,SUBAGENT_FAILED:`maestria:subagent:failed`},A=[`adventurer`,`architect`,`builder`,`diagnose`,`planner`,`reviewer`,`writer`],j=new Set([`completed`,`steered`,`aborted`,`stopped`,`error`]);function M(e,t,n){if(e.registerTool({name:`maestria_subagent`,label:`Maestria Subagent`,description:`Dispatch a task to a @maestria specialist subagent`,promptSnippet:`Delegate tasks to @maestria specialist subagents (adventurer, architect, builder, planner, diagnose, reviewer, writer)`,promptGuidelines:[`Use maestria_subagent when a task MUST be delegated to a specialist subagent rather than handled directly. Each specialist has focused capabilities: adventurer (recon), architect (design), builder (impl), planner (planning), diagnose (bugs), reviewer (QA), writer (docs).`],prepareArguments(e){return e},parameters:c.Object({agent:c.Optional(c.String({description:`Specialist agent name`})),task:c.Optional(c.String({description:`Task description for the subagent`})),tasks:c.Optional(c.Array(c.Object({agent:c.String(),task:c.String()}),{description:`Array of task objects for parallel or chain dispatch`})),mode:c.Optional(c.Union([c.Literal(`parallel`),c.Literal(`chain`),c.Literal(`single`)]))}),async execute(n,r,i,a,o){if(t.reviewMode)return{content:[{type:`text`,text:`Subagent dispatch is not available during review mode. Use /restore-model to exit review mode first.`}]};let s=r.mode??`single`;if(s===`single`){if(!A.includes(r.agent))throw Error(`Unknown agent: "${r.agent}". Allowed: ${A.join(`, `)}`);if(!r.task||!r.task.trim())throw Error(`Task description is required`)}else if(s===`parallel`){if(!r.tasks||r.tasks.length<2)throw Error(`For parallel mode, tasks array is required with at least 2 items`);if(r.tasks.length>8)throw Error(`For parallel mode, tasks array may have at most 8 items (got ${r.tasks.length})`);for(let e of r.tasks){if(!A.includes(e.agent))throw Error(`Unknown agent: "${e.agent}". Allowed: ${A.join(`, `)}`);if(!e.task||!e.task.trim())throw Error(`Task description is required for all tasks`)}}else if(s===`chain`){if(!r.tasks||r.tasks.length<2)throw Error(`For chain mode, tasks array is required with at least 2 items`);for(let e of r.tasks){if(!A.includes(e.agent))throw Error(`Unknown agent: "${e.agent}". Allowed: ${A.join(`, `)}`);if(!e.task||!e.task.trim())throw Error(`Task description is required for all tasks`)}}let{getSubagentsService:c}=await import(`@gotgenes/pi-subagents`),l=c();if(!l||typeof l.spawn!=`function`)return{content:[{type:`text`,text:[`## Subagent Dispatch Unavailable`,``,"The `@gotgenes/pi-subagents` extension is required for subagent dispatch but has not been loaded.",``,`Install it as a Pi extension:`,``,"```",`pi install npm:@gotgenes/pi-subagents`,"```",``,`Then restart your Pi session.`].join(`
|
|
9
|
+
`)}]};try{async function n(e,t,n){let r=0,o=l.getRecord(e);for(;o&&!j.has(o.status)&&r<120;){if(i?.aborted)throw Error(`Maestria subagent call aborted`);await new Promise(e=>setTimeout(e,500)),o=l.getRecord(e),r++,n&&a?.({content:[{type:`text`,text:`${t} running... (${Math.round(r*500/1e3)}s)`}]})}if(o&&!j.has(o.status))throw Error(`Subagent ${e} timed out after 60000ms`);if(!o)throw Error(`Subagent ${e} was cleaned up before completion`);return o}if(s===`single`){let i=r.agent,a=r.task,o=l.spawn(i,a,{description:a.slice(0,80),foreground:!0,inheritContext:!0}),s=f(t,`orchestrator`,i,a);Object.assign(t,s),e.appendEntry(`maestria_state`,t);let c=await n(o,`Subagent ${i}`,!0);return{content:[{type:`text`,text:c.result??c.error??`No output.`}],details:{subagentId:o}}}if(s===`parallel`){let i=r.tasks;a?.({content:[{type:`text`,text:`Spawning ${i.length} parallel subagents...`}]});let o=[];for(let e of i){let n=l.spawn(e.agent,e.task,{description:e.task.slice(0,80),foreground:!0,inheritContext:!0});o.push(n);let r=f(t,`orchestrator`,e.agent,e.task);Object.assign(t,r)}e.appendEntry(`maestria_state`,t);let s=await Promise.all(o.map((e,t)=>n(e,`${i[t].agent} (${t+1}/${i.length})`,!1)));a?.({content:[{type:`text`,text:`All ${i.length} parallel subagents completed.`}]});let c=[`## Parallel Results (${i.length} tasks)\n`];for(let e=0;e<i.length;e++){let t=i[e],n=s[e],r=n.result??n.error??`No output.`;c.push(`### ${e+1}: ${t.agent}`),c.push(r)}return{content:[{type:`text`,text:c.join(`
|
|
9
10
|
|
|
10
|
-
`)}],details:{subagentIds:
|
|
11
|
-
`)}]}}}}),e.events){let r=e.events.on(
|
|
12
|
-
`),{deliverAs:`steer`})}}),e.registerCommand(`maestria-status`,{description:`Show current maestria session state including handoff history`,handler:async(e,n)=>{let r=
|
|
13
|
-
`),{deliverAs:`steer`})}}),e.registerCommand(`restore-model`,{description:`Restore the original model and tools that were active before review mode was entered.`,handler:async(n,r)=>{if(!t.reviewMode){r.ui.notify(`Not in review mode. Nothing to restore.`);return}let i=t.originalModel;await
|
|
11
|
+
`)}],details:{subagentIds:o}}}if(s===`chain`){let i=r.tasks,o=``;for(let r=0;r<i.length;r++){let s=i[r],c=s.task;r>0&&c.includes(`{previous}`)&&(c=c.replace(/\{previous\}/g,o));let u=l.spawn(s.agent,c,{description:c.slice(0,80),foreground:!0,inheritContext:!0}),d=f(t,`orchestrator`,s.agent,c);Object.assign(t,d),e.appendEntry(`maestria_state`,t),a?.({content:[{type:`text`,text:`Chain step ${r+1}/${i.length}: ${s.agent} running...`}]});let p=await n(u,`Chain step ${r+1}: ${s.agent}`,!0);o=p.result??p.error??`No output.`,r<i.length-1&&a?.({content:[{type:`text`,text:`Chain step ${r+1}/${i.length}: ${s.agent} completed. Moving to next step.`}]})}return{content:[{type:`text`,text:o}],details:{subagentId:`chain-completed`}}}throw Error(`Unknown dispatch mode`)}catch(e){console.warn(`[maestria] Subagent dispatch failed:`,e);let t=r.agent??r.tasks?.[0]?.agent??`unknown`,n=r.task??r.tasks?.map(e=>e.task).join(`; `)??`unknown`;return{content:[{type:`text`,text:[`## Subagent Handoff Required`,``,`**From:** orchestrator`,`**To:** ${t}`,`**Task:** ${n}`,``,`Subagent dispatch failed. Please delegate this work manually.`].join(`
|
|
12
|
+
`)}]}}}}),e.events){let r=e.events.on(l.STARTED,n=>{let{id:r,type:i}=n;t.subagentStatus[r]={type:i,status:`running`,startedAt:Date.now()},h(e,t),e.events?.emit(k.SUBAGENT_STARTED,{id:r,type:i,timestamp:Date.now()})}),i=e.events.on(l.COMPLETED,n=>{let{id:r}=n,i=t.subagentStatus[r];i&&(i.status=`completed`,i.completedAt=Date.now()),h(e,t),e.events?.emit(k.SUBAGENT_COMPLETED,{id:r,type:i?.type,timestamp:Date.now()})}),a=e.events.on(l.FAILED,n=>{let{id:r,status:i}=n,a=t.subagentStatus[r];a&&(a.status=i??`error`,a.completedAt=Date.now()),h(e,t),e.events?.emit(k.SUBAGENT_FAILED,{id:r,type:a?.type,timestamp:Date.now()})}),o=e.events.on(l.STEERED,n=>{let{id:r}=n;t.subagentStatus[r]||(t.subagentStatus[r]={type:`unknown`,status:`running`,startedAt:Date.now()}),h(e,t)});n&&n.push(r,i,a,o)}}const N=[`read`,`grep`,`find`,`ls`,`glob`];function P(e,t){e.registerCommand(`orchestrate`,{description:`Start a full pipeline by delegating to the orchestrator`,handler:async(n,r)=>{if(!n.trim()){r.ui.notify(`Usage: /orchestrate <goal> - describe what to accomplish`);return}if(t.reviewMode){let n=t.originalModel;await m(e,r,t),h(e,t),e.events?.emit(k.REVIEW_DEACTIVATED,{originalModel:n,source:`orchestrate`,timestamp:Date.now()})}e.sendUserMessage([`[ORCHESTRATE: ${n}]`,``,`Orchestrate the full maestria pipeline to: ${n}`,`Use the orchestrator prompt template for subagent delegation.`].join(`
|
|
13
|
+
`),{deliverAs:`steer`})}}),e.registerCommand(`maestria-status`,{description:`Show current maestria session state including handoff history`,handler:async(e,n)=>{let r=_(t);if(!r){n.ui.notify(`No active maestria state to report.`);return}n.ui.setEditorText(r)}}),e.registerCommand(`review`,{description:`Enter review mode. Blocks destructive tools, sets read-only toolset.`,handler:async(n,r)=>{if(!n.trim()){r.ui.notify(`Usage: /review <target> - describe what to review`);return}let i=r.model?.id??null,a=e.getActiveTools(),o={...t,reviewMode:!0,originalModel:i,originalTools:a};if(Object.assign(t,o),h(e,t),t.reviewModel){let n=await g(e,r,t);n&&(r.ui.notify(`Review mode: switched to ${n}`),e.events?.emit(k.REVIEW_ACTIVATED,{originalModel:t.originalModel,reviewModel:n,timestamp:Date.now()}))}e.setActiveTools(N),e.sendUserMessage([`[REVIEW: ${n}]`,``,`Review: ${n}. Use the reviewer prompt template.`,`Read only, no edits, report findings.`].join(`
|
|
14
|
+
`),{deliverAs:`steer`})}}),e.registerCommand(`restore-model`,{description:`Restore the original model and tools that were active before review mode was entered.`,handler:async(n,r)=>{if(!t.reviewMode){r.ui.notify(`Not in review mode. Nothing to restore.`);return}let i=t.originalModel;await m(e,r,t),h(e,t),r.ui.notify(`Restored original model and tools.`),e.events?.emit(k.REVIEW_DEACTIVATED,{originalModel:i,timestamp:Date.now()})}}),e.registerCommand(`handoff`,{description:`Generate a structured handoff prompt for a new task context`,handler:async(n,r)=>{if(!n.trim()){r.ui.notify(`Usage: /handoff <goal> - describe the task context for handoff`);return}let i=n.trim(),a=[`**Goal:** `+i,``,`**Context:**`,`- Mode: `+(t.mode??`none`),`- Active task: `+(t.activeTask||`none`),`- Specialists delegated: `+((t.specialistsDelegated?.length??0)>0?t.specialistsDelegated.join(`, `):`none`),`- Recent handoffs: `+(t.handoffHistory?.length??0)+` entries`,`- Files modified: `+((t.filesModified?.length??0)>0?t.filesModified.join(`, `):`none`),``,`**Requirements:**`,`(fill in specific requirements)`,``,`**Known problems:**`,(t.blockers?.length??0)>0?t.blockers.map(e=>`- `+e).join(`
|
|
14
15
|
`):`(no known problems documented)`,``,`**Success criteria:**`,`(fill in how to verify completion)`,``,`**Next step:**`,`(fill in what happens after this task)`,``,`---`,`Complete the fields above before sending.`].join(`
|
|
15
|
-
`);t.handoffHistory=[{from:`current`,to:`next`,task:i,timestamp:Date.now()},...t.handoffHistory??[]].slice(0,5),
|
|
16
|
+
`);t.handoffHistory=[{from:`current`,to:`next`,task:i,timestamp:Date.now()},...t.handoffHistory??[]].slice(0,5),h(e,t),e.sendUserMessage(a,{deliverAs:`steer`})}}),e.registerCommand(`review-model`,{description:`Set which model to use when entering review mode`,handler:async(n,r)=>{if(!n.trim()){r.ui.notify(`Usage: /review-model <model-id>`);return}let i=n.trim(),a=r.modelRegistry.getAll();if(!a.find(e=>e.id===i)){r.ui.notify(`Unknown model: "${i}". Available: ${a.map(e=>e.id).join(`, `)}`);return}t.reviewModel=i,h(e,t),r.ui.notify(`Review model set to: ${i}`)}})}const F=[/rm\s+-rf\s+\//,/dd\s+if=/,/>\s*\/dev\/sd/,/chmod\s+-R\s+777\s+\//,/mkfs\.\w+/,/:(){ :\|:& };:/,/>\s*\/etc\/(passwd|shadow|sudoers)/,/\beval\b/,/wget\s+-O\s*-\s*\|\s*(bash|sh)/,/curl\s+.*\|\s*(bash|sh)/,/crontab\s+-r/];function I(e,t){e.on(`tool_call`,async(e,n)=>{if(!(!e||!e.toolName)){if(t.reviewMode&&(u(`edit`,e)||u(`write`,e)||u(`bash`,e)))return{block:!0,reason:`Review mode is active. Report findings, do not edit.`};if(u(`bash`,e)){if(!e.input||typeof e.input!=`object`)return;let t=e.input.command;if(t){for(let e of F)if(e.test(t))return n.hasUI&&await n.ui.confirm(`Dangerous Pattern Detected`,`This command matches a dangerous pattern:\n${t}\nProceed?`)?void 0:{block:!0,reason:`Command matches dangerous pattern: ${e}`}}}}})}function L(e){let t=d(),n=[];E(e,t);let r=D(t);e.on(`before_agent_start`,(e,t)=>r(e,t)),e.on(`session_start`,(e,n)=>{if(x(n),!n.sessionManager?.getEntries)return;let r=n.sessionManager.getEntries();for(let e=r.length-1;e>=0;e--){let n=r[e];if(n.type===`custom`&&n.customType===`maestria_state`){let e=n.data;e&&typeof e==`object`&&Object.assign(t,e);break}}}),O(e,t),M(e,t,n),P(e,t),e.on(`session_shutdown`,()=>{for(let e of n)e();n.length=0}),I(e,t)}export{L as default};
|
|
16
17
|
//# sourceMappingURL=extension.mjs.map
|
package/dist/extension.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.mjs","names":[],"sources":["../src/state.ts","../src/modes.ts","../src/rules.ts","../src/compaction.ts","../src/subagent.ts","../src/commands.ts","../src/tools.ts","../src/extension.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionCommandContext } from '@earendil-works/pi-coding-agent';\nimport type { ModeKeyword } from '@/modes.js';\n\nconst HANDOFF_HISTORY_CAP = 5;\nconst FILE_HISTORY_CAP = 10;\n\nexport interface HandoffEntry {\n from: string;\n to: string;\n task: string;\n timestamp: number;\n}\n\nexport interface SubagentStatusInfo {\n type: string;\n status: string;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface MaestriaState {\n mode: ModeKeyword | null;\n activeTask: string;\n completionPromise: string;\n specialistsDelegated: string[];\n blockers: string[];\n filesModified: string[];\n filesRead: string[];\n handoffHistory: HandoffEntry[];\n reviewMode: boolean;\n originalModel: string | null;\n originalTools: string[] | null;\n subagentStatus: Record<string, SubagentStatusInfo>;\n /** Model ID to use when entering review mode. Null = no preference. */\n reviewModel: string | null;\n}\n\nexport function createInitialState(): MaestriaState {\n return {\n mode: null,\n activeTask: '',\n completionPromise: '',\n specialistsDelegated: [],\n blockers: [],\n filesModified: [],\n filesRead: [],\n handoffHistory: [],\n reviewMode: false,\n originalModel: null,\n originalTools: null,\n subagentStatus: {},\n reviewModel: null,\n };\n}\n\nexport function recordHandoff(\n state: MaestriaState,\n from: string,\n to: string,\n task: string,\n): MaestriaState {\n const entry: HandoffEntry = { from, to, task, timestamp: Date.now() };\n const history = [entry, ...state.handoffHistory].slice(0, HANDOFF_HISTORY_CAP);\n return { ...state, handoffHistory: history };\n}\n\nfunction prependDeduped(files: string[], path: string, cap: number): string[] {\n const filtered = files.filter((f) => f !== path);\n return [path, ...filtered].slice(0, cap);\n}\n\nexport function recordFileModified(state: MaestriaState, path: string): MaestriaState {\n return { ...state, filesModified: prependDeduped(state.filesModified, path, FILE_HISTORY_CAP) };\n}\n\nexport function recordFileRead(state: MaestriaState, path: string): MaestriaState {\n return { ...state, filesRead: prependDeduped(state.filesRead, path, FILE_HISTORY_CAP) };\n}\n\nexport function recordSubagentStatus(\n state: MaestriaState,\n id: string,\n info: SubagentStatusInfo,\n): MaestriaState {\n return { ...state, subagentStatus: { ...state.subagentStatus, [id]: info } };\n}\n\nexport function setReviewMode(state: MaestriaState, active: boolean): MaestriaState {\n return {\n ...state,\n reviewMode: active,\n };\n}\n\n/**\n * Exit review mode and return the original model/tools for restoration.\n * Returns a new state (immutable) with review mode cleared and the\n * saved originals so the caller can pass them to pi.setModel/setActiveTools.\n */\nexport function exitReviewMode(state: MaestriaState): {\n state: MaestriaState;\n originalModel: string | null;\n originalTools: string[] | null;\n} {\n return {\n state: {\n ...state,\n reviewMode: false,\n originalModel: null,\n originalTools: null,\n },\n originalModel: state.originalModel,\n originalTools: state.originalTools,\n };\n}\n\n/**\n * Restore the original model and tools saved when review mode was entered.\n * Clears review mode from state and resets pi to the pre-review configuration.\n */\nexport async function restoreOriginalState(\n pi: ExtensionAPI,\n ctx: ExtensionCommandContext,\n state: MaestriaState,\n): Promise<void> {\n const { state: clearedState, originalModel, originalTools } = exitReviewMode(state);\n\n // Restore original tools first (makes full toolset available again)\n if (originalTools && originalTools.length > 0) {\n pi.setActiveTools(originalTools);\n }\n\n // Restore original model - best-effort, failures are non-fatal\n if (originalModel) {\n try {\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m: { id: string }) => m.id === originalModel);\n if (model) {\n await pi.setModel(model);\n }\n } catch {\n // Best-effort: model restoration is non-critical\n }\n }\n\n // Clear review mode state\n Object.assign(state, clearedState);\n}\n\n/**\n * Persist the current state to the session by appending a custom entry.\n * Creates a shallow copy to ensure appendEntry sees the latest snapshot.\n */\nexport function persistState(pi: ExtensionAPI, state: MaestriaState): void {\n pi.appendEntry('maestria_state', { ...state });\n}\n\n/**\n * If a review model is configured, switch to it.\n * Returns the model ID switched to, or null if no switch occurred.\n */\nexport async function cycleToReviewModel(\n pi: ExtensionAPI,\n ctx: ExtensionCommandContext,\n state: MaestriaState,\n): Promise<string | null> {\n const reviewModel = state.reviewModel;\n if (!reviewModel) {\n return null;\n }\n try {\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m) => m.id === reviewModel);\n if (model) {\n await pi.setModel(model);\n return reviewModel;\n } else {\n ctx.ui.notify(`Review model \"${reviewModel}\" not found in registry, staying on current.`);\n return null;\n }\n } catch {\n ctx.ui.notify(`Could not switch to review model \"${reviewModel}\", staying on current.`);\n return null;\n }\n}\n\nexport function renderMaestriaSummary(state: MaestriaState): string {\n const parts: string[] = [];\n\n if (state.mode) {\n parts.push(`**Mode:** ${state.mode.toUpperCase()}`);\n }\n\n if (state.reviewModel) {\n parts.push(`**Review Model:** ${state.reviewModel}`);\n }\n\n if (state.activeTask) {\n parts.push(`**Goal:** ${state.activeTask}`);\n }\n\n if (state.completionPromise) {\n parts.push(`**Completion Promise:** ${state.completionPromise}`);\n }\n\n if (state.specialistsDelegated.length > 0) {\n parts.push(`**Specialists Delegated:** ${state.specialistsDelegated.join(', ')}`);\n }\n\n if (state.blockers.length > 0) {\n parts.push('**Blockers:**');\n for (const blocker of state.blockers) {\n parts.push(`- ${blocker}`);\n }\n }\n\n const fileSubs: string[] = [];\n if (state.filesModified.length > 0) {\n fileSubs.push(`**Modified:** ${state.filesModified.join(', ')}`);\n }\n if (state.filesRead.length > 0) {\n fileSubs.push(`**Read:** ${state.filesRead.join(', ')}`);\n }\n if (fileSubs.length > 0) {\n parts.push(`**Files:** ${fileSubs.join('; ')}`);\n }\n\n if (state.handoffHistory.length > 0) {\n parts.push('**Recent Handoffs:**');\n for (const entry of state.handoffHistory) {\n parts.push(`- ${entry.from} → ${entry.to}: ${entry.task}`);\n }\n }\n\n return parts.join('\\n\\n');\n}\n\nexport { HANDOFF_HISTORY_CAP, FILE_HISTORY_CAP };\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { persistState, restoreOriginalState } from '@/state.js';\n\nexport const MODE_KEYWORDS = ['fein', 'sonar', 'blitz'] as const;\nexport type ModeKeyword = (typeof MODE_KEYWORDS)[number];\n\nconst MODE_PROMPTS: Record<ModeKeyword, string> = {\n fein: [\n '## MODE: fein (Full Pipeline)',\n '',\n 'Execute the complete fein pipeline: mandatory reconnaissance',\n '(/adventurer) → design/plan (/architect or /planner) →',\n 'implementation (/builder) → review (/reviewer).',\n 'Do NOT skip any phase unless the user explicitly overrides',\n 'in the same turn.',\n ].join('\\n'),\n sonar: [\n '## MODE: sonar (Research Only)',\n '',\n 'Execute research only: /adventurer (recon) →',\n '/architect or /planner (design/plan) → STOP.',\n 'Do NOT implement anything. Return findings.',\n ].join('\\n'),\n blitz: [\n '## MODE: blitz (Fast Implementation)',\n '',\n 'Execute fast implementation via /builder directly.',\n 'Skip reconnaissance and design unless the codebase',\n 'is genuinely unknown. Skip review unless the result',\n 'needs validation.',\n ].join('\\n'),\n};\n\nconst MODE_MARKERS: Record<ModeKeyword, string> = {\n fein: '[MODE: fein]',\n sonar: '[MODE: sonar]',\n blitz: '[MODE: blitz]',\n};\n\nexport function getModePrompt(keyword: ModeKeyword): string {\n return `${MODE_MARKERS[keyword]}\\n\\n${MODE_PROMPTS[keyword]}`;\n}\n\nexport function installModeCommands(pi: ExtensionAPI, state: MaestriaState): void {\n for (const keyword of MODE_KEYWORDS) {\n pi.registerCommand(keyword, {\n description: `Set workflow mode to ${keyword}`,\n handler: async (args, ctx) => {\n // Exit review mode if active (restore original model/tools)\n if (state.reviewMode) {\n await restoreOriginalState(pi, ctx, state);\n }\n\n state.mode = keyword;\n persistState(pi, state);\n\n if (args.trim()) {\n const modeMessage = [\n getModePrompt(keyword),\n '',\n `Run the maestria default pipeline on: ${args}`,\n ].join('\\n');\n pi.sendUserMessage(modeMessage, { deliverAs: 'steer' });\n } else {\n ctx.ui.notify(`Mode set to ${keyword}. Describe what you'd like to work on.`);\n }\n },\n });\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type {\n BeforeAgentStartEvent,\n BeforeAgentStartEventResult,\n ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { getModePrompt } from '@/modes.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst RULES_CONTENT = readFileSync(join(__dirname, '..', 'rules', 'AGENTS.md'), 'utf-8');\n\nexport function createBeforeAgentStartHandler(state: MaestriaState) {\n return (\n event: BeforeAgentStartEvent,\n _ctx: ExtensionContext,\n ): BeforeAgentStartEventResult | void => {\n const parts: string[] = [RULES_CONTENT, '', event.systemPrompt];\n\n if (state.mode) {\n parts.push('', getModePrompt(state.mode));\n parts.push(\n '',\n `The user has set workflow mode to \"${state.mode}\". ` +\n 'Honor this mode throughout the session until changed via /command.',\n );\n }\n\n return { systemPrompt: parts.join('\\n') };\n };\n}\n","import type {\n ExtensionAPI,\n SessionBeforeCompactEvent,\n SessionBeforeTreeEvent,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { renderMaestriaSummary } from '@/state.js';\n\nexport function installCompactionHandlers(pi: ExtensionAPI, state: MaestriaState): void {\n pi.on('session_before_compact', (event: SessionBeforeCompactEvent) => {\n return {\n compaction: {\n summary: renderMaestriaSummary(state),\n details: { ...state },\n firstKeptEntryId: event.preparation.firstKeptEntryId,\n tokensBefore: event.preparation.tokensBefore,\n },\n };\n });\n\n pi.on('session_before_tree', (event: SessionBeforeTreeEvent) => {\n if (event.preparation.userWantsSummary) {\n return {\n summary: {\n summary: renderMaestriaSummary(state),\n },\n };\n }\n return undefined;\n });\n}\n","import { Type } from 'typebox';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { SUBAGENT_EVENTS } from '@gotgenes/pi-subagents';\nimport type { MaestriaState } from '@/state.js';\nimport { persistState, recordHandoff } from '@/state.js';\n\n/**\n * Maestria cross-extension event names.\n * Other Pi extensions can subscribe via `pi.events?.on(...)`.\n * Convention: `maestria:<domain>:<action>`\n */\nexport const MAESTRIA_EVENTS = {\n REVIEW_ACTIVATED: 'maestria:review:activated',\n REVIEW_DEACTIVATED: 'maestria:review:deactivated',\n SUBAGENT_STARTED: 'maestria:subagent:started',\n SUBAGENT_COMPLETED: 'maestria:subagent:completed',\n SUBAGENT_FAILED: 'maestria:subagent:failed',\n} as const;\n\nconst ALLOWED_AGENTS = [\n 'adventurer',\n 'architect',\n 'builder',\n 'diagnose',\n 'planner',\n 'reviewer',\n 'writer',\n] as const;\ntype AllowedAgent = (typeof ALLOWED_AGENTS)[number];\n\n// The 6-field handoff contract\nconst HANDOFF_FIELDS = [\n 'Goal',\n 'Context',\n 'Requirements',\n 'Known problems',\n 'Success criteria',\n 'Next step',\n] as const;\n\n/** Terminal subagent statuses - agent will produce no more updates. */\nconst TERMINAL_STATUSES = new Set(['completed', 'steered', 'aborted', 'stopped', 'error']);\n\n/** Maximum time to wait for a subagent to complete, in milliseconds. */\nexport const POLL_TIMEOUT_MS = 60_000;\n\n/** Interval between subagent status checks, in milliseconds. */\nexport const POLL_INTERVAL_MS = 500;\n\n/** Maximum number of tasks allowed in parallel dispatch. */\nexport const MAX_PARALLEL_TASKS = 8;\n\nexport function validateHandoff(handoff: string): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n for (const field of HANDOFF_FIELDS) {\n const regex = new RegExp(`\\\\*\\\\*${field}:\\\\*\\\\*[\\\\s\\\\S]*?\\\\S`, 'i');\n if (!regex.test(handoff)) {\n errors.push(`Missing or empty field: \"${field}\"`);\n }\n }\n return { valid: errors.length === 0, errors };\n}\n\nexport function installSubagentTool(\n pi: ExtensionAPI,\n state: MaestriaState,\n cleanups?: Array<() => void>,\n): void {\n pi.registerTool({\n name: 'maestria_subagent',\n label: 'Maestria Subagent',\n description: 'Dispatch a task to a @maestria specialist subagent',\n promptSnippet:\n 'Delegate tasks to @maestria specialist subagents (adventurer, architect, builder, planner, diagnose, reviewer, writer)',\n promptGuidelines: [\n 'Use maestria_subagent when a task MUST be delegated to a specialist subagent rather than handled directly. Each specialist has focused capabilities: adventurer (recon), architect (design), builder (impl), planner (planning), diagnose (bugs), reviewer (QA), writer (docs).',\n ],\n prepareArguments(args: unknown) {\n return args;\n },\n parameters: Type.Object({\n agent: Type.Optional(Type.String({ description: 'Specialist agent name' })),\n task: Type.Optional(Type.String({ description: 'Task description for the subagent' })),\n tasks: Type.Optional(\n Type.Array(\n Type.Object({\n agent: Type.String(),\n task: Type.String(),\n }),\n { description: 'Array of task objects for parallel or chain dispatch' },\n ),\n ),\n mode: Type.Optional(\n Type.Union([Type.Literal('parallel'), Type.Literal('chain'), Type.Literal('single')]),\n ),\n }),\n async execute(\n _toolCallId: string,\n params: {\n agent?: string;\n task?: string;\n tasks?: Array<{ agent: string; task: string }>;\n mode?: 'parallel' | 'chain' | 'single';\n },\n signal: AbortSignal | undefined,\n onUpdate: ((result: { content: Array<{ type: string; text: string }> }) => void) | undefined,\n _ctx: ExtensionContext,\n ) {\n // Block subagent dispatch when in review mode\n if (state.reviewMode) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Subagent dispatch is not available during review mode. Use /restore-model to exit review mode first.',\n },\n ],\n };\n }\n\n // Determine dispatch mode (default to 'single' for backward compat)\n const mode = params.mode ?? 'single';\n\n // Validate parameters based on mode\n if (mode === 'single') {\n // Backward-compatible validation - must match original error messages exactly\n if (!ALLOWED_AGENTS.includes(params.agent as AllowedAgent)) {\n throw new Error(\n `Unknown agent: \"${params.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`,\n );\n }\n if (!params.task || !params.task.trim()) {\n throw new Error('Task description is required');\n }\n } else if (mode === 'parallel') {\n if (!params.tasks || params.tasks.length < 2) {\n throw new Error(`For parallel mode, tasks array is required with at least 2 items`);\n }\n if (params.tasks.length > MAX_PARALLEL_TASKS) {\n throw new Error(\n `For parallel mode, tasks array may have at most ${MAX_PARALLEL_TASKS} items (got ${params.tasks.length})`,\n );\n }\n for (const t of params.tasks) {\n if (!ALLOWED_AGENTS.includes(t.agent as AllowedAgent)) {\n throw new Error(`Unknown agent: \"${t.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`);\n }\n if (!t.task || !t.task.trim()) {\n throw new Error('Task description is required for all tasks');\n }\n }\n } else if (mode === 'chain') {\n if (!params.tasks || params.tasks.length < 2) {\n throw new Error('For chain mode, tasks array is required with at least 2 items');\n }\n for (const t of params.tasks) {\n if (!ALLOWED_AGENTS.includes(t.agent as AllowedAgent)) {\n throw new Error(`Unknown agent: \"${t.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`);\n }\n if (!t.task || !t.task.trim()) {\n throw new Error('Task description is required for all tasks');\n }\n }\n }\n\n // Attempt to dispatch via @gotgenes/pi-subagents; fallback gracefully\n try {\n const { getSubagentsService } = await import('@gotgenes/pi-subagents');\n const service = getSubagentsService()!;\n if (typeof service.spawn !== 'function') {\n throw new Error('Subagents service unavailable or incomplete');\n }\n\n // Helper: poll a single subagent until terminal or timeout\n async function pollSubagent(\n id: string,\n label: string,\n sendUpdates: boolean,\n ): Promise<{ status: string; result?: string; error?: string }> {\n const maxPolls = POLL_TIMEOUT_MS / POLL_INTERVAL_MS;\n let polls = 0;\n let record = service.getRecord(id);\n while (record && !TERMINAL_STATUSES.has(record.status) && polls < maxPolls) {\n if (signal?.aborted) throw new Error('Maestria subagent call aborted');\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n record = service.getRecord(id);\n polls++;\n if (sendUpdates) {\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `${label} running... (${Math.round((polls * POLL_INTERVAL_MS) / 1000)}s)`,\n },\n ],\n });\n }\n }\n if (record && !TERMINAL_STATUSES.has(record.status)) {\n throw new Error(`Subagent ${id} timed out after ${POLL_TIMEOUT_MS}ms`);\n }\n if (!record) {\n throw new Error(`Subagent ${id} was cleaned up before completion`);\n }\n return record;\n }\n\n // --- SINGLE MODE ---\n if (mode === 'single') {\n const agent = params.agent!;\n const task = params.task!;\n\n // Spawn in foreground - returns subagent ID synchronously\n const id = service.spawn(agent, task, {\n description: task.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n\n // Record handoff in state and persist (only after spawn succeeds)\n const updatedState = recordHandoff(state, 'orchestrator', agent, task);\n Object.assign(state, updatedState);\n pi.appendEntry('maestria_state', state);\n\n // Poll for completion\n const record = await pollSubagent(id, `Subagent ${agent}`, true);\n\n const resultText = record.result ?? record.error ?? 'No output.';\n\n return {\n content: [{ type: 'text' as const, text: resultText }],\n details: { subagentId: id },\n };\n }\n\n // --- PARALLEL MODE ---\n if (mode === 'parallel') {\n const taskList = params.tasks!;\n\n onUpdate?.({\n content: [\n { type: 'text' as const, text: `Spawning ${taskList.length} parallel subagents...` },\n ],\n });\n\n // Spawn all tasks\n const spawnedIds: string[] = [];\n for (const t of taskList) {\n const id = service.spawn(t.agent, t.task, {\n description: t.task.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n spawnedIds.push(id);\n\n // Record each handoff\n const updatedState = recordHandoff(state, 'orchestrator', t.agent, t.task);\n Object.assign(state, updatedState);\n }\n pi.appendEntry('maestria_state', state);\n\n // Poll all concurrently\n const records = await Promise.all(\n spawnedIds.map((id, i) =>\n pollSubagent(id, `${taskList[i].agent} (${i + 1}/${taskList.length})`, false),\n ),\n );\n\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `All ${taskList.length} parallel subagents completed.`,\n },\n ],\n });\n\n // Aggregate results\n const parts = [`## Parallel Results (${taskList.length} tasks)\\n`];\n for (let i = 0; i < taskList.length; i++) {\n const t = taskList[i];\n const rec = records[i];\n const resultText = rec.result ?? rec.error ?? 'No output.';\n parts.push(`### ${i + 1}: ${t.agent}`);\n parts.push(resultText);\n }\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n\\n') }],\n details: { subagentIds: spawnedIds },\n };\n }\n\n // --- CHAIN MODE ---\n if (mode === 'chain') {\n const taskList = params.tasks!;\n let previousResult = '';\n\n for (let i = 0; i < taskList.length; i++) {\n const t = taskList[i];\n let taskText = t.task;\n\n // Substitute {previous} placeholder with previous result\n if (i > 0 && taskText.includes('{previous}')) {\n taskText = taskText.replace(/\\{previous\\}/g, previousResult);\n }\n\n const id = service.spawn(t.agent, taskText, {\n description: taskText.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n\n // Record handoff\n const updatedState = recordHandoff(state, 'orchestrator', t.agent, taskText);\n Object.assign(state, updatedState);\n pi.appendEntry('maestria_state', state);\n\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `Chain step ${i + 1}/${taskList.length}: ${t.agent} running...`,\n },\n ],\n });\n\n // Poll for completion\n const record = await pollSubagent(id, `Chain step ${i + 1}: ${t.agent}`, true);\n\n previousResult = record.result ?? record.error ?? 'No output.';\n\n if (i < taskList.length - 1) {\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `Chain step ${i + 1}/${taskList.length}: ${t.agent} completed. Moving to next step.`,\n },\n ],\n });\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: previousResult }],\n details: { subagentId: 'chain-completed' },\n };\n }\n\n // Should not reach here - all modes are handled above\n throw new Error('Unknown dispatch mode');\n } catch (err) {\n console.warn('[maestria] Subagent dispatch failed:', err);\n // Return handoff payload as structured text when dispatch fails\n const agentName = params.agent ?? params.tasks?.[0]?.agent ?? 'unknown';\n const taskDesc = params.task ?? params.tasks?.map((t) => t.task).join('; ') ?? 'unknown';\n const handoffInfo = [\n `## Subagent Handoff Required`,\n ``,\n `**From:** orchestrator`,\n `**To:** ${agentName}`,\n `**Task:** ${taskDesc}`,\n ``,\n `Subagent dispatch failed. Please delegate this work manually.`,\n ].join('\\n');\n\n return {\n content: [{ type: 'text' as const, text: handoffInfo }],\n };\n }\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any); // TypeBox inferred types don't match ToolDefinition exactly\n\n // Subscribe to subagent lifecycle events for accurate state tracking.\n // These subscriptions are set up once at extension init, not on every tool call.\n // pi.events is the shared EventBus - distinct from pi.on() lifecycle hooks.\n if (pi.events) {\n const unsubStarted = pi.events.on(SUBAGENT_EVENTS.STARTED, (data: unknown) => {\n const { id, type } = data as { id: string; type: string };\n state.subagentStatus[id] = { type, status: 'running', startedAt: Date.now() };\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_STARTED, {\n id,\n type,\n timestamp: Date.now(),\n });\n });\n\n const unsubCompleted = pi.events.on(SUBAGENT_EVENTS.COMPLETED, (data: unknown) => {\n const { id } = data as { id: string };\n const existing = state.subagentStatus[id];\n if (existing) {\n existing.status = 'completed';\n existing.completedAt = Date.now();\n }\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_COMPLETED, {\n id,\n type: existing?.type,\n timestamp: Date.now(),\n });\n });\n\n const unsubFailed = pi.events.on(SUBAGENT_EVENTS.FAILED, (data: unknown) => {\n const { id, status } = data as { id: string; status: string };\n const existing = state.subagentStatus[id];\n if (existing) {\n existing.status = status ?? 'error';\n existing.completedAt = Date.now();\n }\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_FAILED, {\n id,\n type: existing?.type,\n timestamp: Date.now(),\n });\n });\n\n const unsubSteered = pi.events.on(SUBAGENT_EVENTS.STEERED, (data: unknown) => {\n // Steering is informational - no status transition, but ensure\n // the agent is tracked as running if it wasn't already observed.\n const { id } = data as { id: string };\n if (!state.subagentStatus[id]) {\n state.subagentStatus[id] = { type: 'unknown', status: 'running', startedAt: Date.now() };\n }\n persistState(pi, state);\n });\n\n if (cleanups) {\n cleanups.push(unsubStarted, unsubCompleted, unsubFailed, unsubSteered);\n }\n }\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport {\n cycleToReviewModel,\n persistState,\n renderMaestriaSummary,\n restoreOriginalState,\n} from '@/state.js';\nimport { MAESTRIA_EVENTS } from '@/subagent.js';\n\n/**\n * Read-only tools that let a reviewer inspect code without making changes.\n *\n * - `read`, `grep`, `find`, `ls`, `glob` - all non-destructive.\n * - Excluded: `bash`, `edit`, `write` - these can modify the filesystem.\n *\n * `glob` is included for file pattern matching even though it's not a\n * built-in Pi tool - extensions may register it, and including it is a no-op\n * if absent.\n */\nconst READ_ONLY_TOOLS = ['read', 'grep', 'find', 'ls', 'glob'];\n\nexport function installCommands(pi: ExtensionAPI, state: MaestriaState): void {\n pi.registerCommand('orchestrate', {\n description: 'Start a full pipeline by delegating to the orchestrator',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /orchestrate <goal> - describe what to accomplish');\n return;\n }\n\n // Exit review mode if active (restore original model/tools)\n if (state.reviewMode) {\n const prevOriginalModel = state.originalModel;\n await restoreOriginalState(pi, ctx, state);\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_DEACTIVATED, {\n originalModel: prevOriginalModel,\n source: 'orchestrate',\n timestamp: Date.now(),\n });\n }\n\n pi.sendUserMessage(\n [\n `[ORCHESTRATE: ${args}]`,\n '',\n `Orchestrate the full maestria pipeline to: ${args}`,\n 'Use the orchestrator prompt template for subagent delegation.',\n ].join('\\n'),\n { deliverAs: 'steer' },\n );\n },\n });\n\n pi.registerCommand('maestria-status', {\n description: 'Show current maestria session state including handoff history',\n handler: async (_args: string, ctx) => {\n const summary = renderMaestriaSummary(state);\n if (!summary) {\n ctx.ui.notify('No active maestria state to report.');\n return;\n }\n ctx.ui.setEditorText(summary);\n },\n });\n\n pi.registerCommand('review', {\n description: 'Enter review mode. Blocks destructive tools, sets read-only toolset.',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /review <target> - describe what to review');\n return;\n }\n\n // 1. Save current model and tools for later restoration\n const currentModelId = ctx.model?.id ?? null;\n const currentTools = pi.getActiveTools();\n\n // 2. Update state: mark review mode, store originals\n const updatedState: MaestriaState = {\n ...state,\n reviewMode: true,\n originalModel: currentModelId,\n originalTools: currentTools,\n };\n Object.assign(state, updatedState);\n persistState(pi, state);\n\n // 3. Switch to review model if configured\n if (state.reviewModel) {\n const switched = await cycleToReviewModel(pi, ctx, state);\n if (switched) {\n ctx.ui.notify(`Review mode: switched to ${switched}`);\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_ACTIVATED, {\n originalModel: state.originalModel,\n reviewModel: switched,\n timestamp: Date.now(),\n });\n }\n }\n\n // 4. Restrict to read-only tools\n pi.setActiveTools(READ_ONLY_TOOLS);\n\n pi.sendUserMessage(\n [\n `[REVIEW: ${args}]`,\n '',\n `Review: ${args}. Use the reviewer prompt template.`,\n 'Read only, no edits, report findings.',\n ].join('\\n'),\n { deliverAs: 'steer' },\n );\n },\n });\n\n pi.registerCommand('restore-model', {\n description:\n 'Restore the original model and tools that were active before review mode was entered.',\n handler: async (_args: string, ctx) => {\n if (!state.reviewMode) {\n ctx.ui.notify('Not in review mode. Nothing to restore.');\n return;\n }\n const prevOriginalModel = state.originalModel;\n await restoreOriginalState(pi, ctx, state);\n persistState(pi, state);\n ctx.ui.notify('Restored original model and tools.');\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_DEACTIVATED, {\n originalModel: prevOriginalModel,\n timestamp: Date.now(),\n });\n },\n });\n\n pi.registerCommand('handoff', {\n description: 'Generate a structured handoff prompt for a new task context',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /handoff <goal> - describe the task context for handoff');\n return;\n }\n\n // Build a structured handoff document with 6 fields\n const goal = args.trim();\n const handoffPrompt = [\n '**Goal:** ' + goal,\n '',\n '**Context:**',\n '- Mode: ' + (state.mode ?? 'none'),\n '- Active task: ' + (state.activeTask || 'none'),\n '- Specialists delegated: ' +\n ((state.specialistsDelegated?.length ?? 0) > 0\n ? state.specialistsDelegated.join(', ')\n : 'none'),\n '- Recent handoffs: ' + (state.handoffHistory?.length ?? 0) + ' entries',\n '- Files modified: ' +\n ((state.filesModified?.length ?? 0) > 0 ? state.filesModified.join(', ') : 'none'),\n '',\n '**Requirements:**',\n '(fill in specific requirements)',\n '',\n '**Known problems:**',\n (state.blockers?.length ?? 0) > 0\n ? state.blockers.map((b: string) => '- ' + b).join('\\n')\n : '(no known problems documented)',\n '',\n '**Success criteria:**',\n '(fill in how to verify completion)',\n '',\n '**Next step:**',\n '(fill in what happens after this task)',\n '',\n '---',\n 'Complete the fields above before sending.',\n ].join('\\n');\n\n // Record in state\n state.handoffHistory = [\n { from: 'current', to: 'next', task: goal, timestamp: Date.now() },\n ...(state.handoffHistory ?? []),\n ].slice(0, 5);\n\n // Persist state\n persistState(pi, state);\n\n // Send as user message with steer delivery\n pi.sendUserMessage(handoffPrompt, { deliverAs: 'steer' });\n },\n });\n\n pi.registerCommand('review-model', {\n description: 'Set which model to use when entering review mode',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /review-model <model-id>');\n return;\n }\n const modelId = args.trim();\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m) => m.id === modelId);\n if (!model) {\n ctx.ui.notify(\n `Unknown model: \"${modelId}\". Available: ${models.map((m) => m.id).join(', ')}`,\n );\n return;\n }\n state.reviewModel = modelId;\n persistState(pi, state);\n ctx.ui.notify(`Review model set to: ${modelId}`);\n },\n });\n}\n","import {\n isToolCallEventType,\n type ExtensionAPI,\n type ToolCallEvent,\n type ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\n\nconst DANGEROUS_PATTERNS = [\n /rm\\s+-rf\\s+\\//,\n /dd\\s+if=/,\n />\\s*\\/dev\\/sd/,\n /chmod\\s+-R\\s+777\\s+\\//,\n /mkfs\\.\\w+/,\n /:(){ :\\|:& };:/, // fork bomb\n />\\s*\\/etc\\/(passwd|shadow|sudoers)/,\n /\\beval\\b/,\n /wget\\s+-O\\s*-\\s*\\|\\s*(bash|sh)/,\n /curl\\s+.*\\|\\s*(bash|sh)/,\n /crontab\\s+-r/,\n];\n\nexport function installToolInterceptors(pi: ExtensionAPI, state: MaestriaState): void {\n pi.on('tool_call', async (event: ToolCallEvent, ctx: ExtensionContext) => {\n if (!event || !event.toolName) return;\n\n // Block destructive tools in review mode\n if (state.reviewMode) {\n if (\n isToolCallEventType('edit', event) ||\n isToolCallEventType('write', event) ||\n isToolCallEventType('bash', event)\n ) {\n return {\n block: true,\n reason: 'Review mode is active. Report findings, do not edit.',\n };\n }\n }\n\n // Block dangerous bash patterns regardless of mode\n if (isToolCallEventType('bash', event)) {\n if (!event.input || typeof event.input !== 'object') return undefined;\n const command = event.input.command;\n if (command) {\n for (const pattern of DANGEROUS_PATTERNS) {\n if (pattern.test(command)) {\n if (ctx.hasUI) {\n const confirmed = await ctx.ui.confirm(\n 'Dangerous Pattern Detected',\n `This command matches a dangerous pattern:\\n${command}\\nProceed?`,\n );\n if (confirmed) return undefined;\n }\n return {\n block: true,\n reason: `Command matches dangerous pattern: ${pattern}`,\n };\n }\n }\n }\n }\n\n return undefined; // allow\n });\n}\n","import type { ExtensionAPI, SessionStartEvent } from '@earendil-works/pi-coding-agent';\nimport { createInitialState } from '@/state.js';\nimport { installModeCommands } from '@/modes.js';\nimport { createBeforeAgentStartHandler } from '@/rules.js';\nimport { installCompactionHandlers } from '@/compaction.js';\nimport { installSubagentTool } from '@/subagent.js';\nimport { installCommands } from '@/commands.js';\nimport { installToolInterceptors } from '@/tools.js';\n\nexport default function (pi: ExtensionAPI): void {\n const state = createInitialState();\n const cleanups: Array<() => void> = [];\n\n // Install mode commands: /fein, /sonar, /blitz\n installModeCommands(pi, state);\n\n // Inject mode prompts when a mode is active\n const handleBeforeAgentStart = createBeforeAgentStartHandler(state);\n\n pi.on('before_agent_start', (event, ctx) => {\n return handleBeforeAgentStart(event, ctx);\n });\n\n // Restore persisted state on session start (reload/resume/fork)\n pi.on('session_start', (_event: SessionStartEvent, ctx) => {\n if (!ctx.sessionManager?.getEntries) return;\n const entries = ctx.sessionManager.getEntries();\n // Walk from newest to oldest, find the last persisted maestria_state entry\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i];\n if (entry.type === 'custom' && entry.customType === 'maestria_state') {\n const data = entry.data;\n if (data && typeof data === 'object') {\n Object.assign(state, data);\n }\n break;\n }\n }\n });\n\n // Install compaction preservation handlers\n installCompactionHandlers(pi, state);\n\n // Install orchestration hooks: subagent tool and commands\n installSubagentTool(pi, state, cleanups);\n installCommands(pi, state);\n\n // Cleanup subscriptions on shutdown\n pi.on('session_shutdown', () => {\n for (const cleanup of cleanups) cleanup();\n cleanups.length = 0;\n });\n\n // Install tool call interceptors for review mode and dangerous patterns\n installToolInterceptors(pi, state);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../src/state.ts","../src/agents.ts","../src/modes.ts","../src/rules.ts","../src/compaction.ts","../src/subagent.ts","../src/commands.ts","../src/tools.ts","../src/extension.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionCommandContext } from '@earendil-works/pi-coding-agent';\nimport type { ModeKeyword } from '@/modes.js';\n\nconst HANDOFF_HISTORY_CAP = 5;\nconst FILE_HISTORY_CAP = 10;\n\nexport interface HandoffEntry {\n from: string;\n to: string;\n task: string;\n timestamp: number;\n}\n\nexport interface SubagentStatusInfo {\n type: string;\n status: string;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface MaestriaState {\n mode: ModeKeyword | null;\n activeTask: string;\n completionPromise: string;\n specialistsDelegated: string[];\n blockers: string[];\n filesModified: string[];\n filesRead: string[];\n handoffHistory: HandoffEntry[];\n reviewMode: boolean;\n originalModel: string | null;\n originalTools: string[] | null;\n subagentStatus: Record<string, SubagentStatusInfo>;\n /** Model ID to use when entering review mode. Null = no preference. */\n reviewModel: string | null;\n}\n\nexport function createInitialState(): MaestriaState {\n return {\n mode: null,\n activeTask: '',\n completionPromise: '',\n specialistsDelegated: [],\n blockers: [],\n filesModified: [],\n filesRead: [],\n handoffHistory: [],\n reviewMode: false,\n originalModel: null,\n originalTools: null,\n subagentStatus: {},\n reviewModel: null,\n };\n}\n\nexport function recordHandoff(\n state: MaestriaState,\n from: string,\n to: string,\n task: string,\n): MaestriaState {\n const entry: HandoffEntry = { from, to, task, timestamp: Date.now() };\n const history = [entry, ...state.handoffHistory].slice(0, HANDOFF_HISTORY_CAP);\n return { ...state, handoffHistory: history };\n}\n\nfunction prependDeduped(files: string[], path: string, cap: number): string[] {\n const filtered = files.filter((f) => f !== path);\n return [path, ...filtered].slice(0, cap);\n}\n\nexport function recordFileModified(state: MaestriaState, path: string): MaestriaState {\n return { ...state, filesModified: prependDeduped(state.filesModified, path, FILE_HISTORY_CAP) };\n}\n\nexport function recordFileRead(state: MaestriaState, path: string): MaestriaState {\n return { ...state, filesRead: prependDeduped(state.filesRead, path, FILE_HISTORY_CAP) };\n}\n\nexport function recordSubagentStatus(\n state: MaestriaState,\n id: string,\n info: SubagentStatusInfo,\n): MaestriaState {\n return { ...state, subagentStatus: { ...state.subagentStatus, [id]: info } };\n}\n\nexport function setReviewMode(state: MaestriaState, active: boolean): MaestriaState {\n return {\n ...state,\n reviewMode: active,\n };\n}\n\n/**\n * Exit review mode and return the original model/tools for restoration.\n * Returns a new state (immutable) with review mode cleared and the\n * saved originals so the caller can pass them to pi.setModel/setActiveTools.\n */\nexport function exitReviewMode(state: MaestriaState): {\n state: MaestriaState;\n originalModel: string | null;\n originalTools: string[] | null;\n} {\n return {\n state: {\n ...state,\n reviewMode: false,\n originalModel: null,\n originalTools: null,\n },\n originalModel: state.originalModel,\n originalTools: state.originalTools,\n };\n}\n\n/**\n * Restore the original model and tools saved when review mode was entered.\n * Clears review mode from state and resets pi to the pre-review configuration.\n */\nexport async function restoreOriginalState(\n pi: ExtensionAPI,\n ctx: ExtensionCommandContext,\n state: MaestriaState,\n): Promise<void> {\n const { state: clearedState, originalModel, originalTools } = exitReviewMode(state);\n\n // Restore original tools first (makes full toolset available again)\n if (originalTools && originalTools.length > 0) {\n pi.setActiveTools(originalTools);\n }\n\n // Restore original model - best-effort, failures are non-fatal\n if (originalModel) {\n try {\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m: { id: string }) => m.id === originalModel);\n if (model) {\n await pi.setModel(model);\n }\n } catch {\n // Best-effort: model restoration is non-critical\n }\n }\n\n // Clear review mode state\n Object.assign(state, clearedState);\n}\n\n/**\n * Persist the current state to the session by appending a custom entry.\n * Creates a shallow copy to ensure appendEntry sees the latest snapshot.\n */\nexport function persistState(pi: ExtensionAPI, state: MaestriaState): void {\n pi.appendEntry('maestria_state', { ...state });\n}\n\n/**\n * If a review model is configured, switch to it.\n * Returns the model ID switched to, or null if no switch occurred.\n */\nexport async function cycleToReviewModel(\n pi: ExtensionAPI,\n ctx: ExtensionCommandContext,\n state: MaestriaState,\n): Promise<string | null> {\n const reviewModel = state.reviewModel;\n if (!reviewModel) {\n return null;\n }\n try {\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m) => m.id === reviewModel);\n if (model) {\n await pi.setModel(model);\n return reviewModel;\n } else {\n ctx.ui.notify(`Review model \"${reviewModel}\" not found in registry, staying on current.`);\n return null;\n }\n } catch {\n ctx.ui.notify(`Could not switch to review model \"${reviewModel}\", staying on current.`);\n return null;\n }\n}\n\nexport function renderMaestriaSummary(state: MaestriaState): string {\n const parts: string[] = [];\n\n if (state.mode) {\n parts.push(`**Mode:** ${state.mode.toUpperCase()}`);\n }\n\n if (state.reviewModel) {\n parts.push(`**Review Model:** ${state.reviewModel}`);\n }\n\n if (state.activeTask) {\n parts.push(`**Goal:** ${state.activeTask}`);\n }\n\n if (state.completionPromise) {\n parts.push(`**Completion Promise:** ${state.completionPromise}`);\n }\n\n if (state.specialistsDelegated.length > 0) {\n parts.push(`**Specialists Delegated:** ${state.specialistsDelegated.join(', ')}`);\n }\n\n if (state.blockers.length > 0) {\n parts.push('**Blockers:**');\n for (const blocker of state.blockers) {\n parts.push(`- ${blocker}`);\n }\n }\n\n const fileSubs: string[] = [];\n if (state.filesModified.length > 0) {\n fileSubs.push(`**Modified:** ${state.filesModified.join(', ')}`);\n }\n if (state.filesRead.length > 0) {\n fileSubs.push(`**Read:** ${state.filesRead.join(', ')}`);\n }\n if (fileSubs.length > 0) {\n parts.push(`**Files:** ${fileSubs.join('; ')}`);\n }\n\n if (state.handoffHistory.length > 0) {\n parts.push('**Recent Handoffs:**');\n for (const entry of state.handoffHistory) {\n parts.push(`- ${entry.from} → ${entry.to}: ${entry.task}`);\n }\n }\n\n return parts.join('\\n\\n');\n}\n\nexport { HANDOFF_HISTORY_CAP, FILE_HISTORY_CAP };\n","import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { homedir } from 'node:os';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/** Source directory for bundled specialist agent files (synced from canonical) */\nconst AGENTS_SRC = join(__dirname, '..', 'agents');\n\n/** Destination directory where pi-subagents discovers agent types */\nconst AGENTS_DEST = join(homedir(), '.pi', 'agent', 'agents');\n\nconst SPECIALIST_NAMES = [\n 'adventurer',\n 'architect',\n 'builder',\n 'diagnose',\n 'planner',\n 'reviewer',\n 'writer',\n] as const;\n\n/**\n * Deploy bundled specialist agent .md files to the pi-subagents agents directory.\n *\n * pi-subagents discovers agent types from ~/.pi/agent/agents/*.md on every\n * registry.reload() call (which fires automatically on each tool invocation).\n * This function ensures the files are in place before the first subagent dispatch.\n *\n * Only creates files that don't already exist - never overwrites user-customized agents.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function deploySpecialistAgents(_ctx?: ExtensionContext): void {\n const srcDir = AGENTS_SRC;\n\n if (!existsSync(srcDir)) {\n console.warn('[maestria] Agents source directory not found:', srcDir);\n return;\n }\n\n // Ensure destination directory exists\n try {\n mkdirSync(AGENTS_DEST, { recursive: true });\n } catch {\n console.warn('[maestria] Could not create agents directory:', AGENTS_DEST);\n return;\n }\n\n let deployed = 0;\n for (const name of SPECIALIST_NAMES) {\n const srcFile = join(srcDir, `${name}.md`);\n const destFile = join(AGENTS_DEST, `${name}.md`);\n\n if (!existsSync(srcFile)) {\n console.warn(`[maestria] Agent source not found: ${name}.md`);\n continue;\n }\n\n // Never overwrite existing files - user may have customized them\n if (existsSync(destFile)) continue;\n\n try {\n const content = readFileSync(srcFile, 'utf-8');\n writeFileSync(destFile, content, 'utf-8');\n deployed++;\n } catch (err) {\n console.warn(`[maestria] Failed to deploy agent ${name}:`, err);\n }\n }\n\n if (deployed > 0) {\n console.log(`[maestria] Deployed ${deployed} specialist agents to ${AGENTS_DEST}`);\n }\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { persistState, restoreOriginalState } from '@/state.js';\n\nexport const MODE_KEYWORDS = ['fein', 'sonar', 'blitz'] as const;\nexport type ModeKeyword = (typeof MODE_KEYWORDS)[number];\n\nconst MODE_PROMPTS: Record<ModeKeyword, string> = {\n fein: [\n '## MODE: fein (Full Pipeline)',\n '',\n 'Execute the complete fein pipeline: mandatory reconnaissance',\n '(/adventurer) → design/plan (/architect or /planner) →',\n 'implementation (/builder) → review (/reviewer).',\n 'Do NOT skip any phase unless the user explicitly overrides',\n 'in the same turn.',\n ].join('\\n'),\n sonar: [\n '## MODE: sonar (Research Only)',\n '',\n 'Execute research only: /adventurer (recon) →',\n '/architect or /planner (design/plan) → STOP.',\n 'Do NOT implement anything. Return findings.',\n ].join('\\n'),\n blitz: [\n '## MODE: blitz (Fast Implementation)',\n '',\n 'Execute fast implementation via /builder directly.',\n 'Skip reconnaissance and design unless the codebase',\n 'is genuinely unknown. Skip review unless the result',\n 'needs validation.',\n ].join('\\n'),\n};\n\nconst MODE_MARKERS: Record<ModeKeyword, string> = {\n fein: '[MODE: fein]',\n sonar: '[MODE: sonar]',\n blitz: '[MODE: blitz]',\n};\n\nexport function getModePrompt(keyword: ModeKeyword): string {\n return `${MODE_MARKERS[keyword]}\\n\\n${MODE_PROMPTS[keyword]}`;\n}\n\nexport function installModeCommands(pi: ExtensionAPI, state: MaestriaState): void {\n for (const keyword of MODE_KEYWORDS) {\n pi.registerCommand(keyword, {\n description: `Set workflow mode to ${keyword}`,\n handler: async (args, ctx) => {\n // Exit review mode if active (restore original model/tools)\n if (state.reviewMode) {\n await restoreOriginalState(pi, ctx, state);\n }\n\n state.mode = keyword;\n persistState(pi, state);\n\n if (args.trim()) {\n const modeMessage = [\n getModePrompt(keyword),\n '',\n `Run the maestria default pipeline on: ${args}`,\n ].join('\\n');\n pi.sendUserMessage(modeMessage, { deliverAs: 'steer' });\n } else {\n ctx.ui.notify(`Mode set to ${keyword}. Describe what you'd like to work on.`);\n }\n },\n });\n }\n}\n","import type {\n BeforeAgentStartEvent,\n BeforeAgentStartEventResult,\n ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { getModePrompt } from '@/modes.js';\n\n/**\n * Creates a before_agent_start handler that injects workflow mode prompts.\n *\n * This is the only dynamic prompt injection needed from the extension.\n * Static behavioral content (orchestrator prompt + global rules) is\n * auto-injected by Pi's skill system via SKILL.md files registered in\n * the pi.skills manifest field - the standard Pi extension pattern.\n *\n * When no mode is active, the handler returns void (no modification),\n * letting Pi's built-in prompt assembly (skills + context files + tools)\n * stand as-is.\n */\nexport function createModePromptHandler(state: MaestriaState) {\n return (\n event: BeforeAgentStartEvent,\n _ctx: ExtensionContext,\n ): BeforeAgentStartEventResult | void => {\n if (!state.mode) return;\n\n const parts: string[] = [\n event.systemPrompt,\n '',\n getModePrompt(state.mode),\n '',\n `The user has set workflow mode to \"${state.mode}\". ` +\n 'Honor this mode throughout the session until changed via /command.',\n ];\n\n return { systemPrompt: parts.join('\\n') };\n };\n}\n","import type {\n ExtensionAPI,\n SessionBeforeCompactEvent,\n SessionBeforeTreeEvent,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport { renderMaestriaSummary } from '@/state.js';\n\nexport function installCompactionHandlers(pi: ExtensionAPI, state: MaestriaState): void {\n pi.on('session_before_compact', (event: SessionBeforeCompactEvent) => {\n return {\n compaction: {\n summary: renderMaestriaSummary(state),\n details: { ...state },\n firstKeptEntryId: event.preparation.firstKeptEntryId,\n tokensBefore: event.preparation.tokensBefore,\n },\n };\n });\n\n pi.on('session_before_tree', (event: SessionBeforeTreeEvent) => {\n if (event.preparation.userWantsSummary) {\n return {\n summary: {\n summary: renderMaestriaSummary(state),\n },\n };\n }\n return undefined;\n });\n}\n","import { Type } from 'typebox';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { SUBAGENT_EVENTS } from '@gotgenes/pi-subagents';\nimport type { MaestriaState } from '@/state.js';\nimport { persistState, recordHandoff } from '@/state.js';\n\n/**\n * Maestria cross-extension event names.\n * Other Pi extensions can subscribe via `pi.events?.on(...)`.\n * Convention: `maestria:<domain>:<action>`\n */\nexport const MAESTRIA_EVENTS = {\n REVIEW_ACTIVATED: 'maestria:review:activated',\n REVIEW_DEACTIVATED: 'maestria:review:deactivated',\n SUBAGENT_STARTED: 'maestria:subagent:started',\n SUBAGENT_COMPLETED: 'maestria:subagent:completed',\n SUBAGENT_FAILED: 'maestria:subagent:failed',\n} as const;\n\nconst ALLOWED_AGENTS = [\n 'adventurer',\n 'architect',\n 'builder',\n 'diagnose',\n 'planner',\n 'reviewer',\n 'writer',\n] as const;\ntype AllowedAgent = (typeof ALLOWED_AGENTS)[number];\n\n// The 6-field handoff contract\nconst HANDOFF_FIELDS = [\n 'Goal',\n 'Context',\n 'Requirements',\n 'Known problems',\n 'Success criteria',\n 'Next step',\n] as const;\n\n/** Terminal subagent statuses - agent will produce no more updates. */\nconst TERMINAL_STATUSES = new Set(['completed', 'steered', 'aborted', 'stopped', 'error']);\n\n/** Maximum time to wait for a subagent to complete, in milliseconds. */\nexport const POLL_TIMEOUT_MS = 60_000;\n\n/** Interval between subagent status checks, in milliseconds. */\nexport const POLL_INTERVAL_MS = 500;\n\n/** Maximum number of tasks allowed in parallel dispatch. */\nexport const MAX_PARALLEL_TASKS = 8;\n\nexport function validateHandoff(handoff: string): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n for (const field of HANDOFF_FIELDS) {\n const regex = new RegExp(`\\\\*\\\\*${field}:\\\\*\\\\*[\\\\s\\\\S]*?\\\\S`, 'i');\n if (!regex.test(handoff)) {\n errors.push(`Missing or empty field: \"${field}\"`);\n }\n }\n return { valid: errors.length === 0, errors };\n}\n\nexport function installSubagentTool(\n pi: ExtensionAPI,\n state: MaestriaState,\n cleanups?: Array<() => void>,\n): void {\n pi.registerTool({\n name: 'maestria_subagent',\n label: 'Maestria Subagent',\n description: 'Dispatch a task to a @maestria specialist subagent',\n promptSnippet:\n 'Delegate tasks to @maestria specialist subagents (adventurer, architect, builder, planner, diagnose, reviewer, writer)',\n promptGuidelines: [\n 'Use maestria_subagent when a task MUST be delegated to a specialist subagent rather than handled directly. Each specialist has focused capabilities: adventurer (recon), architect (design), builder (impl), planner (planning), diagnose (bugs), reviewer (QA), writer (docs).',\n ],\n prepareArguments(args: unknown) {\n return args;\n },\n parameters: Type.Object({\n agent: Type.Optional(Type.String({ description: 'Specialist agent name' })),\n task: Type.Optional(Type.String({ description: 'Task description for the subagent' })),\n tasks: Type.Optional(\n Type.Array(\n Type.Object({\n agent: Type.String(),\n task: Type.String(),\n }),\n { description: 'Array of task objects for parallel or chain dispatch' },\n ),\n ),\n mode: Type.Optional(\n Type.Union([Type.Literal('parallel'), Type.Literal('chain'), Type.Literal('single')]),\n ),\n }),\n async execute(\n _toolCallId: string,\n params: {\n agent?: string;\n task?: string;\n tasks?: Array<{ agent: string; task: string }>;\n mode?: 'parallel' | 'chain' | 'single';\n },\n signal: AbortSignal | undefined,\n onUpdate: ((result: { content: Array<{ type: string; text: string }> }) => void) | undefined,\n _ctx: ExtensionContext,\n ) {\n // Block subagent dispatch when in review mode\n if (state.reviewMode) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Subagent dispatch is not available during review mode. Use /restore-model to exit review mode first.',\n },\n ],\n };\n }\n\n // Determine dispatch mode (default to 'single' for backward compat)\n const mode = params.mode ?? 'single';\n\n // Validate parameters based on mode\n if (mode === 'single') {\n // Backward-compatible validation - must match original error messages exactly\n if (!ALLOWED_AGENTS.includes(params.agent as AllowedAgent)) {\n throw new Error(\n `Unknown agent: \"${params.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`,\n );\n }\n if (!params.task || !params.task.trim()) {\n throw new Error('Task description is required');\n }\n } else if (mode === 'parallel') {\n if (!params.tasks || params.tasks.length < 2) {\n throw new Error(`For parallel mode, tasks array is required with at least 2 items`);\n }\n if (params.tasks.length > MAX_PARALLEL_TASKS) {\n throw new Error(\n `For parallel mode, tasks array may have at most ${MAX_PARALLEL_TASKS} items (got ${params.tasks.length})`,\n );\n }\n for (const t of params.tasks) {\n if (!ALLOWED_AGENTS.includes(t.agent as AllowedAgent)) {\n throw new Error(`Unknown agent: \"${t.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`);\n }\n if (!t.task || !t.task.trim()) {\n throw new Error('Task description is required for all tasks');\n }\n }\n } else if (mode === 'chain') {\n if (!params.tasks || params.tasks.length < 2) {\n throw new Error('For chain mode, tasks array is required with at least 2 items');\n }\n for (const t of params.tasks) {\n if (!ALLOWED_AGENTS.includes(t.agent as AllowedAgent)) {\n throw new Error(`Unknown agent: \"${t.agent}\". Allowed: ${ALLOWED_AGENTS.join(', ')}`);\n }\n if (!t.task || !t.task.trim()) {\n throw new Error('Task description is required for all tasks');\n }\n }\n }\n\n // Attempt to dispatch via @gotgenes/pi-subagents; handle missing service\n const { getSubagentsService } = await import('@gotgenes/pi-subagents');\n const service = getSubagentsService();\n if (!service || typeof service.spawn !== 'function') {\n return {\n content: [\n {\n type: 'text' as const,\n text: [\n '## Subagent Dispatch Unavailable',\n '',\n 'The `@gotgenes/pi-subagents` extension is required for subagent dispatch but has not been loaded.',\n '',\n 'Install it as a Pi extension:',\n '',\n '```',\n 'pi install npm:@gotgenes/pi-subagents',\n '```',\n '',\n 'Then restart your Pi session.',\n ].join('\\n'),\n },\n ],\n };\n }\n\n try {\n // Helper: poll a single subagent until terminal or timeout\n async function pollSubagent(\n id: string,\n label: string,\n sendUpdates: boolean,\n ): Promise<{ status: string; result?: string; error?: string }> {\n const maxPolls = POLL_TIMEOUT_MS / POLL_INTERVAL_MS;\n let polls = 0;\n let record = service!.getRecord(id);\n while (record && !TERMINAL_STATUSES.has(record.status) && polls < maxPolls) {\n if (signal?.aborted) throw new Error('Maestria subagent call aborted');\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n record = service!.getRecord(id);\n polls++;\n if (sendUpdates) {\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `${label} running... (${Math.round((polls * POLL_INTERVAL_MS) / 1000)}s)`,\n },\n ],\n });\n }\n }\n if (record && !TERMINAL_STATUSES.has(record.status)) {\n throw new Error(`Subagent ${id} timed out after ${POLL_TIMEOUT_MS}ms`);\n }\n if (!record) {\n throw new Error(`Subagent ${id} was cleaned up before completion`);\n }\n return record;\n }\n\n // --- SINGLE MODE ---\n if (mode === 'single') {\n const agent = params.agent!;\n const task = params.task!;\n\n // Spawn in foreground - returns subagent ID synchronously\n const id = service.spawn(agent, task, {\n description: task.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n\n // Record handoff in state and persist (only after spawn succeeds)\n const updatedState = recordHandoff(state, 'orchestrator', agent, task);\n Object.assign(state, updatedState);\n pi.appendEntry('maestria_state', state);\n\n // Poll for completion\n const record = await pollSubagent(id, `Subagent ${agent}`, true);\n\n const resultText = record.result ?? record.error ?? 'No output.';\n\n return {\n content: [{ type: 'text' as const, text: resultText }],\n details: { subagentId: id },\n };\n }\n\n // --- PARALLEL MODE ---\n if (mode === 'parallel') {\n const taskList = params.tasks!;\n\n onUpdate?.({\n content: [\n { type: 'text' as const, text: `Spawning ${taskList.length} parallel subagents...` },\n ],\n });\n\n // Spawn all tasks\n const spawnedIds: string[] = [];\n for (const t of taskList) {\n const id = service.spawn(t.agent, t.task, {\n description: t.task.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n spawnedIds.push(id);\n\n // Record each handoff\n const updatedState = recordHandoff(state, 'orchestrator', t.agent, t.task);\n Object.assign(state, updatedState);\n }\n pi.appendEntry('maestria_state', state);\n\n // Poll all concurrently\n const records = await Promise.all(\n spawnedIds.map((id, i) =>\n pollSubagent(id, `${taskList[i].agent} (${i + 1}/${taskList.length})`, false),\n ),\n );\n\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `All ${taskList.length} parallel subagents completed.`,\n },\n ],\n });\n\n // Aggregate results\n const parts = [`## Parallel Results (${taskList.length} tasks)\\n`];\n for (let i = 0; i < taskList.length; i++) {\n const t = taskList[i];\n const rec = records[i];\n const resultText = rec.result ?? rec.error ?? 'No output.';\n parts.push(`### ${i + 1}: ${t.agent}`);\n parts.push(resultText);\n }\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n\\n') }],\n details: { subagentIds: spawnedIds },\n };\n }\n\n // --- CHAIN MODE ---\n if (mode === 'chain') {\n const taskList = params.tasks!;\n let previousResult = '';\n\n for (let i = 0; i < taskList.length; i++) {\n const t = taskList[i];\n let taskText = t.task;\n\n // Substitute {previous} placeholder with previous result\n if (i > 0 && taskText.includes('{previous}')) {\n taskText = taskText.replace(/\\{previous\\}/g, previousResult);\n }\n\n const id = service.spawn(t.agent, taskText, {\n description: taskText.slice(0, 80),\n foreground: true,\n inheritContext: true,\n });\n\n // Record handoff\n const updatedState = recordHandoff(state, 'orchestrator', t.agent, taskText);\n Object.assign(state, updatedState);\n pi.appendEntry('maestria_state', state);\n\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `Chain step ${i + 1}/${taskList.length}: ${t.agent} running...`,\n },\n ],\n });\n\n // Poll for completion\n const record = await pollSubagent(id, `Chain step ${i + 1}: ${t.agent}`, true);\n\n previousResult = record.result ?? record.error ?? 'No output.';\n\n if (i < taskList.length - 1) {\n onUpdate?.({\n content: [\n {\n type: 'text' as const,\n text: `Chain step ${i + 1}/${taskList.length}: ${t.agent} completed. Moving to next step.`,\n },\n ],\n });\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: previousResult }],\n details: { subagentId: 'chain-completed' },\n };\n }\n\n // Should not reach here - all modes are handled above\n throw new Error('Unknown dispatch mode');\n } catch (err) {\n console.warn('[maestria] Subagent dispatch failed:', err);\n // Return handoff payload as structured text when dispatch fails\n const agentName = params.agent ?? params.tasks?.[0]?.agent ?? 'unknown';\n const taskDesc = params.task ?? params.tasks?.map((t) => t.task).join('; ') ?? 'unknown';\n const handoffInfo = [\n `## Subagent Handoff Required`,\n ``,\n `**From:** orchestrator`,\n `**To:** ${agentName}`,\n `**Task:** ${taskDesc}`,\n ``,\n `Subagent dispatch failed. Please delegate this work manually.`,\n ].join('\\n');\n\n return {\n content: [{ type: 'text' as const, text: handoffInfo }],\n };\n }\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any); // TypeBox inferred types don't match ToolDefinition exactly\n\n // Subscribe to subagent lifecycle events for accurate state tracking.\n // These subscriptions are set up once at extension init, not on every tool call.\n // pi.events is the shared EventBus - distinct from pi.on() lifecycle hooks.\n if (pi.events) {\n const unsubStarted = pi.events.on(SUBAGENT_EVENTS.STARTED, (data: unknown) => {\n const { id, type } = data as { id: string; type: string };\n state.subagentStatus[id] = { type, status: 'running', startedAt: Date.now() };\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_STARTED, {\n id,\n type,\n timestamp: Date.now(),\n });\n });\n\n const unsubCompleted = pi.events.on(SUBAGENT_EVENTS.COMPLETED, (data: unknown) => {\n const { id } = data as { id: string };\n const existing = state.subagentStatus[id];\n if (existing) {\n existing.status = 'completed';\n existing.completedAt = Date.now();\n }\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_COMPLETED, {\n id,\n type: existing?.type,\n timestamp: Date.now(),\n });\n });\n\n const unsubFailed = pi.events.on(SUBAGENT_EVENTS.FAILED, (data: unknown) => {\n const { id, status } = data as { id: string; status: string };\n const existing = state.subagentStatus[id];\n if (existing) {\n existing.status = status ?? 'error';\n existing.completedAt = Date.now();\n }\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.SUBAGENT_FAILED, {\n id,\n type: existing?.type,\n timestamp: Date.now(),\n });\n });\n\n const unsubSteered = pi.events.on(SUBAGENT_EVENTS.STEERED, (data: unknown) => {\n // Steering is informational - no status transition, but ensure\n // the agent is tracked as running if it wasn't already observed.\n const { id } = data as { id: string };\n if (!state.subagentStatus[id]) {\n state.subagentStatus[id] = { type: 'unknown', status: 'running', startedAt: Date.now() };\n }\n persistState(pi, state);\n });\n\n if (cleanups) {\n cleanups.push(unsubStarted, unsubCompleted, unsubFailed, unsubSteered);\n }\n }\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\nimport {\n cycleToReviewModel,\n persistState,\n renderMaestriaSummary,\n restoreOriginalState,\n} from '@/state.js';\nimport { MAESTRIA_EVENTS } from '@/subagent.js';\n\n/**\n * Read-only tools that let a reviewer inspect code without making changes.\n *\n * - `read`, `grep`, `find`, `ls`, `glob` - all non-destructive.\n * - Excluded: `bash`, `edit`, `write` - these can modify the filesystem.\n *\n * `glob` is included for file pattern matching even though it's not a\n * built-in Pi tool - extensions may register it, and including it is a no-op\n * if absent.\n */\nconst READ_ONLY_TOOLS = ['read', 'grep', 'find', 'ls', 'glob'];\n\nexport function installCommands(pi: ExtensionAPI, state: MaestriaState): void {\n pi.registerCommand('orchestrate', {\n description: 'Start a full pipeline by delegating to the orchestrator',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /orchestrate <goal> - describe what to accomplish');\n return;\n }\n\n // Exit review mode if active (restore original model/tools)\n if (state.reviewMode) {\n const prevOriginalModel = state.originalModel;\n await restoreOriginalState(pi, ctx, state);\n persistState(pi, state);\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_DEACTIVATED, {\n originalModel: prevOriginalModel,\n source: 'orchestrate',\n timestamp: Date.now(),\n });\n }\n\n pi.sendUserMessage(\n [\n `[ORCHESTRATE: ${args}]`,\n '',\n `Orchestrate the full maestria pipeline to: ${args}`,\n 'Use the orchestrator prompt template for subagent delegation.',\n ].join('\\n'),\n { deliverAs: 'steer' },\n );\n },\n });\n\n pi.registerCommand('maestria-status', {\n description: 'Show current maestria session state including handoff history',\n handler: async (_args: string, ctx) => {\n const summary = renderMaestriaSummary(state);\n if (!summary) {\n ctx.ui.notify('No active maestria state to report.');\n return;\n }\n ctx.ui.setEditorText(summary);\n },\n });\n\n pi.registerCommand('review', {\n description: 'Enter review mode. Blocks destructive tools, sets read-only toolset.',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /review <target> - describe what to review');\n return;\n }\n\n // 1. Save current model and tools for later restoration\n const currentModelId = ctx.model?.id ?? null;\n const currentTools = pi.getActiveTools();\n\n // 2. Update state: mark review mode, store originals\n const updatedState: MaestriaState = {\n ...state,\n reviewMode: true,\n originalModel: currentModelId,\n originalTools: currentTools,\n };\n Object.assign(state, updatedState);\n persistState(pi, state);\n\n // 3. Switch to review model if configured\n if (state.reviewModel) {\n const switched = await cycleToReviewModel(pi, ctx, state);\n if (switched) {\n ctx.ui.notify(`Review mode: switched to ${switched}`);\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_ACTIVATED, {\n originalModel: state.originalModel,\n reviewModel: switched,\n timestamp: Date.now(),\n });\n }\n }\n\n // 4. Restrict to read-only tools\n pi.setActiveTools(READ_ONLY_TOOLS);\n\n pi.sendUserMessage(\n [\n `[REVIEW: ${args}]`,\n '',\n `Review: ${args}. Use the reviewer prompt template.`,\n 'Read only, no edits, report findings.',\n ].join('\\n'),\n { deliverAs: 'steer' },\n );\n },\n });\n\n pi.registerCommand('restore-model', {\n description:\n 'Restore the original model and tools that were active before review mode was entered.',\n handler: async (_args: string, ctx) => {\n if (!state.reviewMode) {\n ctx.ui.notify('Not in review mode. Nothing to restore.');\n return;\n }\n const prevOriginalModel = state.originalModel;\n await restoreOriginalState(pi, ctx, state);\n persistState(pi, state);\n ctx.ui.notify('Restored original model and tools.');\n pi.events?.emit(MAESTRIA_EVENTS.REVIEW_DEACTIVATED, {\n originalModel: prevOriginalModel,\n timestamp: Date.now(),\n });\n },\n });\n\n pi.registerCommand('handoff', {\n description: 'Generate a structured handoff prompt for a new task context',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /handoff <goal> - describe the task context for handoff');\n return;\n }\n\n // Build a structured handoff document with 6 fields\n const goal = args.trim();\n const handoffPrompt = [\n '**Goal:** ' + goal,\n '',\n '**Context:**',\n '- Mode: ' + (state.mode ?? 'none'),\n '- Active task: ' + (state.activeTask || 'none'),\n '- Specialists delegated: ' +\n ((state.specialistsDelegated?.length ?? 0) > 0\n ? state.specialistsDelegated.join(', ')\n : 'none'),\n '- Recent handoffs: ' + (state.handoffHistory?.length ?? 0) + ' entries',\n '- Files modified: ' +\n ((state.filesModified?.length ?? 0) > 0 ? state.filesModified.join(', ') : 'none'),\n '',\n '**Requirements:**',\n '(fill in specific requirements)',\n '',\n '**Known problems:**',\n (state.blockers?.length ?? 0) > 0\n ? state.blockers.map((b: string) => '- ' + b).join('\\n')\n : '(no known problems documented)',\n '',\n '**Success criteria:**',\n '(fill in how to verify completion)',\n '',\n '**Next step:**',\n '(fill in what happens after this task)',\n '',\n '---',\n 'Complete the fields above before sending.',\n ].join('\\n');\n\n // Record in state\n state.handoffHistory = [\n { from: 'current', to: 'next', task: goal, timestamp: Date.now() },\n ...(state.handoffHistory ?? []),\n ].slice(0, 5);\n\n // Persist state\n persistState(pi, state);\n\n // Send as user message with steer delivery\n pi.sendUserMessage(handoffPrompt, { deliverAs: 'steer' });\n },\n });\n\n pi.registerCommand('review-model', {\n description: 'Set which model to use when entering review mode',\n handler: async (args: string, ctx) => {\n if (!args.trim()) {\n ctx.ui.notify('Usage: /review-model <model-id>');\n return;\n }\n const modelId = args.trim();\n const models = ctx.modelRegistry.getAll();\n const model = models.find((m) => m.id === modelId);\n if (!model) {\n ctx.ui.notify(\n `Unknown model: \"${modelId}\". Available: ${models.map((m) => m.id).join(', ')}`,\n );\n return;\n }\n state.reviewModel = modelId;\n persistState(pi, state);\n ctx.ui.notify(`Review model set to: ${modelId}`);\n },\n });\n}\n","import {\n isToolCallEventType,\n type ExtensionAPI,\n type ToolCallEvent,\n type ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { MaestriaState } from '@/state.js';\n\nconst DANGEROUS_PATTERNS = [\n /rm\\s+-rf\\s+\\//,\n /dd\\s+if=/,\n />\\s*\\/dev\\/sd/,\n /chmod\\s+-R\\s+777\\s+\\//,\n /mkfs\\.\\w+/,\n /:(){ :\\|:& };:/, // fork bomb\n />\\s*\\/etc\\/(passwd|shadow|sudoers)/,\n /\\beval\\b/,\n /wget\\s+-O\\s*-\\s*\\|\\s*(bash|sh)/,\n /curl\\s+.*\\|\\s*(bash|sh)/,\n /crontab\\s+-r/,\n];\n\nexport function installToolInterceptors(pi: ExtensionAPI, state: MaestriaState): void {\n pi.on('tool_call', async (event: ToolCallEvent, ctx: ExtensionContext) => {\n if (!event || !event.toolName) return;\n\n // Block destructive tools in review mode\n if (state.reviewMode) {\n if (\n isToolCallEventType('edit', event) ||\n isToolCallEventType('write', event) ||\n isToolCallEventType('bash', event)\n ) {\n return {\n block: true,\n reason: 'Review mode is active. Report findings, do not edit.',\n };\n }\n }\n\n // Block dangerous bash patterns regardless of mode\n if (isToolCallEventType('bash', event)) {\n if (!event.input || typeof event.input !== 'object') return undefined;\n const command = event.input.command;\n if (command) {\n for (const pattern of DANGEROUS_PATTERNS) {\n if (pattern.test(command)) {\n if (ctx.hasUI) {\n const confirmed = await ctx.ui.confirm(\n 'Dangerous Pattern Detected',\n `This command matches a dangerous pattern:\\n${command}\\nProceed?`,\n );\n if (confirmed) return undefined;\n }\n return {\n block: true,\n reason: `Command matches dangerous pattern: ${pattern}`,\n };\n }\n }\n }\n }\n\n return undefined; // allow\n });\n}\n","import type { ExtensionAPI, SessionStartEvent } from '@earendil-works/pi-coding-agent';\nimport { createInitialState } from '@/state.js';\nimport { deploySpecialistAgents } from '@/agents.js';\nimport { installModeCommands } from '@/modes.js';\nimport { createModePromptHandler } from '@/rules.js';\nimport { installCompactionHandlers } from '@/compaction.js';\nimport { installSubagentTool } from '@/subagent.js';\nimport { installCommands } from '@/commands.js';\nimport { installToolInterceptors } from '@/tools.js';\n\nexport default function (pi: ExtensionAPI): void {\n const state = createInitialState();\n const cleanups: Array<() => void> = [];\n\n // Install mode commands: /fein, /sonar, /blitz\n installModeCommands(pi, state);\n\n // Inject mode prompt when a workflow mode is active\n const handleModePrompt = createModePromptHandler(state);\n\n pi.on('before_agent_start', (event, ctx) => {\n return handleModePrompt(event, ctx);\n });\n\n // Deploy specialist agent files for pi-subagents discovery\n pi.on('session_start', (_event: SessionStartEvent, ctx) => {\n deploySpecialistAgents(ctx);\n\n // Restore persisted state on session start (reload/resume/fork)\n if (!ctx.sessionManager?.getEntries) return;\n const entries = ctx.sessionManager.getEntries();\n // Walk from newest to oldest, find the last persisted maestria_state entry\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i];\n if (entry.type === 'custom' && entry.customType === 'maestria_state') {\n const data = entry.data;\n if (data && typeof data === 'object') {\n Object.assign(state, data);\n }\n break;\n }\n }\n });\n\n // Install compaction preservation handlers\n installCompactionHandlers(pi, state);\n\n // Install orchestration hooks: subagent tool and commands\n installSubagentTool(pi, state, cleanups);\n installCommands(pi, state);\n\n // Cleanup subscriptions on shutdown\n pi.on('session_shutdown', () => {\n for (const cleanup of cleanups) cleanup();\n cleanups.length = 0;\n });\n\n // Install tool call interceptors for review mode and dangerous patterns\n installToolInterceptors(pi, state);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maestria/pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Maestria extension for the Pi coding agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-orchestration",
|
|
@@ -15,9 +15,8 @@
|
|
|
15
15
|
"directory": "packages/pi"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
+
"agents",
|
|
18
19
|
"dist",
|
|
19
|
-
"prompts",
|
|
20
|
-
"rules",
|
|
21
20
|
"skills",
|
|
22
21
|
"README.md",
|
|
23
22
|
"LICENSE"
|
|
@@ -27,9 +26,7 @@
|
|
|
27
26
|
"access": "public",
|
|
28
27
|
"provenance": true
|
|
29
28
|
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"@gotgenes/pi-subagents": "^17.0.0"
|
|
32
|
-
},
|
|
29
|
+
"dependencies": {},
|
|
33
30
|
"devDependencies": {
|
|
34
31
|
"@types/node": "^24",
|
|
35
32
|
"typescript": "^6.0.3",
|
|
@@ -38,6 +35,7 @@
|
|
|
38
35
|
"peerDependencies": {
|
|
39
36
|
"@earendil-works/pi-ai": "*",
|
|
40
37
|
"@earendil-works/pi-coding-agent": "*",
|
|
38
|
+
"@gotgenes/pi-subagents": "^17.0.0",
|
|
41
39
|
"typebox": "*"
|
|
42
40
|
},
|
|
43
41
|
"engines": {
|
|
@@ -47,9 +45,6 @@
|
|
|
47
45
|
"extensions": [
|
|
48
46
|
"./dist/extension.mjs"
|
|
49
47
|
],
|
|
50
|
-
"prompts": [
|
|
51
|
-
"./prompts"
|
|
52
|
-
],
|
|
53
48
|
"skills": [
|
|
54
49
|
"./skills"
|
|
55
50
|
]
|
|
@@ -58,8 +53,8 @@
|
|
|
58
53
|
"build": "vp pack",
|
|
59
54
|
"test": "vp test",
|
|
60
55
|
"lint": "vp check",
|
|
61
|
-
"
|
|
56
|
+
"sync": "npx tsx ../core/scripts/sync.ts --config sync.config.ts",
|
|
62
57
|
"validate-skills": "node --experimental-strip-types scripts/validate-skills.ts",
|
|
63
|
-
"validate": "npm run validate-
|
|
58
|
+
"validate": "npm run validate-skills"
|
|
64
59
|
}
|
|
65
60
|
}
|
|
File without changes
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: global-rules
|
|
3
|
+
description: >-
|
|
4
|
+
Global behavioral constraints and best practices for maestria-powered
|
|
5
|
+
Pi agents. Covers orchestration conventions, delegation rules, context
|
|
6
|
+
management, commit policy, pipeline patterns, and branch discipline.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
|
|
1
10
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
11
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
12
|
|
|
File without changes
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator
|
|
3
|
+
description: >-
|
|
4
|
+
Maestria agent orchestration dispatcher. Delegates work to 7 specialist
|
|
5
|
+
subagents (adventurer, architect, builder, diagnose, planner, reviewer, writer)
|
|
6
|
+
using spec-driven handoffs. Enforces maker/checker split, commit protocol,
|
|
7
|
+
and role-based pipeline sequencing.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
<!-- Auto-generated from @maestria/core. Do not edit directly.
|
|
2
12
|
Edit the canonical file at packages/core/agent-directives/ instead. -->
|
|
3
13
|
|
|
@@ -25,14 +35,18 @@ These apply on every invocation without exception:
|
|
|
25
35
|
8. **!!! Default to the most specialized specialist for the question, not to `/builder`** - most tasks need `/adventurer` (recon), `/architect` (design), `/planner` (multi-phase), `/diagnose` (bugs), `/reviewer` (QA), or `/writer` (docs) before any code is touched. See the **Trigger phrases** section below.
|
|
26
36
|
9. **!!! After any `/builder` task that lands a code change, dispatch `/reviewer` for validation** - unless the user explicitly opts out in the same turn. Code without review is a maker/checker split violation. The default pipeline always ends with /reviewer, not with implementation.
|
|
27
37
|
10. **Use Conventional Commits for commit messages** - when composing commit messages, use the most specific prefix:
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
|
|
39
|
+
### Preferred order (most common first)
|
|
40
|
+
- `refactor`: Changes to existing behavior (restructuring, permission changes, internal improvements). **Default when unsure.**
|
|
30
41
|
- `fix`: Bug fix
|
|
42
|
+
- `feat`: New **user-facing** feature or capability. Not for internal refactoring, dependency updates, or skill configuration.
|
|
31
43
|
- `chore`: Maintenance, tooling, dependencies
|
|
32
44
|
- `docs`: Documentation only
|
|
33
45
|
- `ci`: CI/CD changes
|
|
34
46
|
- `test`: Test additions or changes
|
|
35
47
|
|
|
48
|
+
**Decision rule:** If a change doesn't introduce a new user-facing capability, it's `refactor`, not `feat`.
|
|
49
|
+
|
|
36
50
|
11. **!!! Don't anthropomorphize effort** - You are a dispatcher, not an implementer. Thinking "that analysis would be too much work" or "this approach is less effort" is always wrong reasoning - you delegate all work to specialists who have machine-scale capabilities. When assessing alternatives, choose the right specialist for the question, not the one that "feels" like less work. Effort estimation using human standards is a category error for a dispatcher that only routes.
|
|
37
51
|
|
|
38
52
|
12. **!!! Ship docs with code** - Every functional change needs a docs audit before committing (see step 1a). Don't wait to be asked.
|
|
@@ -59,7 +73,7 @@ When a logical unit of work is complete (implementation done, tests pass, valida
|
|
|
59
73
|
- If on any other branch (feature branch): push automatically after successful validation. Do not ask.
|
|
60
74
|
- Do not push every intermediate commit - push when a meaningful batch is ready or before creating a PR.
|
|
61
75
|
|
|
62
|
-
7. **PR** - After
|
|
76
|
+
7. **PR** - After pushing to a feature branch (non-main/master) where no PR exists yet, create a PR automatically. Check the remote URL (`git remote -v`) to detect the platform (GitHub → `gh`, GitLab → `glab`, Bitbucket → `bb`), then use the appropriate CLI or API. Do not ask - just create it. The user can edit after creation.
|
|
63
77
|
|
|
64
78
|
## Workflow Mode Override
|
|
65
79
|
|