@agimon-ai/doompi-team 0.0.1-alpha.28 → 0.0.1-alpha.29
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 +39 -12
- package/dist/api/teamSnapshot.cjs +1 -1
- package/dist/api/teamSnapshot.d.cts +2 -2
- package/dist/api/teamSnapshot.d.mts +2 -2
- package/dist/api/teamSnapshot.mjs +1 -1
- package/dist/src/adapters/pi/extension.cjs +1 -1
- package/dist/src/adapters/pi/extension.cjs.map +1 -1
- package/dist/src/adapters/pi/extension.mjs +1 -1
- package/dist/src/adapters/pi/extension.mjs.map +1 -1
- package/dist/src/adapters/pi/teamRuntime.cjs +1 -1
- package/dist/src/adapters/pi/teamRuntime.cjs.map +1 -1
- package/dist/src/adapters/pi/teamRuntime.mjs +1 -1
- package/dist/src/adapters/pi/teamRuntime.mjs.map +1 -1
- package/dist/src/extensions/orchestratorPrompt.cjs +5 -3
- package/dist/src/extensions/orchestratorPrompt.cjs.map +1 -1
- package/dist/src/extensions/orchestratorPrompt.mjs +5 -3
- package/dist/src/extensions/orchestratorPrompt.mjs.map +1 -1
- package/dist/src/extensions/spawnPlan.cjs +2 -2
- package/dist/src/extensions/spawnPlan.cjs.map +1 -1
- package/dist/src/extensions/spawnPlan.mjs +2 -2
- package/dist/src/extensions/spawnPlan.mjs.map +1 -1
- package/dist/src/extensions/statusViews.cjs.map +1 -1
- package/dist/src/extensions/statusViews.mjs.map +1 -1
- package/dist/src/extensions/subagentTool.cjs +3 -3
- package/dist/src/extensions/subagentTool.cjs.map +1 -1
- package/dist/src/extensions/subagentTool.mjs +3 -3
- package/dist/src/extensions/subagentTool.mjs.map +1 -1
- package/dist/src/extensions/toolDescription.cjs +1 -1
- package/dist/src/extensions/toolDescription.cjs.map +1 -1
- package/dist/src/extensions/toolDescription.mjs +1 -1
- package/dist/src/extensions/toolDescription.mjs.map +1 -1
- package/dist/src/services/api/teamSnapshot.cjs +2 -1
- package/dist/src/services/api/teamSnapshot.cjs.map +1 -1
- package/dist/src/services/api/teamSnapshot.d.cts +3 -1
- package/dist/src/services/api/teamSnapshot.d.cts.map +1 -1
- package/dist/src/services/api/teamSnapshot.d.mts +3 -1
- package/dist/src/services/api/teamSnapshot.d.mts.map +1 -1
- package/dist/src/services/api/teamSnapshot.mjs +2 -1
- package/dist/src/services/api/teamSnapshot.mjs.map +1 -1
- package/dist/src/services/runs/background/notify.cjs +2 -2
- package/dist/src/services/runs/background/notify.cjs.map +1 -1
- package/dist/src/services/runs/background/notify.mjs +2 -2
- package/dist/src/services/runs/background/notify.mjs.map +1 -1
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.cjs +1 -1
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.cjs.map +1 -1
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.d.cts +1 -0
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.d.mts +1 -0
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.mjs +1 -1
- package/dist/src/services/runs/shared/mcpDirectToolAllowlist.mjs.map +1 -1
- package/dist/src/services/runs/shared/piArgs.cjs +1 -1
- package/dist/src/services/runs/shared/piArgs.cjs.map +1 -1
- package/dist/src/services/runs/shared/piArgs.d.cts +2 -1
- package/dist/src/services/runs/shared/piArgs.d.mts +2 -1
- package/dist/src/services/runs/shared/piArgs.mjs +1 -1
- package/dist/src/services/runs/shared/piArgs.mjs.map +1 -1
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# @agimon-ai/doompi-team
|
|
2
2
|
|
|
3
|
-
An asynchronous subagent runtime for Pi: agent discovery, background runs, membership, intercom,
|
|
3
|
+
An asynchronous subagent runtime for Pi: agent discovery, background runs, membership, intercom,
|
|
4
|
+
and model and tool policy.
|
|
4
5
|
|
|
5
6
|
Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
|
|
6
7
|
|
|
7
|
-
Team does not own Task's graph. When both packages are loaded, Team fulfills Task delegation
|
|
8
|
+
Team does not own Task's graph. When both packages are loaded, Team fulfills Task delegation
|
|
9
|
+
requests while Task remains the source of truth for task status and dependencies.
|
|
8
10
|
|
|
9
11
|
> **Alpha:** run, policy, and intercom contracts may change between releases.
|
|
10
12
|
|
|
11
13
|
## Requirements
|
|
12
14
|
|
|
13
15
|
- Node.js 22.19.0 or newer
|
|
14
|
-
-
|
|
16
|
+
- `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`,
|
|
17
|
+
`@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` 0.84.2
|
|
15
18
|
|
|
16
19
|
## Install
|
|
17
20
|
|
|
@@ -41,7 +44,8 @@ For Team without Task in standalone Pi:
|
|
|
41
44
|
pi install npm:@agimon-ai/doompi-team
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
Team-only sessions can launch and manage agents directly; they simply have no Task-owned graph to
|
|
47
|
+
Team-only sessions can launch and manage agents directly; they simply have no Task-owned graph to
|
|
48
|
+
update.
|
|
45
49
|
|
|
46
50
|
## Commands and tools
|
|
47
51
|
|
|
@@ -56,21 +60,40 @@ Slash commands include:
|
|
|
56
60
|
/subagents-fleet
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
Use `/run` for one agent, `/parallel` for several, `/subagents-doctor` for diagnostics,
|
|
64
|
+
`/subagents-stop` to stop work, `/subagents-list` for available agents, and `/subagents-fleet` for
|
|
65
|
+
current runs.
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
The `subagent` tool exposes `agents`, `run`, `status`, `steer`, `stop`, `suspended`, and `restore`.
|
|
68
|
+
The `intercom` tool exposes `members`, `send`, `ask`, `pending`, and `reply`.
|
|
69
|
+
|
|
70
|
+
Use `SPC a l` to browse agents and `SPC a r` to inspect current-session runs. TUI views require an
|
|
71
|
+
interactive host; tools and commands support headless orchestration.
|
|
62
72
|
|
|
63
73
|
## Run lifecycle
|
|
64
74
|
|
|
65
|
-
Runs are asynchronous. The parent receives a run identifier and later completion or failure rather
|
|
75
|
+
Runs are asynchronous. The parent receives a run identifier and later completion or failure rather
|
|
76
|
+
than an inline child transcript. A shutdown requests suspension and writes restorable state. A later
|
|
77
|
+
session can list suspended work and explicitly restore it. Reopening does not automatically restart
|
|
78
|
+
children, and Team does not promise that every run continues after its parent exits.
|
|
66
79
|
|
|
67
|
-
The root session scopes run results, transcripts, control inboxes, membership, intercom, and
|
|
80
|
+
The root session scopes run results, transcripts, control inboxes, membership, intercom, and
|
|
81
|
+
suspended records. State is stored in private, per-user temporary directories with per-session
|
|
82
|
+
subdirectories. Suspended records are recoverable only while those temporary files remain. Launch
|
|
83
|
+
contracts can contain full prompts and are written with private permissions, then removed after
|
|
84
|
+
handoff. Intercom messages expire after 24 hours; liveness checks remove stale membership and run
|
|
85
|
+
state.
|
|
68
86
|
|
|
69
87
|
## Model and tool policy
|
|
70
88
|
|
|
71
|
-
Package configuration belongs on the Team package entry. When several selected entries contribute
|
|
89
|
+
Package configuration belongs on the Team package entry. When several selected entries contribute
|
|
90
|
+
configuration, later entries replace the `models` list and `excludeTools` values are combined in
|
|
91
|
+
layer order.
|
|
72
92
|
|
|
73
|
-
Agent configuration, explicit launch options, Team policy, and provider availability determine the
|
|
93
|
+
Agent configuration, explicit launch options, Team policy, and provider availability determine the
|
|
94
|
+
final model and tools. A child cannot exceed the capability ceiling supplied by its parent or
|
|
95
|
+
provider policy. Allowed MCP and stdio tools can execute commands, so treat agent definitions and
|
|
96
|
+
the inherited environment as trusted configuration.
|
|
74
97
|
|
|
75
98
|
## Task delegation bridge
|
|
76
99
|
|
|
@@ -81,7 +104,9 @@ With Task installed:
|
|
|
81
104
|
3. Team owns the background run, messaging, steering, and suspension.
|
|
82
105
|
4. Task records the terminal result on its own task.
|
|
83
106
|
|
|
84
|
-
This is a named Cordis
|
|
107
|
+
This is a named Cordis service relationship, not shared persistence. Team provides
|
|
108
|
+
`doom/delegation`, `doom/background-work`, `doom/subagent-policy`, and `doom/fable-plan` for the
|
|
109
|
+
active session. Consumers disconnect and reconnect automatically when that provider changes.
|
|
85
110
|
|
|
86
111
|
## Public API
|
|
87
112
|
|
|
@@ -89,7 +114,9 @@ This is a named Cordis-service relationship, not shared persistence. Team provid
|
|
|
89
114
|
import { resolveSubagentLaunchContract } from '@agimon-ai/doompi-team';
|
|
90
115
|
```
|
|
91
116
|
|
|
92
|
-
Focused subpaths expose the pure capability-ceiling codec,
|
|
117
|
+
Focused subpaths expose the pure capability-ceiling codec, compatibility delegation payload types,
|
|
118
|
+
and team-snapshot contracts. Live cross-extension collaboration contracts come from
|
|
119
|
+
`@agimon-ai/doompi-extension-contracts`; the standard Pi extension is available at `/extensions/pi`.
|
|
93
120
|
|
|
94
121
|
## Development
|
|
95
122
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../src/services/api/teamSnapshot.cjs");exports.readActiveTeamSnapshot=e.readActiveTeamSnapshot;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../src/services/api/teamSnapshot.cjs");exports.formatTeamContextSnapshot=e.formatTeamContextSnapshot,exports.readActiveTeamSnapshot=e.readActiveTeamSnapshot;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { TeamMemberSnapshot, TeamSnapshot, readActiveTeamSnapshot } from "../src/services/api/teamSnapshot.cjs";
|
|
2
|
-
export { TeamMemberSnapshot, TeamSnapshot, readActiveTeamSnapshot };
|
|
1
|
+
import { TeamMemberSnapshot, TeamSnapshot, formatTeamContextSnapshot, readActiveTeamSnapshot } from "../src/services/api/teamSnapshot.cjs";
|
|
2
|
+
export { TeamMemberSnapshot, TeamSnapshot, formatTeamContextSnapshot, readActiveTeamSnapshot };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { TeamMemberSnapshot, TeamSnapshot, readActiveTeamSnapshot } from "../src/services/api/teamSnapshot.mjs";
|
|
2
|
-
export { TeamMemberSnapshot, TeamSnapshot, readActiveTeamSnapshot };
|
|
1
|
+
import { TeamMemberSnapshot, TeamSnapshot, formatTeamContextSnapshot, readActiveTeamSnapshot } from "../src/services/api/teamSnapshot.mjs";
|
|
2
|
+
export { TeamMemberSnapshot, TeamSnapshot, formatTeamContextSnapshot, readActiveTeamSnapshot };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readActiveTeamSnapshot as
|
|
1
|
+
import{formatTeamContextSnapshot as e,readActiveTeamSnapshot as t}from"../src/services/api/teamSnapshot.mjs";export{e as formatTeamContextSnapshot,t as readActiveTeamSnapshot};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../shared/paths.cjs"),t=require("../../shared/modelResolution.cjs"),n=require("../../services/runs/shared/modelFallback.cjs"),r=require("../../extensions/spawnPlan.cjs"),i=require("../asyncJobTracker.cjs");require("../../services/runs/background/asyncJobTracker.cjs");const a=require("../../commands/slash/slashCommands.cjs"),o=require("../../extensions/config.cjs"),s=require("../../extensions/delegationBridge.cjs"),ee=require("../scopeOwner.cjs"),c=require("../../extensions/fablePlanBridge.cjs"),l=require("../../extensions/orchestratorPrompt.cjs"),te=require("../suspendedRuns.cjs");require("../../services/runs/registry/suspendedRuns.cjs");const u=require("../../services/runs/registry/sessionLifecycle.cjs");require("../../shared/scopeOwner.cjs");const d=require("../../tui/completionNotice.cjs"),f=require("../../tui/register.cjs"),ne=require("./collaboration.cjs"),p=require("./teamRuntime.cjs");let m=require("@agimon-ai/doompi-extension-contracts/child-process"),h=require("@agimon-ai/doompi-extension-contracts/cordis-host"),g=require("@agimon-ai/doompi-extension-contracts/readiness"),_=require("@agimon-ai/doompi-extension-contracts/ui-hub"),re=require("@agimon-ai/doompi-telemetry");const v=`unknown`,y=`@agimon-ai/doompi-team`;function ie(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function ae(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`;return`${e.packageId} initialization ${e.state}: ${n}`}function oe(e,t,n,r,i,a){return{spawnPlanner:n,tracker:r,scheduler:i,discovery:e,skills:t,management:a,loadConfig:()=>o.loadConfig().config}}function se(e,t){if(t.kind===`requested`){let{event:n}=t;e.recordEvent(`doom_team.delegation_requested`,{"agent.name":n.agent,"task.id":n.taskId,mode:n.runMode??`foreground`})}else if(t.kind===`started`){let{event:n}=t;e.recordEvent(`doom_team.child_started`,{"run.id":n.runId,outcome:`started`})}else if(t.kind===`updated`){let{event:n}=t;e.recordEvent(`doom_team.delegation_updated`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,"team.token_count":n.tokens??0,outcome:n.status??`updated`})}else if(t.kind===`finished`){let{event:n}=t;e.recordEvent(`doom_team.delegation_finished`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,outcome:n.status})}else e.recordEvent(`doom_team.delegation_cancelled`,{outcome:`cancelled`})}function b(b,x){let S,ce=e=>(S??=(0,re.createDoomTelemetry)({serviceName:`doom-team`,packageName:`@agimon-ai/doompi-team`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),S),le=(e,t)=>{S?.recordEvent(e,t)};b.effect(()=>async()=>{await S?.shutdown(),S=void 0},`@agimon-ai/doompi-team/telemetry`);let C=p.createTeamExtensionRuntime(le),{subagentTool:ue,teamChannel:w,pollScheduler:T,asyncJobTracker:E,subagentWaiter:D,asyncSubagentSpawner:de,discovery:O,skills:k,spawnPlanner:A,completionNotifier:j,resultWatcher:M,staleRunReconciler:N,management:P,capabilityPolicies:F}=C,I=!0,L=0,R,z,B,V,H,U;b.inject([h.DOOM_CORDIS_SESSION_SERVICE],e=>{let t={cordis:e,service:e.get(h.DOOM_CORDIS_SESSION_SERVICE)};U=t,e.effect(()=>()=>{U===t&&(U=void 0)},`${y}/cordis-session`)});let fe=e=>{let t=U,n=e.sessionManager.getSessionId();return(t?.service.context.sessionManager===e.sessionManager&&t.service.sessionId===n?(0,g.readDoomReadinessCoordinator)(t.cordis):void 0)||(V??=(0,g.createDoomReadinessCoordinator)({notify:e=>{let t=ae(e);H?.hasUI?H.ui.notify(t,`warning`):process.emitWarning(t)}}),V)},W=async(e,t)=>{t?.throwIfAborted();let n=z;if(!n)throw Error(`Doom Team session initialization has not started.`);if(B!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale Pi session.`);let r=await n;if(t?.throwIfAborted(),await r.wait(t?{signal:t}:void 0),!I||n!==z||B!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale extension generation.`)},G=new Proxy(x,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await W(a,r),t.execute(e,n,r,i,a))})}:t===`registerCommand`?(t,n)=>{e.registerCommand(t,{...n,handler:async(e,t)=>(await W(t),n.handler(e,t))})}:t===`registerShortcut`?(t,n)=>{e.registerShortcut(t,{...n,handler:async e=>(await W(e),n.handler(e))})}:ie(e,t)}});ue.registerTool(G),b.inject([_.DOOM_UI_HUB_SERVICE],e=>f.registerSubagentLeaderContribution((0,_.requireDoomUiHub)(e)));let K=w.createRuntime(G);b.effect(()=>()=>K.dispose(),`@agimon-ai/doompi-team/channel`),w.registerClient(G),j.attachHost(x),b.effect(()=>()=>j.dispose(),`@agimon-ai/doompi-team/completions`),T.start(),b.effect(()=>()=>T.stop(),`@agimon-ai/doompi-team/polling`),E.start(),b.effect(()=>()=>E.stop(),`@agimon-ai/doompi-team/jobs`);let q,J,Y,X=s.createDelegationBridge({planner:A,management:P,waiter:D,scheduler:T,tracker:E,loadConfig:()=>o.loadConfig().config}),Z=c.createFablePlanBridge({spawner:de,waiter:D,management:P,policies:F,report:(e,t)=>{S?.recordEvent(e,t)}});b.effect(()=>async()=>{await q?.dispose(),q=void 0},`@agimon-ai/doompi-team/collaboration`),b.effect(()=>()=>{M.stop(),Y=void 0},`@agimon-ai/doompi-team/result-watcher`);let pe=T.register({id:`stale-run-reconciler`,intervalMs:2e3,run:async()=>{let e=!1,t=!1;for(let n of J?.list()??[]){if(n.status&&i.TERMINAL_ASYNC_JOB_STATES.has(n.status))continue;t=!0;let{reconcile:r,sweep:a}=N.reconcileAndSweepAsync?await N.reconcileAndSweepAsync(n.runId):N.reconcileAndSweep(n.runId);r.repaired&&(J?.track(n.runId),e=!0),a.recovered.length>0&&(e=!0)}return e||t}});b.effect(()=>pe,`@agimon-ai/doompi-team/stale-runs`),x.on(`before_agent_start`,e=>{if(!(!I||!l.shouldInjectOrchestratorPrompt(o.loadConfig().config)))return{systemPrompt:l.appendOrchestratorPrompt(e.systemPrompt)}});let Q={baseCwd:void 0};a.registerSlashCommands(G,Q,oe(O,k,A,E,T,P)),f.registerAgentListCommand(G,{discovery:O,skills:k,policies:F}),f.registerFleetCommand(G,{scheduler:T,tracker:E,management:P}),b.inject([_.DOOM_UI_HUB_SERVICE],e=>f.registerAgentStatus(x,(0,_.requireDoomUiHub)(e),{scheduler:T,tracker:E})),d.registerCompletionRenderer(x);let me=async()=>{let e=[],t=q;q=void 0;try{await t?.dispose()}catch(t){e.push(t)}for(let t of[()=>F.clear(),()=>X.abandonAll(),()=>Z.abandonAll(),()=>K.dispose()])try{t()}catch(t){e.push(t)}if(J=void 0,e.length!==0)return e.length===1&&e[0]instanceof Error?e[0]:AggregateError(e,`Team session cleanup failed.`)};x.on(`session_start`,(i,a)=>{if(!I)return;let o=++L,s=z;R?.abort(Error(`Doom Team session initialization was superseded.`));let c=new AbortController;R=c,B=a.sessionManager,H=a;let l=ce(a);l.recordEvent(`doom_team.session_started`,{"team.root_session":(0,m.resolveRootSessionId)(a.sessionManager.getSessionId())===a.sessionManager.getSessionId()});let d=a.sessionManager.getSessionId(),f=e.createSessionScope((0,m.resolveRootSessionId)(d));e.setCurrentSessionScope(f),Q.baseCwd=a.cwd,Y!==void 0&&Y!==f.scopeKey&&(M.stop(),Y=void 0);let p=me(),h=fe(a),g=()=>I&&o===L&&B===a.sessionManager&&!c.signal.aborted;z=(async()=>{if(s&&await Promise.allSettled([s.then(e=>e.wait())]),!g())throw Error(`Doom Team session initialization was superseded.`);return h.start(y,`${d}:${o}`,async e=>{e.throwIfAborted();let i=await p;if(i)throw i;if(!g()||(await ee.writeScopeOwnerAsync(f),e.throwIfAborted(),!g()))return{value:void 0};let o=await u.openScopeAsync(f,{readStatusAsync:async e=>P.statusAsync?(await P.statusAsync(e)).status:P.status(e).status});if(e.throwIfAborted(),!g())return{value:void 0};if(o.suspended.length>0&&a.hasUI){let t=await te.formatSuspendedRunsAsync(o.suspended);if(e.throwIfAborted(),!g())return{value:void 0};a.ui.notify(t,`info`)}l.recordEvent(`doom_team.runs_restored`,{"team.suspended_count":o.suspended.length,"team.pruned_count":o.pruned.length,"team.reaped_count":o.reaped,outcome:`reported`}),J=E.forSession(d),Y!==f.scopeKey&&(Y=f.scopeKey,M.start(e=>J?.get(e.runId)?j.deliver(e):!1));let s=n.normalizeParentModel(a.model),c=U,m=(c?.service.context.sessionManager===a.sessionManager?c.cordis:b).plugin(ne.teamCollaborationPlugin,{session:{sessionId:d,cwd:a.cwd,availableModels:t.authenticatedModelInfos(a.modelRegistry),...s?{parentModel:s}:{},forkSource:r.captureSessionForkSource(a.sessionManager,`tool`)},delegation:X,fablePlan:Z,policies:F,observeDelegation:e=>se(l,e)});return q=m,await m.await(),g()?(K.bindMainSession(d),{value:void 0}):(await m.dispose(),q===m&&(q=void 0),{value:void 0})})})(),Promise.allSettled([z.then(e=>e.wait())])}),b.effect(()=>async()=>{I=!1,L+=1;let e=z;z=void 0,B=void 0,R?.abort(Error(`Doom Team runtime was disposed.`)),R=void 0;let t=V;V=void 0,t?await t.dispose():e&&await Promise.allSettled([e.then(e=>e.wait())]),H=void 0},`@agimon-ai/doompi-team/session-fence`);let $,he=async t=>{I=!1,L+=1;let n=z;z=void 0,B=void 0,R?.abort(Error(`Doom Team session ended.`)),R=void 0;let r=V;V=void 0,await Promise.allSettled([...n?[n.then(e=>e.wait())]:[],...r?[r.dispose()]:[]]);let i=e.tryCurrentSessionScope(),a=i?u.suspendScopeRuns({scope:i,reason:t.reason??v,readStatus:e=>P.status(e).status}):Promise.resolve(void 0),o;try{o=await a,await S?.recordEvent(`doom_team.session_finished`,{reason:t.reason??v,"team.suspended_count":o?.suspended.length??0,"team.unstoppable_count":o?.unstoppable.length??0,outcome:o?.unstoppable.length?`degraded`:`suspended`})}catch(e){await S?.recordError(`doom_team.session_shutdown_failed`,e,{reason:t.reason??v})}finally{await S?.shutdown(),S=void 0}};return x.on(`session_shutdown`,e=>($??=he(e),$)),C}exports.installTeamRuntime=b;
|
|
1
|
+
const e=require("../../shared/paths.cjs"),t=require("../../services/api/teamSnapshot.cjs"),n=require("../../shared/modelResolution.cjs"),r=require("../../services/runs/shared/modelFallback.cjs"),i=require("../../extensions/spawnPlan.cjs"),a=require("../asyncJobTracker.cjs");require("../../services/runs/background/asyncJobTracker.cjs");const o=require("../../commands/slash/slashCommands.cjs"),s=require("../../extensions/config.cjs"),c=require("../../extensions/delegationBridge.cjs"),ee=require("../scopeOwner.cjs"),l=require("../../extensions/fablePlanBridge.cjs"),u=require("../../extensions/orchestratorPrompt.cjs"),te=require("../suspendedRuns.cjs");require("../../services/runs/registry/suspendedRuns.cjs");const d=require("../../services/runs/registry/sessionLifecycle.cjs");require("../../shared/scopeOwner.cjs");const f=require("../../tui/completionNotice.cjs"),p=require("../../tui/register.cjs"),ne=require("./collaboration.cjs"),m=require("./teamRuntime.cjs");let h=require("@agimon-ai/doompi-extension-contracts/child-process"),g=require("@agimon-ai/doompi-extension-contracts/cordis-host"),_=require("@agimon-ai/doompi-extension-contracts/context-contributions"),v=require("@agimon-ai/doompi-extension-contracts/mcp-tool-resolver"),y=require("@agimon-ai/doompi-extension-contracts/readiness"),b=require("@agimon-ai/doompi-extension-contracts/ui-hub"),re=require("@agimon-ai/doompi-telemetry");const x=`unknown`,S=`@agimon-ai/doompi-team`;function ie(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function ae(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`;return`${e.packageId} initialization ${e.state}: ${n}`}function oe(e,t,n,r,i,a){return{spawnPlanner:n,tracker:r,scheduler:i,discovery:e,skills:t,management:a,loadConfig:()=>s.loadConfig().config}}function se(e,t){if(t.kind===`requested`){let{event:n}=t;e.recordEvent(`doom_team.delegation_requested`,{"agent.name":n.agent,"task.id":n.taskId,mode:n.runMode??`foreground`})}else if(t.kind===`started`){let{event:n}=t;e.recordEvent(`doom_team.child_started`,{"run.id":n.runId,outcome:`started`})}else if(t.kind===`updated`){let{event:n}=t;e.recordEvent(`doom_team.delegation_updated`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,"team.token_count":n.tokens??0,outcome:n.status??`updated`})}else if(t.kind===`finished`){let{event:n}=t;e.recordEvent(`doom_team.delegation_finished`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,outcome:n.status})}else e.recordEvent(`doom_team.delegation_cancelled`,{outcome:`cancelled`})}function C(C,w){let T,ce=e=>(T??=(0,re.createDoomTelemetry)({serviceName:`doom-team`,packageName:`@agimon-ai/doompi-team`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),T),le=(e,t)=>{T?.recordEvent(e,t)};C.effect(()=>async()=>{await T?.shutdown(),T=void 0},`@agimon-ai/doompi-team/telemetry`);let E=m.createTeamExtensionRuntime(le),{subagentTool:ue,teamChannel:D,pollScheduler:O,asyncJobTracker:k,subagentWaiter:A,asyncSubagentSpawner:de,discovery:j,skills:M,spawnPlanner:N,completionNotifier:P,resultWatcher:F,staleRunReconciler:I,management:L,capabilityPolicies:R,mcpToolResolver:fe}=E,z=!0,B=0,V,H,U,W,G,K;C.inject([g.DOOM_CORDIS_SESSION_SERVICE],e=>{let n={cordis:e,service:e.get(g.DOOM_CORDIS_SESSION_SERVICE)};K=n,e.inject([v.DOOM_MCP_TOOL_RESOLVER_SERVICE],e=>fe.bind((0,v.requireDoomMcpToolResolver)(e))),e.inject([_.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE],e=>{let n=(0,_.requireDoomContextContributions)(e).register({source:S,id:`runtime`,label:`Team`,order:200,snapshot:()=>t.formatTeamContextSnapshot(t.readActiveTeamSnapshot())});return()=>n.dispose()}),e.effect(()=>()=>{K===n&&(K=void 0)},`${S}/cordis-session`)});let pe=e=>{let t=K,n=e.sessionManager.getSessionId();return(t?.service.context.sessionManager===e.sessionManager&&t.service.sessionId===n?(0,y.readDoomReadinessCoordinator)(t.cordis):void 0)||(W??=(0,y.createDoomReadinessCoordinator)({notify:e=>{let t=ae(e);G?.hasUI?G.ui.notify(t,`warning`):process.emitWarning(t)}}),W)},q=async(e,t)=>{t?.throwIfAborted();let n=H;if(!n)throw Error(`Doom Team session initialization has not started.`);if(U!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale Pi session.`);let r=await n;if(t?.throwIfAborted(),await r.wait(t?{signal:t}:void 0),!z||n!==H||U!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale extension generation.`)},J=new Proxy(w,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await q(a,r),t.execute(e,n,r,i,a))})}:t===`registerCommand`?(t,n)=>{e.registerCommand(t,{...n,handler:async(e,t)=>(await q(t),n.handler(e,t))})}:t===`registerShortcut`?(t,n)=>{e.registerShortcut(t,{...n,handler:async e=>(await q(e),n.handler(e))})}:ie(e,t)}});ue.registerTool(J),C.inject([b.DOOM_UI_HUB_SERVICE],e=>p.registerSubagentLeaderContribution((0,b.requireDoomUiHub)(e)));let Y=D.createRuntime(J);C.effect(()=>()=>Y.dispose(),`@agimon-ai/doompi-team/channel`),D.registerClient(J),P.attachHost(w),C.effect(()=>()=>P.dispose(),`@agimon-ai/doompi-team/completions`),O.start(),C.effect(()=>()=>O.stop(),`@agimon-ai/doompi-team/polling`),k.start(),C.effect(()=>()=>k.stop(),`@agimon-ai/doompi-team/jobs`);let X,Z,Q,me=c.createDelegationBridge({planner:N,management:L,waiter:A,scheduler:O,tracker:k,loadConfig:()=>s.loadConfig().config}),he=l.createFablePlanBridge({spawner:de,waiter:A,management:L,policies:R,report:(e,t)=>{T?.recordEvent(e,t)}});C.effect(()=>async()=>{await X?.dispose(),X=void 0},`@agimon-ai/doompi-team/collaboration`),C.effect(()=>()=>{F.stop(),Q=void 0},`@agimon-ai/doompi-team/result-watcher`);let ge=O.register({id:`stale-run-reconciler`,intervalMs:2e3,run:async()=>{let e=!1,t=!1;for(let n of Z?.list()??[]){if(n.status&&a.TERMINAL_ASYNC_JOB_STATES.has(n.status))continue;t=!0;let{reconcile:r,sweep:i}=I.reconcileAndSweepAsync?await I.reconcileAndSweepAsync(n.runId):I.reconcileAndSweep(n.runId);r.repaired&&(Z?.track(n.runId),e=!0),i.recovered.length>0&&(e=!0)}return e||t}});C.effect(()=>ge,`@agimon-ai/doompi-team/stale-runs`),w.on(`before_agent_start`,e=>{if(!(!z||!u.shouldInjectOrchestratorPrompt(s.loadConfig().config)))return{systemPrompt:u.appendOrchestratorPrompt(e.systemPrompt)}});let $={baseCwd:void 0};o.registerSlashCommands(J,$,oe(j,M,N,k,O,L)),p.registerAgentListCommand(J,{discovery:j,skills:M,policies:R}),p.registerFleetCommand(J,{scheduler:O,tracker:k,management:L}),C.inject([b.DOOM_UI_HUB_SERVICE],e=>p.registerAgentStatus(w,(0,b.requireDoomUiHub)(e),{scheduler:O,tracker:k})),f.registerCompletionRenderer(w);let _e=async()=>{let e=[],t=X;X=void 0;try{await t?.dispose()}catch(t){e.push(t)}for(let t of[()=>R.clear(),()=>me.abandonAll(),()=>he.abandonAll(),()=>Y.dispose()])try{t()}catch(t){e.push(t)}if(Z=void 0,e.length!==0)return e.length===1&&e[0]instanceof Error?e[0]:AggregateError(e,`Team session cleanup failed.`)};w.on(`session_start`,(t,a)=>{if(!z)return;let o=++B,s=H;V?.abort(Error(`Doom Team session initialization was superseded.`));let c=new AbortController;V=c,U=a.sessionManager,G=a;let l=ce(a);l.recordEvent(`doom_team.session_started`,{"team.root_session":(0,h.resolveRootSessionId)(a.sessionManager.getSessionId())===a.sessionManager.getSessionId()});let u=a.sessionManager.getSessionId(),f=e.createSessionScope((0,h.resolveRootSessionId)(u));e.setCurrentSessionScope(f),$.baseCwd=a.cwd,Q!==void 0&&Q!==f.scopeKey&&(F.stop(),Q=void 0);let p=_e(),m=pe(a),g=()=>z&&o===B&&U===a.sessionManager&&!c.signal.aborted;H=(async()=>{if(s&&await Promise.allSettled([s.then(e=>e.wait())]),!g())throw Error(`Doom Team session initialization was superseded.`);return m.start(S,`${u}:${o}`,async e=>{e.throwIfAborted();let t=await p;if(t)throw t;if(!g()||(await ee.writeScopeOwnerAsync(f),e.throwIfAborted(),!g()))return{value:void 0};let o=await d.openScopeAsync(f,{readStatusAsync:async e=>L.statusAsync?(await L.statusAsync(e)).status:L.status(e).status});if(e.throwIfAborted(),!g())return{value:void 0};if(o.suspended.length>0&&a.hasUI){let t=await te.formatSuspendedRunsAsync(o.suspended);if(e.throwIfAborted(),!g())return{value:void 0};a.ui.notify(t,`info`)}l.recordEvent(`doom_team.runs_restored`,{"team.suspended_count":o.suspended.length,"team.pruned_count":o.pruned.length,"team.reaped_count":o.reaped,outcome:`reported`}),Z=k.forSession(u),Q!==f.scopeKey&&(Q=f.scopeKey,F.start(e=>Z?.get(e.runId)?P.deliver(e):!1));let s=r.normalizeParentModel(a.model),c=K,m=(c?.service.context.sessionManager===a.sessionManager?c.cordis:C).plugin(ne.teamCollaborationPlugin,{session:{sessionId:u,cwd:a.cwd,availableModels:n.authenticatedModelInfos(a.modelRegistry),...s?{parentModel:s}:{},forkSource:i.captureSessionForkSource(a.sessionManager,`tool`)},delegation:me,fablePlan:he,policies:R,observeDelegation:e=>se(l,e)});return X=m,await m.await(),g()?(Y.bindMainSession(u),{value:void 0}):(await m.dispose(),X===m&&(X=void 0),{value:void 0})})})(),Promise.allSettled([H.then(e=>e.wait())])}),C.effect(()=>async()=>{z=!1,B+=1;let e=H;H=void 0,U=void 0,V?.abort(Error(`Doom Team runtime was disposed.`)),V=void 0;let t=W;W=void 0,t?await t.dispose():e&&await Promise.allSettled([e.then(e=>e.wait())]),G=void 0},`@agimon-ai/doompi-team/session-fence`);let ve,ye=async t=>{z=!1,B+=1;let n=H;H=void 0,U=void 0,V?.abort(Error(`Doom Team session ended.`)),V=void 0;let r=W;W=void 0,await Promise.allSettled([...n?[n.then(e=>e.wait())]:[],...r?[r.dispose()]:[]]);let i=e.tryCurrentSessionScope(),a=i?d.suspendScopeRuns({scope:i,reason:t.reason??x,readStatus:e=>L.status(e).status}):Promise.resolve(void 0),o;try{o=await a,await T?.recordEvent(`doom_team.session_finished`,{reason:t.reason??x,"team.suspended_count":o?.suspended.length??0,"team.unstoppable_count":o?.unstoppable.length??0,outcome:o?.unstoppable.length?`degraded`:`suspended`})}catch(e){await T?.recordError(`doom_team.session_shutdown_failed`,e,{reason:t.reason??x})}finally{await T?.shutdown(),T=void 0}};return w.on(`session_shutdown`,e=>(ve??=ye(e),ve)),E}exports.installTeamRuntime=C;
|
|
2
2
|
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.cjs","names":["loadConfig","createDoomTelemetry","createTeamExtensionRuntime","DOOM_CORDIS_SESSION_SERVICE","readDoomReadinessCoordinator","createDoomReadinessCoordinator","DOOM_UI_HUB_SERVICE","registerSubagentLeaderContribution","requireDoomUiHub","createDelegationBridge","createFablePlanBridge","TERMINAL_ASYNC_JOB_STATES","shouldInjectOrchestratorPrompt","appendOrchestratorPrompt","registerAgentStatus","resolveRootSessionId","createSessionScope","writeScopeOwnerAsync","openScopeAsync","formatSuspendedRunsAsync","normalizeParentModel","teamCollaborationPlugin","authenticatedModelInfos","captureSessionForkSource","tryCurrentSessionScope","suspendScopeRuns"],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Install the Team feature into one package-local Cordis root.\n *\n * The standard Pi factory owns that root and disposes it when Pi emits\n * `session_shutdown`. Each factory invocation therefore creates fresh session\n * state; no process-global container or replacement-root handshake participates\n * in reload. Long-lived services are registered as Cordis effects, and stale\n * asynchronous session-start continuations are fenced by a generation token.\n */\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport {\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context, Fiber } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n registerSlashCommands,\n type SlashCommandDeps,\n type SlashCommandState,\n} from '../../commands/slash/slashCommands.ts';\nimport { loadConfig } from '../../extensions/config.ts';\nimport { createDelegationBridge } from '../../extensions/delegationBridge.ts';\nimport { createFablePlanBridge } from '../../extensions/fablePlanBridge.ts';\nimport type { IManagementActions } from '../../extensions/managementActions.ts';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from '../../extensions/orchestratorPrompt.ts';\nimport { captureSessionForkSource, type ISpawnPlanner } from '../../extensions/spawnPlan.ts';\nimport type { ISkillDiscoveryService } from '../../services/agents/skills.ts';\nimport type { IAgentDiscoveryService } from '../../services/agents/types.ts';\nimport {\n type IAsyncJobTracker,\n type ITrackedAsyncJobs,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../../services/runs/background/asyncJobTracker.ts';\nimport { openScopeAsync, suspendScopeRuns } from '../../services/runs/registry/sessionLifecycle.ts';\nimport { formatSuspendedRunsAsync } from '../../services/runs/registry/suspendedRuns.ts';\nimport { normalizeParentModel } from '../../services/runs/shared/modelFallback.ts';\nimport { authenticatedModelInfos } from '../../shared/modelResolution.ts';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../../shared/paths.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\nimport { writeScopeOwnerAsync } from '../../shared/scopeOwner.ts';\nimport { registerCompletionRenderer } from '../../tui/completionNotice.ts';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from '../../tui/register.ts';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration.ts';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime.ts';\n\n/** See the subscriber's own comment for why crash detection does not need the 250ms floor. */\nconst STALE_RUN_RECONCILE_INTERVAL_MS = 2_000;\nconst SESSION_SHUTDOWN_REASON_FALLBACK = 'unknown';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-team';\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\n\nfunction boundPiValue(target: ExtensionAPI, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction readinessNotificationMessage(notification: DoomReadinessNotification): string {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n return `${notification.packageId} initialization ${notification.state}: ${detail}`;\n}\n\nfunction buildSlashCommandDeps(\n discovery: IAgentDiscoveryService,\n skills: ISkillDiscoveryService,\n planner: ISpawnPlanner,\n tracker: IAsyncJobTracker,\n scheduler: IPollScheduler,\n management: IManagementActions,\n): SlashCommandDeps {\n return {\n spawnPlanner: planner,\n tracker,\n scheduler,\n discovery,\n skills,\n management,\n loadConfig: () => loadConfig().config,\n };\n}\n\nfunction recordDelegationObservation(telemetry: DoomTelemetry, observation: TeamDelegationObservation): void {\n if (observation.kind === 'requested') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_requested', {\n 'agent.name': event.agent,\n 'task.id': event.taskId,\n mode: event.runMode ?? 'foreground',\n });\n } else if (observation.kind === 'started') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.child_started', { 'run.id': event.runId, outcome: 'started' });\n } else if (observation.kind === 'updated') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_updated', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n 'team.token_count': event.tokens ?? 0,\n outcome: event.status ?? 'updated',\n });\n } else if (observation.kind === 'finished') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_finished', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n outcome: event.status,\n });\n } else {\n void telemetry.recordEvent('doom_team.delegation_cancelled', { outcome: 'cancelled' });\n }\n}\n\n/**\n * The extension factory pi's loader calls, exported as the module default\n * (see the override this file carries in `vibe-lint.config.yaml`). This is an\n * ESM `.ts` module, so it CANNOT use the `export =` form that\n * `subagentPromptRuntimeEntry.cts` is required to use - that file is `.cts`\n * and is resolved by raw path, this one is resolved as a package subpath and\n * matches the `export default` convention every sibling extension in this repo\n * already uses (`doom-task`, `doom-file-edit`, `doom-pi-ui`).\n */\nexport function installTeamRuntime(cordis: Context, pi: ExtensionAPI): TeamExtensionRuntime {\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-team',\n packageName: '@agimon-ai/doompi-team',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n const reportConcurrencyEvent = (event: string, attributes: Record<string, unknown>): void => {\n void telemetry?.recordEvent(event, attributes);\n };\n cordis.effect(\n () => async () => {\n await telemetry?.shutdown();\n telemetry = undefined;\n },\n '@agimon-ai/doompi-team/telemetry',\n );\n const runtime = createTeamExtensionRuntime(reportConcurrencyEvent);\n const {\n subagentTool,\n teamChannel,\n pollScheduler,\n asyncJobTracker,\n subagentWaiter,\n asyncSubagentSpawner,\n discovery,\n skills,\n spawnPlanner,\n completionNotifier,\n resultWatcher,\n staleRunReconciler,\n management,\n capabilityPolicies,\n } = runtime;\n\n let active = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let readinessSessionManager: object | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n let readinessNotificationContext: ExtensionContext | undefined;\n let activeCordisSession:\n | {\n readonly cordis: Context;\n readonly service: DoomCordisSessionService;\n }\n | undefined;\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], (sessionContext) => {\n const service = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const binding = { cordis: sessionContext, service };\n activeCordisSession = binding;\n sessionContext.effect(\n () => () => {\n if (activeCordisSession === binding) activeCordisSession = undefined;\n },\n `${PACKAGE_SOURCE}/cordis-session`,\n );\n });\n const coordinatorFor = (ctx: ExtensionContext): DoomReadinessCoordinator => {\n const cordisSession = activeCordisSession;\n const sessionId = ctx.sessionManager.getSessionId();\n const activeSessionMatches =\n cordisSession?.service.context.sessionManager === ctx.sessionManager &&\n cordisSession.service.sessionId === sessionId;\n const shared = activeSessionMatches ? readDoomReadinessCoordinator(cordisSession.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n const message = readinessNotificationMessage(notification);\n if (readinessNotificationContext?.hasUI) readinessNotificationContext.ui.notify(message, 'warning');\n else process.emitWarning(message);\n },\n });\n return standaloneReadiness;\n };\n const waitForSessionReadiness = async (ctx: ExtensionContext, signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Doom Team session initialization has not started.');\n if (readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale Pi session.');\n }\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!active || pending !== readinessHandle || readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale extension generation.');\n }\n };\n const readinessPi = new Proxy(pi, {\n get(target, property) {\n if (property === 'registerTool') {\n return (tool: RegisteredTool): void => {\n target.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, ctx) => {\n await waitForSessionReadiness(ctx, signal);\n return tool.execute(toolCallId, params, signal, onUpdate, ctx);\n },\n });\n };\n }\n if (property === 'registerCommand') {\n return (name: string, options: CommandOptions): void => {\n target.registerCommand(name, {\n ...options,\n handler: async (args, ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(args, ctx);\n },\n });\n };\n }\n if (property === 'registerShortcut') {\n return (shortcut: Parameters<ExtensionAPI['registerShortcut']>[0], options: ShortcutOptions): void => {\n target.registerShortcut(shortcut, {\n ...options,\n handler: async (ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(ctx);\n },\n });\n };\n }\n return boundPiValue(target, property);\n },\n });\n\n subagentTool.registerTool(readinessPi);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerSubagentLeaderContribution(requireDoomUiHub(uiContext)));\n\n const teamRuntime = teamChannel.createRuntime(readinessPi);\n cordis.effect(() => () => teamRuntime.dispose(), '@agimon-ai/doompi-team/channel');\n teamChannel.registerClient(readinessPi);\n\n // Attach before `ResultWatcher.start()`, which `session_start` drives.\n completionNotifier.attachHost(pi);\n cordis.effect(() => () => completionNotifier.dispose(), '@agimon-ai/doompi-team/completions');\n\n pollScheduler.start();\n cordis.effect(() => () => pollScheduler.stop(), '@agimon-ai/doompi-team/polling');\n\n asyncJobTracker.start();\n cordis.effect(() => () => asyncJobTracker.stop(), '@agimon-ai/doompi-team/jobs');\n\n let collaborationFiber: Fiber | undefined;\n let currentSessionJobs: ITrackedAsyncJobs | undefined;\n // The scope `ResultWatcher` is currently watching. See its start site in\n // the `session_start` handler for why the watcher is latched on this\n // rather than started once.\n let watchedScopeKey: string | undefined;\n const delegationBridge = createDelegationBridge({\n planner: spawnPlanner,\n management,\n waiter: subagentWaiter,\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n loadConfig: () => loadConfig().config,\n });\n const fablePlanBridge = createFablePlanBridge({\n spawner: asyncSubagentSpawner,\n waiter: subagentWaiter,\n management,\n policies: capabilityPolicies,\n report: (event, attributes) => {\n void telemetry?.recordEvent(event, attributes);\n },\n });\n cordis.effect(\n () => async () => {\n await collaborationFiber?.dispose();\n collaborationFiber = undefined;\n },\n '@agimon-ai/doompi-team/collaboration',\n );\n cordis.effect(\n () => () => {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n },\n '@agimon-ai/doompi-team/result-watcher',\n );\n\n const unregisterStaleRunReconciler = pollScheduler.register({\n id: 'stale-run-reconciler',\n // Crash detection, not status freshness - `AsyncJobTracker` owns that and\n // polls on its own 250ms. This subscriber only ever acts on a run whose\n // process is provably dead, so noticing that 2s later is invisible, while\n // running it 4x/second per active run was not: each pass is a status read,\n // a run-id resolve and a pid probe that a healthy child always discards.\n intervalMs: STALE_RUN_RECONCILE_INTERVAL_MS,\n run: async () => {\n let repaired = false;\n let hasActiveRun = false;\n for (const job of currentSessionJobs?.list() ?? []) {\n if (job.status && TERMINAL_ASYNC_JOB_STATES.has(job.status)) continue;\n hasActiveRun = true;\n // One pass, one `inspect()`. Calling `reconcile` and\n // `sweepOrphanedClaims` separately probed the same pid twice for the\n // same answer - see `IStaleRunReconciler.reconcileAndSweep`.\n const { reconcile: outcome, sweep } = staleRunReconciler.reconcileAndSweepAsync\n ? await staleRunReconciler.reconcileAndSweepAsync(job.runId)\n : staleRunReconciler.reconcileAndSweep(job.runId);\n if (outcome.repaired) {\n currentSessionJobs?.track(job.runId);\n repaired = true;\n }\n if (sweep.recovered.length > 0) repaired = true;\n }\n // An active runner is useful work for scheduling purposes: keeping\n // the shared scheduler at its floor prevents crash detection from\n // inheriting the idle five-second backoff ceiling.\n return repaired || hasActiveRun;\n },\n });\n cordis.effect(() => unregisterStaleRunReconciler, '@agimon-ai/doompi-team/stale-runs');\n // The orchestration addendum. Registered here rather than inside the\n // `subagent` tool's description because it is behavioural guidance, and it\n // has to land before the model decides whether to reach for the tool at\n // all - see `orchestratorPrompt.ts`. Read config per turn so toggling it\n // does not need a session restart; `loadConfig` is memoized on the file's\n // own mtime, so this is a stat, not a read.\n pi.on('before_agent_start', (event: { systemPrompt?: string }) => {\n if (!active || !shouldInjectOrchestratorPrompt(loadConfig().config)) return undefined;\n return { systemPrompt: appendOrchestratorPrompt(event.systemPrompt) };\n });\n\n const state: SlashCommandState = { baseCwd: undefined };\n registerSlashCommands(\n readinessPi,\n state,\n buildSlashCommandDeps(discovery, skills, spawnPlanner, asyncJobTracker, pollScheduler, management),\n );\n registerAgentListCommand(readinessPi, { discovery, skills, policies: capabilityPolicies });\n registerFleetCommand(readinessPi, {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n management,\n });\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerAgentStatus(pi, requireDoomUiHub(uiContext), {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n });\n });\n registerCompletionRenderer(pi);\n\n const retireSessionBindings = async (): Promise<Error | undefined> => {\n const errors: unknown[] = [];\n const previousCollaboration = collaborationFiber;\n collaborationFiber = undefined;\n try {\n await previousCollaboration?.dispose();\n } catch (error) {\n errors.push(error);\n }\n for (const cleanup of [\n () => capabilityPolicies.clear(),\n () => delegationBridge.abandonAll(),\n () => fablePlanBridge.abandonAll(),\n () => teamRuntime.dispose(),\n ]) {\n try {\n cleanup();\n } catch (error) {\n errors.push(error);\n }\n }\n currentSessionJobs = undefined;\n if (errors.length === 0) return undefined;\n if (errors.length === 1 && errors[0] instanceof Error) return errors[0];\n return new AggregateError(errors, 'Team session cleanup failed.');\n };\n\n // Bind the root session directly into the one intercom transport. Child\n // processes bind from the team environment written during spawn.\n pi.on('session_start', (_event, ctx: ExtensionContext) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort(new Error('Doom Team session initialization was superseded.'));\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n readinessSessionManager = ctx.sessionManager;\n readinessNotificationContext = ctx;\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_team.session_started', {\n 'team.root_session':\n resolveRootSessionId(ctx.sessionManager.getSessionId()) === ctx.sessionManager.getSessionId(),\n });\n // Before anything else: every scoped path helper reads this. A child\n // keeps the root inherited from its spawn environment, while a top-level\n // session falls back to its own Pi session id.\n const sessionId = ctx.sessionManager.getSessionId();\n const scope = createSessionScope(resolveRootSessionId(sessionId));\n setCurrentSessionScope(scope);\n state.baseCwd = ctx.cwd;\n if (watchedScopeKey !== undefined && watchedScopeKey !== scope.scopeKey) {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n }\n const retirement = retireSessionBindings();\n const coordinator = coordinatorFor(ctx);\n const ownsSession = (): boolean =>\n active &&\n ownGeneration === sessionGeneration &&\n readinessSessionManager === ctx.sessionManager &&\n !ownReadinessAbort.signal.aborted;\n\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Doom Team session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${sessionId}:${ownGeneration}`, async (signal) => {\n signal.throwIfAborted();\n const retirementError = await retirement;\n if (retirementError) throw retirementError;\n if (!ownsSession()) return { value: undefined };\n // Claim the scope for this process, so a later sweep can tell an\n // abandoned tree from a live one. Rewritten on every session_start\n // because /resume legitimately re-adopts a scope under a new process.\n await writeScopeOwnerAsync(scope);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n // Prune records whose process is gone, reap sibling scopes holding\n // nothing alive, and REPORT what is suspended. Nothing is restarted:\n // reopening a session must not silently spend tokens on stale work.\n const opened = await openScopeAsync(scope, {\n readStatusAsync: async (runId) =>\n management.statusAsync ? (await management.statusAsync(runId)).status : management.status(runId).status,\n });\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n if (opened.suspended.length > 0 && ctx.hasUI) {\n const message = await formatSuspendedRunsAsync(opened.suspended);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n ctx.ui.notify(message, 'info');\n }\n void activeTelemetry.recordEvent('doom_team.runs_restored', {\n 'team.suspended_count': opened.suspended.length,\n 'team.pruned_count': opened.pruned.length,\n 'team.reaped_count': opened.reaped,\n outcome: 'reported',\n });\n currentSessionJobs = asyncJobTracker.forSession(sessionId);\n // ResultWatcher needs the session scope, but a repeated start for the\n // same scope must not reset its in-flight claims.\n if (watchedScopeKey !== scope.scopeKey) {\n watchedScopeKey = scope.scopeKey;\n resultWatcher.start((result) =>\n currentSessionJobs?.get(result.runId) ? completionNotifier.deliver(result) : false,\n );\n }\n const parentModel = normalizeParentModel(ctx.model);\n const activeSession = activeCordisSession;\n const collaborationParent =\n activeSession?.service.context.sessionManager === ctx.sessionManager ? activeSession.cordis : cordis;\n const nextCollaboration = collaborationParent.plugin(teamCollaborationPlugin, {\n session: {\n sessionId,\n cwd: ctx.cwd,\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n forkSource: captureSessionForkSource(ctx.sessionManager, 'tool'),\n },\n delegation: delegationBridge,\n fablePlan: fablePlanBridge,\n policies: capabilityPolicies,\n observeDelegation: (observation) => recordDelegationObservation(activeTelemetry, observation),\n });\n collaborationFiber = nextCollaboration;\n await nextCollaboration.await();\n if (!ownsSession()) {\n await nextCollaboration.dispose();\n if (collaborationFiber === nextCollaboration) collaborationFiber = undefined;\n return { value: undefined };\n }\n teamRuntime.bindMainSession(sessionId);\n return { value: undefined };\n });\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n return undefined;\n });\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team runtime was disposed.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) await ownedReadiness.dispose();\n else if (pendingReadiness) await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n readinessNotificationContext = undefined;\n },\n '@agimon-ai/doompi-team/session-fence',\n );\n\n /**\n * Every reason suspends, with no exception for `reload`.\n *\n * Pi emits this for `quit`, `reload`, `new`, `resume` and `fork`. Treating\n * `reload` differently - keeping children alive because `/domains`, `/major-mode`\n * and `/profile` only reload the extension - would be the one case someone\n * has to remember, and the one that silently misbehaves if Pi adds a sixth\n * reason. Suspending uniformly costs a respawn on reload; restore continues\n * the child's own transcript rather than restarting its task.\n */\n let shutdownPromise: Promise<void> | undefined;\n const shutdownSession = async (event: { reason?: string }): Promise<void> => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team session ended.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n await Promise.allSettled([\n ...(pendingReadiness ? [pendingReadiness.then((handle) => handle.wait())] : []),\n ...(ownedReadiness ? [ownedReadiness.dispose()] : []),\n ]);\n const scope = tryCurrentSessionScope();\n const suspensionPromise = scope\n ? suspendScopeRuns({\n scope,\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n readStatus: (runId) => management.status(runId).status,\n })\n : Promise.resolve(undefined);\n let suspension: Awaited<ReturnType<typeof suspendScopeRuns>> | undefined;\n try {\n suspension = await suspensionPromise;\n await telemetry?.recordEvent('doom_team.session_finished', {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n 'team.suspended_count': suspension?.suspended.length ?? 0,\n 'team.unstoppable_count': suspension?.unstoppable.length ?? 0,\n outcome: suspension?.unstoppable.length ? 'degraded' : 'suspended',\n });\n } catch (error) {\n await telemetry?.recordError('doom_team.session_shutdown_failed', error, {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n });\n } finally {\n await telemetry?.shutdown();\n telemetry = undefined;\n }\n };\n pi.on('session_shutdown', (event: { reason?: string }) => {\n shutdownPromise ??= shutdownSession(event);\n return shutdownPromise;\n });\n\n return runtime;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["loadConfig","createDoomTelemetry","createTeamExtensionRuntime","DOOM_CORDIS_SESSION_SERVICE","DOOM_MCP_TOOL_RESOLVER_SERVICE","requireDoomMcpToolResolver","DOOM_CONTEXT_CONTRIBUTIONS_SERVICE","requireDoomContextContributions","formatTeamContextSnapshot","readActiveTeamSnapshot","readDoomReadinessCoordinator","createDoomReadinessCoordinator","DOOM_UI_HUB_SERVICE","registerSubagentLeaderContribution","requireDoomUiHub","createDelegationBridge","createFablePlanBridge","TERMINAL_ASYNC_JOB_STATES","shouldInjectOrchestratorPrompt","appendOrchestratorPrompt","registerAgentStatus","resolveRootSessionId","createSessionScope","writeScopeOwnerAsync","openScopeAsync","formatSuspendedRunsAsync","normalizeParentModel","teamCollaborationPlugin","authenticatedModelInfos","captureSessionForkSource","tryCurrentSessionScope","suspendScopeRuns"],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Install the Team feature into one package-local Cordis root.\n *\n * The standard Pi factory owns that root and disposes it when Pi emits\n * `session_shutdown`. Each factory invocation therefore creates fresh session\n * state; no process-global container or replacement-root handshake participates\n * in reload. Long-lived services are registered as Cordis effects, and stale\n * asynchronous session-start continuations are fenced by a generation token.\n */\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport {\n DOOM_CONTEXT_CONTRIBUTIONS_SERVICE,\n requireDoomContextContributions,\n} from '@agimon-ai/doompi-extension-contracts/context-contributions';\nimport {\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n requireDoomMcpToolResolver,\n} from '@agimon-ai/doompi-extension-contracts/mcp-tool-resolver';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context, Fiber } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n registerSlashCommands,\n type SlashCommandDeps,\n type SlashCommandState,\n} from '../../commands/slash/slashCommands.ts';\nimport { loadConfig } from '../../extensions/config.ts';\nimport { createDelegationBridge } from '../../extensions/delegationBridge.ts';\nimport { createFablePlanBridge } from '../../extensions/fablePlanBridge.ts';\nimport type { IManagementActions } from '../../extensions/managementActions.ts';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from '../../extensions/orchestratorPrompt.ts';\nimport { captureSessionForkSource, type ISpawnPlanner } from '../../extensions/spawnPlan.ts';\nimport type { ISkillDiscoveryService } from '../../services/agents/skills.ts';\nimport type { IAgentDiscoveryService } from '../../services/agents/types.ts';\nimport { formatTeamContextSnapshot, readActiveTeamSnapshot } from '../../services/api/teamSnapshot.ts';\nimport {\n type IAsyncJobTracker,\n type ITrackedAsyncJobs,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../../services/runs/background/asyncJobTracker.ts';\nimport { openScopeAsync, suspendScopeRuns } from '../../services/runs/registry/sessionLifecycle.ts';\nimport { formatSuspendedRunsAsync } from '../../services/runs/registry/suspendedRuns.ts';\nimport { normalizeParentModel } from '../../services/runs/shared/modelFallback.ts';\nimport { authenticatedModelInfos } from '../../shared/modelResolution.ts';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../../shared/paths.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\nimport { writeScopeOwnerAsync } from '../../shared/scopeOwner.ts';\nimport { registerCompletionRenderer } from '../../tui/completionNotice.ts';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from '../../tui/register.ts';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration.ts';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime.ts';\n\n/** See the subscriber's own comment for why crash detection does not need the 250ms floor. */\nconst STALE_RUN_RECONCILE_INTERVAL_MS = 2_000;\nconst SESSION_SHUTDOWN_REASON_FALLBACK = 'unknown';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-team';\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\n\nfunction boundPiValue(target: ExtensionAPI, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction readinessNotificationMessage(notification: DoomReadinessNotification): string {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n return `${notification.packageId} initialization ${notification.state}: ${detail}`;\n}\n\nfunction buildSlashCommandDeps(\n discovery: IAgentDiscoveryService,\n skills: ISkillDiscoveryService,\n planner: ISpawnPlanner,\n tracker: IAsyncJobTracker,\n scheduler: IPollScheduler,\n management: IManagementActions,\n): SlashCommandDeps {\n return {\n spawnPlanner: planner,\n tracker,\n scheduler,\n discovery,\n skills,\n management,\n loadConfig: () => loadConfig().config,\n };\n}\n\nfunction recordDelegationObservation(telemetry: DoomTelemetry, observation: TeamDelegationObservation): void {\n if (observation.kind === 'requested') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_requested', {\n 'agent.name': event.agent,\n 'task.id': event.taskId,\n mode: event.runMode ?? 'foreground',\n });\n } else if (observation.kind === 'started') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.child_started', { 'run.id': event.runId, outcome: 'started' });\n } else if (observation.kind === 'updated') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_updated', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n 'team.token_count': event.tokens ?? 0,\n outcome: event.status ?? 'updated',\n });\n } else if (observation.kind === 'finished') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_finished', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n outcome: event.status,\n });\n } else {\n void telemetry.recordEvent('doom_team.delegation_cancelled', { outcome: 'cancelled' });\n }\n}\n\n/**\n * The extension factory pi's loader calls, exported as the module default\n * (see the override this file carries in `vibe-lint.config.yaml`). This is an\n * ESM `.ts` module, so it CANNOT use the `export =` form that\n * `subagentPromptRuntimeEntry.cts` is required to use - that file is `.cts`\n * and is resolved by raw path, this one is resolved as a package subpath and\n * matches the `export default` convention every sibling extension in this repo\n * already uses (`doom-task`, `doom-file-edit`, `doom-pi-ui`).\n */\nexport function installTeamRuntime(cordis: Context, pi: ExtensionAPI): TeamExtensionRuntime {\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-team',\n packageName: '@agimon-ai/doompi-team',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n const reportConcurrencyEvent = (event: string, attributes: Record<string, unknown>): void => {\n void telemetry?.recordEvent(event, attributes);\n };\n cordis.effect(\n () => async () => {\n await telemetry?.shutdown();\n telemetry = undefined;\n },\n '@agimon-ai/doompi-team/telemetry',\n );\n const runtime = createTeamExtensionRuntime(reportConcurrencyEvent);\n const {\n subagentTool,\n teamChannel,\n pollScheduler,\n asyncJobTracker,\n subagentWaiter,\n asyncSubagentSpawner,\n discovery,\n skills,\n spawnPlanner,\n completionNotifier,\n resultWatcher,\n staleRunReconciler,\n management,\n capabilityPolicies,\n mcpToolResolver,\n } = runtime;\n\n let active = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let readinessSessionManager: object | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n let readinessNotificationContext: ExtensionContext | undefined;\n let activeCordisSession:\n | {\n readonly cordis: Context;\n readonly service: DoomCordisSessionService;\n }\n | undefined;\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], (sessionContext) => {\n const service = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const binding = { cordis: sessionContext, service };\n activeCordisSession = binding;\n sessionContext.inject([DOOM_MCP_TOOL_RESOLVER_SERVICE], (resolverContext) =>\n mcpToolResolver.bind(requireDoomMcpToolResolver(resolverContext)),\n );\n sessionContext.inject([DOOM_CONTEXT_CONTRIBUTIONS_SERVICE], (contributionContext) => {\n const registration = requireDoomContextContributions(contributionContext).register({\n source: PACKAGE_SOURCE,\n id: 'runtime',\n label: 'Team',\n order: 200,\n snapshot: () => formatTeamContextSnapshot(readActiveTeamSnapshot()),\n });\n return () => registration.dispose();\n });\n sessionContext.effect(\n () => () => {\n if (activeCordisSession === binding) activeCordisSession = undefined;\n },\n `${PACKAGE_SOURCE}/cordis-session`,\n );\n });\n const coordinatorFor = (ctx: ExtensionContext): DoomReadinessCoordinator => {\n const cordisSession = activeCordisSession;\n const sessionId = ctx.sessionManager.getSessionId();\n const activeSessionMatches =\n cordisSession?.service.context.sessionManager === ctx.sessionManager &&\n cordisSession.service.sessionId === sessionId;\n const shared = activeSessionMatches ? readDoomReadinessCoordinator(cordisSession.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n const message = readinessNotificationMessage(notification);\n if (readinessNotificationContext?.hasUI) readinessNotificationContext.ui.notify(message, 'warning');\n else process.emitWarning(message);\n },\n });\n return standaloneReadiness;\n };\n const waitForSessionReadiness = async (ctx: ExtensionContext, signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Doom Team session initialization has not started.');\n if (readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale Pi session.');\n }\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!active || pending !== readinessHandle || readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale extension generation.');\n }\n };\n const readinessPi = new Proxy(pi, {\n get(target, property) {\n if (property === 'registerTool') {\n return (tool: RegisteredTool): void => {\n target.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, ctx) => {\n await waitForSessionReadiness(ctx, signal);\n return tool.execute(toolCallId, params, signal, onUpdate, ctx);\n },\n });\n };\n }\n if (property === 'registerCommand') {\n return (name: string, options: CommandOptions): void => {\n target.registerCommand(name, {\n ...options,\n handler: async (args, ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(args, ctx);\n },\n });\n };\n }\n if (property === 'registerShortcut') {\n return (shortcut: Parameters<ExtensionAPI['registerShortcut']>[0], options: ShortcutOptions): void => {\n target.registerShortcut(shortcut, {\n ...options,\n handler: async (ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(ctx);\n },\n });\n };\n }\n return boundPiValue(target, property);\n },\n });\n\n subagentTool.registerTool(readinessPi);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerSubagentLeaderContribution(requireDoomUiHub(uiContext)));\n\n const teamRuntime = teamChannel.createRuntime(readinessPi);\n cordis.effect(() => () => teamRuntime.dispose(), '@agimon-ai/doompi-team/channel');\n teamChannel.registerClient(readinessPi);\n\n // Attach before `ResultWatcher.start()`, which `session_start` drives.\n completionNotifier.attachHost(pi);\n cordis.effect(() => () => completionNotifier.dispose(), '@agimon-ai/doompi-team/completions');\n\n pollScheduler.start();\n cordis.effect(() => () => pollScheduler.stop(), '@agimon-ai/doompi-team/polling');\n\n asyncJobTracker.start();\n cordis.effect(() => () => asyncJobTracker.stop(), '@agimon-ai/doompi-team/jobs');\n\n let collaborationFiber: Fiber | undefined;\n let currentSessionJobs: ITrackedAsyncJobs | undefined;\n // The scope `ResultWatcher` is currently watching. See its start site in\n // the `session_start` handler for why the watcher is latched on this\n // rather than started once.\n let watchedScopeKey: string | undefined;\n const delegationBridge = createDelegationBridge({\n planner: spawnPlanner,\n management,\n waiter: subagentWaiter,\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n loadConfig: () => loadConfig().config,\n });\n const fablePlanBridge = createFablePlanBridge({\n spawner: asyncSubagentSpawner,\n waiter: subagentWaiter,\n management,\n policies: capabilityPolicies,\n report: (event, attributes) => {\n void telemetry?.recordEvent(event, attributes);\n },\n });\n cordis.effect(\n () => async () => {\n await collaborationFiber?.dispose();\n collaborationFiber = undefined;\n },\n '@agimon-ai/doompi-team/collaboration',\n );\n cordis.effect(\n () => () => {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n },\n '@agimon-ai/doompi-team/result-watcher',\n );\n\n const unregisterStaleRunReconciler = pollScheduler.register({\n id: 'stale-run-reconciler',\n // Crash detection, not status freshness - `AsyncJobTracker` owns that and\n // polls on its own 250ms. This subscriber only ever acts on a run whose\n // process is provably dead, so noticing that 2s later is invisible, while\n // running it 4x/second per active run was not: each pass is a status read,\n // a run-id resolve and a pid probe that a healthy child always discards.\n intervalMs: STALE_RUN_RECONCILE_INTERVAL_MS,\n run: async () => {\n let repaired = false;\n let hasActiveRun = false;\n for (const job of currentSessionJobs?.list() ?? []) {\n if (job.status && TERMINAL_ASYNC_JOB_STATES.has(job.status)) continue;\n hasActiveRun = true;\n // One pass, one `inspect()`. Calling `reconcile` and\n // `sweepOrphanedClaims` separately probed the same pid twice for the\n // same answer - see `IStaleRunReconciler.reconcileAndSweep`.\n const { reconcile: outcome, sweep } = staleRunReconciler.reconcileAndSweepAsync\n ? await staleRunReconciler.reconcileAndSweepAsync(job.runId)\n : staleRunReconciler.reconcileAndSweep(job.runId);\n if (outcome.repaired) {\n currentSessionJobs?.track(job.runId);\n repaired = true;\n }\n if (sweep.recovered.length > 0) repaired = true;\n }\n // An active runner is useful work for scheduling purposes: keeping\n // the shared scheduler at its floor prevents crash detection from\n // inheriting the idle five-second backoff ceiling.\n return repaired || hasActiveRun;\n },\n });\n cordis.effect(() => unregisterStaleRunReconciler, '@agimon-ai/doompi-team/stale-runs');\n // The orchestration addendum. Registered here rather than inside the\n // `subagent` tool's description because it is behavioural guidance, and it\n // has to land before the model decides whether to reach for the tool at\n // all - see `orchestratorPrompt.ts`. Read config per turn so toggling it\n // does not need a session restart; `loadConfig` is memoized on the file's\n // own mtime, so this is a stat, not a read.\n pi.on('before_agent_start', (event: { systemPrompt?: string }) => {\n if (!active || !shouldInjectOrchestratorPrompt(loadConfig().config)) return undefined;\n return { systemPrompt: appendOrchestratorPrompt(event.systemPrompt) };\n });\n\n const state: SlashCommandState = { baseCwd: undefined };\n registerSlashCommands(\n readinessPi,\n state,\n buildSlashCommandDeps(discovery, skills, spawnPlanner, asyncJobTracker, pollScheduler, management),\n );\n registerAgentListCommand(readinessPi, { discovery, skills, policies: capabilityPolicies });\n registerFleetCommand(readinessPi, {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n management,\n });\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerAgentStatus(pi, requireDoomUiHub(uiContext), {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n });\n });\n registerCompletionRenderer(pi);\n\n const retireSessionBindings = async (): Promise<Error | undefined> => {\n const errors: unknown[] = [];\n const previousCollaboration = collaborationFiber;\n collaborationFiber = undefined;\n try {\n await previousCollaboration?.dispose();\n } catch (error) {\n errors.push(error);\n }\n for (const cleanup of [\n () => capabilityPolicies.clear(),\n () => delegationBridge.abandonAll(),\n () => fablePlanBridge.abandonAll(),\n () => teamRuntime.dispose(),\n ]) {\n try {\n cleanup();\n } catch (error) {\n errors.push(error);\n }\n }\n currentSessionJobs = undefined;\n if (errors.length === 0) return undefined;\n if (errors.length === 1 && errors[0] instanceof Error) return errors[0];\n return new AggregateError(errors, 'Team session cleanup failed.');\n };\n\n // Bind the root session directly into the one intercom transport. Child\n // processes bind from the team environment written during spawn.\n pi.on('session_start', (_event, ctx: ExtensionContext) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort(new Error('Doom Team session initialization was superseded.'));\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n readinessSessionManager = ctx.sessionManager;\n readinessNotificationContext = ctx;\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_team.session_started', {\n 'team.root_session':\n resolveRootSessionId(ctx.sessionManager.getSessionId()) === ctx.sessionManager.getSessionId(),\n });\n // Before anything else: every scoped path helper reads this. A child\n // keeps the root inherited from its spawn environment, while a top-level\n // session falls back to its own Pi session id.\n const sessionId = ctx.sessionManager.getSessionId();\n const scope = createSessionScope(resolveRootSessionId(sessionId));\n setCurrentSessionScope(scope);\n state.baseCwd = ctx.cwd;\n if (watchedScopeKey !== undefined && watchedScopeKey !== scope.scopeKey) {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n }\n const retirement = retireSessionBindings();\n const coordinator = coordinatorFor(ctx);\n const ownsSession = (): boolean =>\n active &&\n ownGeneration === sessionGeneration &&\n readinessSessionManager === ctx.sessionManager &&\n !ownReadinessAbort.signal.aborted;\n\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Doom Team session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${sessionId}:${ownGeneration}`, async (signal) => {\n signal.throwIfAborted();\n const retirementError = await retirement;\n if (retirementError) throw retirementError;\n if (!ownsSession()) return { value: undefined };\n // Claim the scope for this process, so a later sweep can tell an\n // abandoned tree from a live one. Rewritten on every session_start\n // because /resume legitimately re-adopts a scope under a new process.\n await writeScopeOwnerAsync(scope);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n // Prune records whose process is gone, reap sibling scopes holding\n // nothing alive, and REPORT what is suspended. Nothing is restarted:\n // reopening a session must not silently spend tokens on stale work.\n const opened = await openScopeAsync(scope, {\n readStatusAsync: async (runId) =>\n management.statusAsync ? (await management.statusAsync(runId)).status : management.status(runId).status,\n });\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n if (opened.suspended.length > 0 && ctx.hasUI) {\n const message = await formatSuspendedRunsAsync(opened.suspended);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n ctx.ui.notify(message, 'info');\n }\n void activeTelemetry.recordEvent('doom_team.runs_restored', {\n 'team.suspended_count': opened.suspended.length,\n 'team.pruned_count': opened.pruned.length,\n 'team.reaped_count': opened.reaped,\n outcome: 'reported',\n });\n currentSessionJobs = asyncJobTracker.forSession(sessionId);\n // ResultWatcher needs the session scope, but a repeated start for the\n // same scope must not reset its in-flight claims.\n if (watchedScopeKey !== scope.scopeKey) {\n watchedScopeKey = scope.scopeKey;\n resultWatcher.start((result) =>\n currentSessionJobs?.get(result.runId) ? completionNotifier.deliver(result) : false,\n );\n }\n const parentModel = normalizeParentModel(ctx.model);\n const activeSession = activeCordisSession;\n const collaborationParent =\n activeSession?.service.context.sessionManager === ctx.sessionManager ? activeSession.cordis : cordis;\n const nextCollaboration = collaborationParent.plugin(teamCollaborationPlugin, {\n session: {\n sessionId,\n cwd: ctx.cwd,\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n forkSource: captureSessionForkSource(ctx.sessionManager, 'tool'),\n },\n delegation: delegationBridge,\n fablePlan: fablePlanBridge,\n policies: capabilityPolicies,\n observeDelegation: (observation) => recordDelegationObservation(activeTelemetry, observation),\n });\n collaborationFiber = nextCollaboration;\n await nextCollaboration.await();\n if (!ownsSession()) {\n await nextCollaboration.dispose();\n if (collaborationFiber === nextCollaboration) collaborationFiber = undefined;\n return { value: undefined };\n }\n teamRuntime.bindMainSession(sessionId);\n return { value: undefined };\n });\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n return undefined;\n });\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team runtime was disposed.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) await ownedReadiness.dispose();\n else if (pendingReadiness) await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n readinessNotificationContext = undefined;\n },\n '@agimon-ai/doompi-team/session-fence',\n );\n\n /**\n * Every reason suspends, with no exception for `reload`.\n *\n * Pi emits this for `quit`, `reload`, `new`, `resume` and `fork`. Treating\n * `reload` differently - keeping children alive because `/domains`, `/major-mode`\n * and `/profile` only reload the extension - would be the one case someone\n * has to remember, and the one that silently misbehaves if Pi adds a sixth\n * reason. Suspending uniformly costs a respawn on reload; restore continues\n * the child's own transcript rather than restarting its task.\n */\n let shutdownPromise: Promise<void> | undefined;\n const shutdownSession = async (event: { reason?: string }): Promise<void> => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team session ended.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n await Promise.allSettled([\n ...(pendingReadiness ? [pendingReadiness.then((handle) => handle.wait())] : []),\n ...(ownedReadiness ? [ownedReadiness.dispose()] : []),\n ]);\n const scope = tryCurrentSessionScope();\n const suspensionPromise = scope\n ? suspendScopeRuns({\n scope,\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n readStatus: (runId) => management.status(runId).status,\n })\n : Promise.resolve(undefined);\n let suspension: Awaited<ReturnType<typeof suspendScopeRuns>> | undefined;\n try {\n suspension = await suspensionPromise;\n await telemetry?.recordEvent('doom_team.session_finished', {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n 'team.suspended_count': suspension?.suspended.length ?? 0,\n 'team.unstoppable_count': suspension?.unstoppable.length ?? 0,\n outcome: suspension?.unstoppable.length ? 'degraded' : 'suspended',\n });\n } catch (error) {\n await telemetry?.recordError('doom_team.session_shutdown_failed', error, {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n });\n } finally {\n await telemetry?.shutdown();\n telemetry = undefined;\n }\n };\n pi.on('session_shutdown', (event: { reason?: string }) => {\n shutdownPromise ??= shutdownSession(event);\n return shutdownPromise;\n });\n\n return runtime;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createSessionScope as e,init_paths as t,setCurrentSessionScope as n,tryCurrentSessionScope as r}from"../../shared/paths.mjs";import{authenticatedModelInfos as i}from"../../shared/modelResolution.mjs";import{normalizeParentModel as a}from"../../services/runs/shared/modelFallback.mjs";import{captureSessionForkSource as o}from"../../extensions/spawnPlan.mjs";import{TERMINAL_ASYNC_JOB_STATES as s}from"../asyncJobTracker.mjs";import{init_asyncJobTracker as c}from"../../services/runs/background/asyncJobTracker.mjs";import{registerSlashCommands as l}from"../../commands/slash/slashCommands.mjs";import{loadConfig as u}from"../../extensions/config.mjs";import{createDelegationBridge as d}from"../../extensions/delegationBridge.mjs";import{init_scopeOwner as f,writeScopeOwnerAsync as ee}from"../scopeOwner.mjs";import{createFablePlanBridge as p}from"../../extensions/fablePlanBridge.mjs";import{appendOrchestratorPrompt as m,shouldInjectOrchestratorPrompt as h}from"../../extensions/orchestratorPrompt.mjs";import{formatSuspendedRunsAsync as te}from"../suspendedRuns.mjs";import"../../services/runs/registry/suspendedRuns.mjs";import{openScopeAsync as ne,suspendScopeRuns as g}from"../../services/runs/registry/sessionLifecycle.mjs";import"../../shared/scopeOwner.mjs";import{registerCompletionRenderer as re}from"../../tui/completionNotice.mjs";import{registerAgentListCommand as ie,registerAgentStatus as ae,registerFleetCommand as oe,registerSubagentLeaderContribution as se}from"../../tui/register.mjs";import{teamCollaborationPlugin as ce}from"./collaboration.mjs";import{createTeamExtensionRuntime as le}from"./teamRuntime.mjs";import{resolveRootSessionId as _}from"@agimon-ai/doompi-extension-contracts/child-process";import{DOOM_CORDIS_SESSION_SERVICE as v}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{createDoomReadinessCoordinator as ue,readDoomReadinessCoordinator as de}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as y,requireDoomUiHub as b}from"@agimon-ai/doompi-extension-contracts/ui-hub";import{createDoomTelemetry as fe}from"@agimon-ai/doompi-telemetry";c(),t(),f();const x=`unknown`,S=`@agimon-ai/doompi-team`;function pe(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function me(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`;return`${e.packageId} initialization ${e.state}: ${n}`}function he(e,t,n,r,i,a){return{spawnPlanner:n,tracker:r,scheduler:i,discovery:e,skills:t,management:a,loadConfig:()=>u().config}}function ge(e,t){if(t.kind===`requested`){let{event:n}=t;e.recordEvent(`doom_team.delegation_requested`,{"agent.name":n.agent,"task.id":n.taskId,mode:n.runMode??`foreground`})}else if(t.kind===`started`){let{event:n}=t;e.recordEvent(`doom_team.child_started`,{"run.id":n.runId,outcome:`started`})}else if(t.kind===`updated`){let{event:n}=t;e.recordEvent(`doom_team.delegation_updated`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,"team.token_count":n.tokens??0,outcome:n.status??`updated`})}else if(t.kind===`finished`){let{event:n}=t;e.recordEvent(`doom_team.delegation_finished`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,outcome:n.status})}else e.recordEvent(`doom_team.delegation_cancelled`,{outcome:`cancelled`})}function C(t,c){let f,C=e=>(f??=fe({serviceName:`doom-team`,packageName:`@agimon-ai/doompi-team`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),f),_e=(e,t)=>{f?.recordEvent(e,t)};t.effect(()=>async()=>{await f?.shutdown(),f=void 0},`@agimon-ai/doompi-team/telemetry`);let w=le(_e),{subagentTool:ve,teamChannel:T,pollScheduler:E,asyncJobTracker:D,subagentWaiter:O,asyncSubagentSpawner:ye,discovery:k,skills:A,spawnPlanner:j,completionNotifier:M,resultWatcher:N,staleRunReconciler:P,management:F,capabilityPolicies:I}=w,L=!0,R=0,z,B,V,H,U,W;t.inject([v],e=>{let t={cordis:e,service:e.get(v)};W=t,e.effect(()=>()=>{W===t&&(W=void 0)},`${S}/cordis-session`)});let be=e=>{let t=W,n=e.sessionManager.getSessionId();return(t?.service.context.sessionManager===e.sessionManager&&t.service.sessionId===n?de(t.cordis):void 0)||(H??=ue({notify:e=>{let t=me(e);U?.hasUI?U.ui.notify(t,`warning`):process.emitWarning(t)}}),H)},G=async(e,t)=>{t?.throwIfAborted();let n=B;if(!n)throw Error(`Doom Team session initialization has not started.`);if(V!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale Pi session.`);let r=await n;if(t?.throwIfAborted(),await r.wait(t?{signal:t}:void 0),!L||n!==B||V!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale extension generation.`)},K=new Proxy(c,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await G(a,r),t.execute(e,n,r,i,a))})}:t===`registerCommand`?(t,n)=>{e.registerCommand(t,{...n,handler:async(e,t)=>(await G(t),n.handler(e,t))})}:t===`registerShortcut`?(t,n)=>{e.registerShortcut(t,{...n,handler:async e=>(await G(e),n.handler(e))})}:pe(e,t)}});ve.registerTool(K),t.inject([y],e=>se(b(e)));let q=T.createRuntime(K);t.effect(()=>()=>q.dispose(),`@agimon-ai/doompi-team/channel`),T.registerClient(K),M.attachHost(c),t.effect(()=>()=>M.dispose(),`@agimon-ai/doompi-team/completions`),E.start(),t.effect(()=>()=>E.stop(),`@agimon-ai/doompi-team/polling`),D.start(),t.effect(()=>()=>D.stop(),`@agimon-ai/doompi-team/jobs`);let J,Y,X,Z=d({planner:j,management:F,waiter:O,scheduler:E,tracker:D,loadConfig:()=>u().config}),Q=p({spawner:ye,waiter:O,management:F,policies:I,report:(e,t)=>{f?.recordEvent(e,t)}});t.effect(()=>async()=>{await J?.dispose(),J=void 0},`@agimon-ai/doompi-team/collaboration`),t.effect(()=>()=>{N.stop(),X=void 0},`@agimon-ai/doompi-team/result-watcher`);let xe=E.register({id:`stale-run-reconciler`,intervalMs:2e3,run:async()=>{let e=!1,t=!1;for(let n of Y?.list()??[]){if(n.status&&s.has(n.status))continue;t=!0;let{reconcile:r,sweep:i}=P.reconcileAndSweepAsync?await P.reconcileAndSweepAsync(n.runId):P.reconcileAndSweep(n.runId);r.repaired&&(Y?.track(n.runId),e=!0),i.recovered.length>0&&(e=!0)}return e||t}});t.effect(()=>xe,`@agimon-ai/doompi-team/stale-runs`),c.on(`before_agent_start`,e=>{if(!(!L||!h(u().config)))return{systemPrompt:m(e.systemPrompt)}});let Se={baseCwd:void 0};l(K,Se,he(k,A,j,D,E,F)),ie(K,{discovery:k,skills:A,policies:I}),oe(K,{scheduler:E,tracker:D,management:F}),t.inject([y],e=>ae(c,b(e),{scheduler:E,tracker:D})),re(c);let Ce=async()=>{let e=[],t=J;J=void 0;try{await t?.dispose()}catch(t){e.push(t)}for(let t of[()=>I.clear(),()=>Z.abandonAll(),()=>Q.abandonAll(),()=>q.dispose()])try{t()}catch(t){e.push(t)}if(Y=void 0,e.length!==0)return e.length===1&&e[0]instanceof Error?e[0]:AggregateError(e,`Team session cleanup failed.`)};c.on(`session_start`,(r,s)=>{if(!L)return;let c=++R,l=B;z?.abort(Error(`Doom Team session initialization was superseded.`));let u=new AbortController;z=u,V=s.sessionManager,U=s;let d=C(s);d.recordEvent(`doom_team.session_started`,{"team.root_session":_(s.sessionManager.getSessionId())===s.sessionManager.getSessionId()});let f=s.sessionManager.getSessionId(),p=e(_(f));n(p),Se.baseCwd=s.cwd,X!==void 0&&X!==p.scopeKey&&(N.stop(),X=void 0);let m=Ce(),h=be(s),g=()=>L&&c===R&&V===s.sessionManager&&!u.signal.aborted;B=(async()=>{if(l&&await Promise.allSettled([l.then(e=>e.wait())]),!g())throw Error(`Doom Team session initialization was superseded.`);return h.start(S,`${f}:${c}`,async e=>{e.throwIfAborted();let n=await m;if(n)throw n;if(!g()||(await ee(p),e.throwIfAborted(),!g()))return{value:void 0};let r=await ne(p,{readStatusAsync:async e=>F.statusAsync?(await F.statusAsync(e)).status:F.status(e).status});if(e.throwIfAborted(),!g())return{value:void 0};if(r.suspended.length>0&&s.hasUI){let t=await te(r.suspended);if(e.throwIfAborted(),!g())return{value:void 0};s.ui.notify(t,`info`)}d.recordEvent(`doom_team.runs_restored`,{"team.suspended_count":r.suspended.length,"team.pruned_count":r.pruned.length,"team.reaped_count":r.reaped,outcome:`reported`}),Y=D.forSession(f),X!==p.scopeKey&&(X=p.scopeKey,N.start(e=>Y?.get(e.runId)?M.deliver(e):!1));let c=a(s.model),l=W,u=(l?.service.context.sessionManager===s.sessionManager?l.cordis:t).plugin(ce,{session:{sessionId:f,cwd:s.cwd,availableModels:i(s.modelRegistry),...c?{parentModel:c}:{},forkSource:o(s.sessionManager,`tool`)},delegation:Z,fablePlan:Q,policies:I,observeDelegation:e=>ge(d,e)});return J=u,await u.await(),g()?(q.bindMainSession(f),{value:void 0}):(await u.dispose(),J===u&&(J=void 0),{value:void 0})})})(),Promise.allSettled([B.then(e=>e.wait())])}),t.effect(()=>async()=>{L=!1,R+=1;let e=B;B=void 0,V=void 0,z?.abort(Error(`Doom Team runtime was disposed.`)),z=void 0;let t=H;H=void 0,t?await t.dispose():e&&await Promise.allSettled([e.then(e=>e.wait())]),U=void 0},`@agimon-ai/doompi-team/session-fence`);let $,we=async e=>{L=!1,R+=1;let t=B;B=void 0,V=void 0,z?.abort(Error(`Doom Team session ended.`)),z=void 0;let n=H;H=void 0,await Promise.allSettled([...t?[t.then(e=>e.wait())]:[],...n?[n.dispose()]:[]]);let i=r(),a=i?g({scope:i,reason:e.reason??x,readStatus:e=>F.status(e).status}):Promise.resolve(void 0),o;try{o=await a,await f?.recordEvent(`doom_team.session_finished`,{reason:e.reason??x,"team.suspended_count":o?.suspended.length??0,"team.unstoppable_count":o?.unstoppable.length??0,outcome:o?.unstoppable.length?`degraded`:`suspended`})}catch(t){await f?.recordError(`doom_team.session_shutdown_failed`,t,{reason:e.reason??x})}finally{await f?.shutdown(),f=void 0}};return c.on(`session_shutdown`,e=>($??=we(e),$)),w}export{C as installTeamRuntime};
|
|
1
|
+
import{createSessionScope as e,init_paths as t,setCurrentSessionScope as n,tryCurrentSessionScope as r}from"../../shared/paths.mjs";import{formatTeamContextSnapshot as i,readActiveTeamSnapshot as a}from"../../services/api/teamSnapshot.mjs";import{authenticatedModelInfos as o}from"../../shared/modelResolution.mjs";import{normalizeParentModel as ee}from"../../services/runs/shared/modelFallback.mjs";import{captureSessionForkSource as te}from"../../extensions/spawnPlan.mjs";import{TERMINAL_ASYNC_JOB_STATES as s}from"../asyncJobTracker.mjs";import{init_asyncJobTracker as c}from"../../services/runs/background/asyncJobTracker.mjs";import{registerSlashCommands as l}from"../../commands/slash/slashCommands.mjs";import{loadConfig as u}from"../../extensions/config.mjs";import{createDelegationBridge as d}from"../../extensions/delegationBridge.mjs";import{init_scopeOwner as f,writeScopeOwnerAsync as ne}from"../scopeOwner.mjs";import{createFablePlanBridge as p}from"../../extensions/fablePlanBridge.mjs";import{appendOrchestratorPrompt as m,shouldInjectOrchestratorPrompt as re}from"../../extensions/orchestratorPrompt.mjs";import{formatSuspendedRunsAsync as ie}from"../suspendedRuns.mjs";import"../../services/runs/registry/suspendedRuns.mjs";import{openScopeAsync as ae,suspendScopeRuns as oe}from"../../services/runs/registry/sessionLifecycle.mjs";import"../../shared/scopeOwner.mjs";import{registerCompletionRenderer as se}from"../../tui/completionNotice.mjs";import{registerAgentListCommand as ce,registerAgentStatus as le,registerFleetCommand as ue,registerSubagentLeaderContribution as de}from"../../tui/register.mjs";import{teamCollaborationPlugin as fe}from"./collaboration.mjs";import{createTeamExtensionRuntime as pe}from"./teamRuntime.mjs";import{resolveRootSessionId as h}from"@agimon-ai/doompi-extension-contracts/child-process";import{DOOM_CORDIS_SESSION_SERVICE as g}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_CONTEXT_CONTRIBUTIONS_SERVICE as me,requireDoomContextContributions as he}from"@agimon-ai/doompi-extension-contracts/context-contributions";import{DOOM_MCP_TOOL_RESOLVER_SERVICE as ge,requireDoomMcpToolResolver as _e}from"@agimon-ai/doompi-extension-contracts/mcp-tool-resolver";import{createDoomReadinessCoordinator as ve,readDoomReadinessCoordinator as ye}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as _,requireDoomUiHub as v}from"@agimon-ai/doompi-extension-contracts/ui-hub";import{createDoomTelemetry as be}from"@agimon-ai/doompi-telemetry";c(),t(),f();const y=`unknown`,b=`@agimon-ai/doompi-team`;function xe(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function Se(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`;return`${e.packageId} initialization ${e.state}: ${n}`}function Ce(e,t,n,r,i,a){return{spawnPlanner:n,tracker:r,scheduler:i,discovery:e,skills:t,management:a,loadConfig:()=>u().config}}function we(e,t){if(t.kind===`requested`){let{event:n}=t;e.recordEvent(`doom_team.delegation_requested`,{"agent.name":n.agent,"task.id":n.taskId,mode:n.runMode??`foreground`})}else if(t.kind===`started`){let{event:n}=t;e.recordEvent(`doom_team.child_started`,{"run.id":n.runId,outcome:`started`})}else if(t.kind===`updated`){let{event:n}=t;e.recordEvent(`doom_team.delegation_updated`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,"team.token_count":n.tokens??0,outcome:n.status??`updated`})}else if(t.kind===`finished`){let{event:n}=t;e.recordEvent(`doom_team.delegation_finished`,{"run.id":n.runId,"team.tool_count":n.toolCount??0,"team.duration_ms":n.durationMs??0,outcome:n.status})}else e.recordEvent(`doom_team.delegation_cancelled`,{outcome:`cancelled`})}function x(t,c){let f,x=e=>(f??=be({serviceName:`doom-team`,packageName:`@agimon-ai/doompi-team`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),f),Te=(e,t)=>{f?.recordEvent(e,t)};t.effect(()=>async()=>{await f?.shutdown(),f=void 0},`@agimon-ai/doompi-team/telemetry`);let S=pe(Te),{subagentTool:Ee,teamChannel:C,pollScheduler:w,asyncJobTracker:T,subagentWaiter:E,asyncSubagentSpawner:De,discovery:D,skills:O,spawnPlanner:k,completionNotifier:A,resultWatcher:j,staleRunReconciler:M,management:N,capabilityPolicies:P,mcpToolResolver:Oe}=S,F=!0,I=0,L,R,z,B,V,H;t.inject([g],e=>{let t={cordis:e,service:e.get(g)};H=t,e.inject([ge],e=>Oe.bind(_e(e))),e.inject([me],e=>{let t=he(e).register({source:b,id:`runtime`,label:`Team`,order:200,snapshot:()=>i(a())});return()=>t.dispose()}),e.effect(()=>()=>{H===t&&(H=void 0)},`${b}/cordis-session`)});let U=e=>{let t=H,n=e.sessionManager.getSessionId();return(t?.service.context.sessionManager===e.sessionManager&&t.service.sessionId===n?ye(t.cordis):void 0)||(B??=ve({notify:e=>{let t=Se(e);V?.hasUI?V.ui.notify(t,`warning`):process.emitWarning(t)}}),B)},W=async(e,t)=>{t?.throwIfAborted();let n=R;if(!n)throw Error(`Doom Team session initialization has not started.`);if(z!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale Pi session.`);let r=await n;if(t?.throwIfAborted(),await r.wait(t?{signal:t}:void 0),!F||n!==R||z!==e.sessionManager)throw Error(`Doom Team readiness belongs to a stale extension generation.`)},G=new Proxy(c,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await W(a,r),t.execute(e,n,r,i,a))})}:t===`registerCommand`?(t,n)=>{e.registerCommand(t,{...n,handler:async(e,t)=>(await W(t),n.handler(e,t))})}:t===`registerShortcut`?(t,n)=>{e.registerShortcut(t,{...n,handler:async e=>(await W(e),n.handler(e))})}:xe(e,t)}});Ee.registerTool(G),t.inject([_],e=>de(v(e)));let K=C.createRuntime(G);t.effect(()=>()=>K.dispose(),`@agimon-ai/doompi-team/channel`),C.registerClient(G),A.attachHost(c),t.effect(()=>()=>A.dispose(),`@agimon-ai/doompi-team/completions`),w.start(),t.effect(()=>()=>w.stop(),`@agimon-ai/doompi-team/polling`),T.start(),t.effect(()=>()=>T.stop(),`@agimon-ai/doompi-team/jobs`);let q,J,Y,X=d({planner:k,management:N,waiter:E,scheduler:w,tracker:T,loadConfig:()=>u().config}),Z=p({spawner:De,waiter:E,management:N,policies:P,report:(e,t)=>{f?.recordEvent(e,t)}});t.effect(()=>async()=>{await q?.dispose(),q=void 0},`@agimon-ai/doompi-team/collaboration`),t.effect(()=>()=>{j.stop(),Y=void 0},`@agimon-ai/doompi-team/result-watcher`);let ke=w.register({id:`stale-run-reconciler`,intervalMs:2e3,run:async()=>{let e=!1,t=!1;for(let n of J?.list()??[]){if(n.status&&s.has(n.status))continue;t=!0;let{reconcile:r,sweep:i}=M.reconcileAndSweepAsync?await M.reconcileAndSweepAsync(n.runId):M.reconcileAndSweep(n.runId);r.repaired&&(J?.track(n.runId),e=!0),i.recovered.length>0&&(e=!0)}return e||t}});t.effect(()=>ke,`@agimon-ai/doompi-team/stale-runs`),c.on(`before_agent_start`,e=>{if(!(!F||!re(u().config)))return{systemPrompt:m(e.systemPrompt)}});let Q={baseCwd:void 0};l(G,Q,Ce(D,O,k,T,w,N)),ce(G,{discovery:D,skills:O,policies:P}),ue(G,{scheduler:w,tracker:T,management:N}),t.inject([_],e=>le(c,v(e),{scheduler:w,tracker:T})),se(c);let Ae=async()=>{let e=[],t=q;q=void 0;try{await t?.dispose()}catch(t){e.push(t)}for(let t of[()=>P.clear(),()=>X.abandonAll(),()=>Z.abandonAll(),()=>K.dispose()])try{t()}catch(t){e.push(t)}if(J=void 0,e.length!==0)return e.length===1&&e[0]instanceof Error?e[0]:AggregateError(e,`Team session cleanup failed.`)};c.on(`session_start`,(r,i)=>{if(!F)return;let a=++I,s=R;L?.abort(Error(`Doom Team session initialization was superseded.`));let c=new AbortController;L=c,z=i.sessionManager,V=i;let l=x(i);l.recordEvent(`doom_team.session_started`,{"team.root_session":h(i.sessionManager.getSessionId())===i.sessionManager.getSessionId()});let u=i.sessionManager.getSessionId(),d=e(h(u));n(d),Q.baseCwd=i.cwd,Y!==void 0&&Y!==d.scopeKey&&(j.stop(),Y=void 0);let f=Ae(),p=U(i),m=()=>F&&a===I&&z===i.sessionManager&&!c.signal.aborted;R=(async()=>{if(s&&await Promise.allSettled([s.then(e=>e.wait())]),!m())throw Error(`Doom Team session initialization was superseded.`);return p.start(b,`${u}:${a}`,async e=>{e.throwIfAborted();let n=await f;if(n)throw n;if(!m()||(await ne(d),e.throwIfAborted(),!m()))return{value:void 0};let r=await ae(d,{readStatusAsync:async e=>N.statusAsync?(await N.statusAsync(e)).status:N.status(e).status});if(e.throwIfAborted(),!m())return{value:void 0};if(r.suspended.length>0&&i.hasUI){let t=await ie(r.suspended);if(e.throwIfAborted(),!m())return{value:void 0};i.ui.notify(t,`info`)}l.recordEvent(`doom_team.runs_restored`,{"team.suspended_count":r.suspended.length,"team.pruned_count":r.pruned.length,"team.reaped_count":r.reaped,outcome:`reported`}),J=T.forSession(u),Y!==d.scopeKey&&(Y=d.scopeKey,j.start(e=>J?.get(e.runId)?A.deliver(e):!1));let a=ee(i.model),s=H,c=(s?.service.context.sessionManager===i.sessionManager?s.cordis:t).plugin(fe,{session:{sessionId:u,cwd:i.cwd,availableModels:o(i.modelRegistry),...a?{parentModel:a}:{},forkSource:te(i.sessionManager,`tool`)},delegation:X,fablePlan:Z,policies:P,observeDelegation:e=>we(l,e)});return q=c,await c.await(),m()?(K.bindMainSession(u),{value:void 0}):(await c.dispose(),q===c&&(q=void 0),{value:void 0})})})(),Promise.allSettled([R.then(e=>e.wait())])}),t.effect(()=>async()=>{F=!1,I+=1;let e=R;R=void 0,z=void 0,L?.abort(Error(`Doom Team runtime was disposed.`)),L=void 0;let t=B;B=void 0,t?await t.dispose():e&&await Promise.allSettled([e.then(e=>e.wait())]),V=void 0},`@agimon-ai/doompi-team/session-fence`);let $,je=async e=>{F=!1,I+=1;let t=R;R=void 0,z=void 0,L?.abort(Error(`Doom Team session ended.`)),L=void 0;let n=B;B=void 0,await Promise.allSettled([...t?[t.then(e=>e.wait())]:[],...n?[n.dispose()]:[]]);let i=r(),a=i?oe({scope:i,reason:e.reason??y,readStatus:e=>N.status(e).status}):Promise.resolve(void 0),o;try{o=await a,await f?.recordEvent(`doom_team.session_finished`,{reason:e.reason??y,"team.suspended_count":o?.suspended.length??0,"team.unstoppable_count":o?.unstoppable.length??0,outcome:o?.unstoppable.length?`degraded`:`suspended`})}catch(t){await f?.recordError(`doom_team.session_shutdown_failed`,t,{reason:e.reason??y})}finally{await f?.shutdown(),f=void 0}};return c.on(`session_shutdown`,e=>($??=je(e),$)),S}export{x as installTeamRuntime};
|
|
2
2
|
//# sourceMappingURL=extension.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Install the Team feature into one package-local Cordis root.\n *\n * The standard Pi factory owns that root and disposes it when Pi emits\n * `session_shutdown`. Each factory invocation therefore creates fresh session\n * state; no process-global container or replacement-root handshake participates\n * in reload. Long-lived services are registered as Cordis effects, and stale\n * asynchronous session-start continuations are fenced by a generation token.\n */\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport {\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context, Fiber } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n registerSlashCommands,\n type SlashCommandDeps,\n type SlashCommandState,\n} from '../../commands/slash/slashCommands.ts';\nimport { loadConfig } from '../../extensions/config.ts';\nimport { createDelegationBridge } from '../../extensions/delegationBridge.ts';\nimport { createFablePlanBridge } from '../../extensions/fablePlanBridge.ts';\nimport type { IManagementActions } from '../../extensions/managementActions.ts';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from '../../extensions/orchestratorPrompt.ts';\nimport { captureSessionForkSource, type ISpawnPlanner } from '../../extensions/spawnPlan.ts';\nimport type { ISkillDiscoveryService } from '../../services/agents/skills.ts';\nimport type { IAgentDiscoveryService } from '../../services/agents/types.ts';\nimport {\n type IAsyncJobTracker,\n type ITrackedAsyncJobs,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../../services/runs/background/asyncJobTracker.ts';\nimport { openScopeAsync, suspendScopeRuns } from '../../services/runs/registry/sessionLifecycle.ts';\nimport { formatSuspendedRunsAsync } from '../../services/runs/registry/suspendedRuns.ts';\nimport { normalizeParentModel } from '../../services/runs/shared/modelFallback.ts';\nimport { authenticatedModelInfos } from '../../shared/modelResolution.ts';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../../shared/paths.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\nimport { writeScopeOwnerAsync } from '../../shared/scopeOwner.ts';\nimport { registerCompletionRenderer } from '../../tui/completionNotice.ts';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from '../../tui/register.ts';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration.ts';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime.ts';\n\n/** See the subscriber's own comment for why crash detection does not need the 250ms floor. */\nconst STALE_RUN_RECONCILE_INTERVAL_MS = 2_000;\nconst SESSION_SHUTDOWN_REASON_FALLBACK = 'unknown';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-team';\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\n\nfunction boundPiValue(target: ExtensionAPI, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction readinessNotificationMessage(notification: DoomReadinessNotification): string {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n return `${notification.packageId} initialization ${notification.state}: ${detail}`;\n}\n\nfunction buildSlashCommandDeps(\n discovery: IAgentDiscoveryService,\n skills: ISkillDiscoveryService,\n planner: ISpawnPlanner,\n tracker: IAsyncJobTracker,\n scheduler: IPollScheduler,\n management: IManagementActions,\n): SlashCommandDeps {\n return {\n spawnPlanner: planner,\n tracker,\n scheduler,\n discovery,\n skills,\n management,\n loadConfig: () => loadConfig().config,\n };\n}\n\nfunction recordDelegationObservation(telemetry: DoomTelemetry, observation: TeamDelegationObservation): void {\n if (observation.kind === 'requested') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_requested', {\n 'agent.name': event.agent,\n 'task.id': event.taskId,\n mode: event.runMode ?? 'foreground',\n });\n } else if (observation.kind === 'started') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.child_started', { 'run.id': event.runId, outcome: 'started' });\n } else if (observation.kind === 'updated') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_updated', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n 'team.token_count': event.tokens ?? 0,\n outcome: event.status ?? 'updated',\n });\n } else if (observation.kind === 'finished') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_finished', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n outcome: event.status,\n });\n } else {\n void telemetry.recordEvent('doom_team.delegation_cancelled', { outcome: 'cancelled' });\n }\n}\n\n/**\n * The extension factory pi's loader calls, exported as the module default\n * (see the override this file carries in `vibe-lint.config.yaml`). This is an\n * ESM `.ts` module, so it CANNOT use the `export =` form that\n * `subagentPromptRuntimeEntry.cts` is required to use - that file is `.cts`\n * and is resolved by raw path, this one is resolved as a package subpath and\n * matches the `export default` convention every sibling extension in this repo\n * already uses (`doom-task`, `doom-file-edit`, `doom-pi-ui`).\n */\nexport function installTeamRuntime(cordis: Context, pi: ExtensionAPI): TeamExtensionRuntime {\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-team',\n packageName: '@agimon-ai/doompi-team',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n const reportConcurrencyEvent = (event: string, attributes: Record<string, unknown>): void => {\n void telemetry?.recordEvent(event, attributes);\n };\n cordis.effect(\n () => async () => {\n await telemetry?.shutdown();\n telemetry = undefined;\n },\n '@agimon-ai/doompi-team/telemetry',\n );\n const runtime = createTeamExtensionRuntime(reportConcurrencyEvent);\n const {\n subagentTool,\n teamChannel,\n pollScheduler,\n asyncJobTracker,\n subagentWaiter,\n asyncSubagentSpawner,\n discovery,\n skills,\n spawnPlanner,\n completionNotifier,\n resultWatcher,\n staleRunReconciler,\n management,\n capabilityPolicies,\n } = runtime;\n\n let active = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let readinessSessionManager: object | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n let readinessNotificationContext: ExtensionContext | undefined;\n let activeCordisSession:\n | {\n readonly cordis: Context;\n readonly service: DoomCordisSessionService;\n }\n | undefined;\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], (sessionContext) => {\n const service = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const binding = { cordis: sessionContext, service };\n activeCordisSession = binding;\n sessionContext.effect(\n () => () => {\n if (activeCordisSession === binding) activeCordisSession = undefined;\n },\n `${PACKAGE_SOURCE}/cordis-session`,\n );\n });\n const coordinatorFor = (ctx: ExtensionContext): DoomReadinessCoordinator => {\n const cordisSession = activeCordisSession;\n const sessionId = ctx.sessionManager.getSessionId();\n const activeSessionMatches =\n cordisSession?.service.context.sessionManager === ctx.sessionManager &&\n cordisSession.service.sessionId === sessionId;\n const shared = activeSessionMatches ? readDoomReadinessCoordinator(cordisSession.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n const message = readinessNotificationMessage(notification);\n if (readinessNotificationContext?.hasUI) readinessNotificationContext.ui.notify(message, 'warning');\n else process.emitWarning(message);\n },\n });\n return standaloneReadiness;\n };\n const waitForSessionReadiness = async (ctx: ExtensionContext, signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Doom Team session initialization has not started.');\n if (readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale Pi session.');\n }\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!active || pending !== readinessHandle || readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale extension generation.');\n }\n };\n const readinessPi = new Proxy(pi, {\n get(target, property) {\n if (property === 'registerTool') {\n return (tool: RegisteredTool): void => {\n target.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, ctx) => {\n await waitForSessionReadiness(ctx, signal);\n return tool.execute(toolCallId, params, signal, onUpdate, ctx);\n },\n });\n };\n }\n if (property === 'registerCommand') {\n return (name: string, options: CommandOptions): void => {\n target.registerCommand(name, {\n ...options,\n handler: async (args, ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(args, ctx);\n },\n });\n };\n }\n if (property === 'registerShortcut') {\n return (shortcut: Parameters<ExtensionAPI['registerShortcut']>[0], options: ShortcutOptions): void => {\n target.registerShortcut(shortcut, {\n ...options,\n handler: async (ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(ctx);\n },\n });\n };\n }\n return boundPiValue(target, property);\n },\n });\n\n subagentTool.registerTool(readinessPi);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerSubagentLeaderContribution(requireDoomUiHub(uiContext)));\n\n const teamRuntime = teamChannel.createRuntime(readinessPi);\n cordis.effect(() => () => teamRuntime.dispose(), '@agimon-ai/doompi-team/channel');\n teamChannel.registerClient(readinessPi);\n\n // Attach before `ResultWatcher.start()`, which `session_start` drives.\n completionNotifier.attachHost(pi);\n cordis.effect(() => () => completionNotifier.dispose(), '@agimon-ai/doompi-team/completions');\n\n pollScheduler.start();\n cordis.effect(() => () => pollScheduler.stop(), '@agimon-ai/doompi-team/polling');\n\n asyncJobTracker.start();\n cordis.effect(() => () => asyncJobTracker.stop(), '@agimon-ai/doompi-team/jobs');\n\n let collaborationFiber: Fiber | undefined;\n let currentSessionJobs: ITrackedAsyncJobs | undefined;\n // The scope `ResultWatcher` is currently watching. See its start site in\n // the `session_start` handler for why the watcher is latched on this\n // rather than started once.\n let watchedScopeKey: string | undefined;\n const delegationBridge = createDelegationBridge({\n planner: spawnPlanner,\n management,\n waiter: subagentWaiter,\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n loadConfig: () => loadConfig().config,\n });\n const fablePlanBridge = createFablePlanBridge({\n spawner: asyncSubagentSpawner,\n waiter: subagentWaiter,\n management,\n policies: capabilityPolicies,\n report: (event, attributes) => {\n void telemetry?.recordEvent(event, attributes);\n },\n });\n cordis.effect(\n () => async () => {\n await collaborationFiber?.dispose();\n collaborationFiber = undefined;\n },\n '@agimon-ai/doompi-team/collaboration',\n );\n cordis.effect(\n () => () => {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n },\n '@agimon-ai/doompi-team/result-watcher',\n );\n\n const unregisterStaleRunReconciler = pollScheduler.register({\n id: 'stale-run-reconciler',\n // Crash detection, not status freshness - `AsyncJobTracker` owns that and\n // polls on its own 250ms. This subscriber only ever acts on a run whose\n // process is provably dead, so noticing that 2s later is invisible, while\n // running it 4x/second per active run was not: each pass is a status read,\n // a run-id resolve and a pid probe that a healthy child always discards.\n intervalMs: STALE_RUN_RECONCILE_INTERVAL_MS,\n run: async () => {\n let repaired = false;\n let hasActiveRun = false;\n for (const job of currentSessionJobs?.list() ?? []) {\n if (job.status && TERMINAL_ASYNC_JOB_STATES.has(job.status)) continue;\n hasActiveRun = true;\n // One pass, one `inspect()`. Calling `reconcile` and\n // `sweepOrphanedClaims` separately probed the same pid twice for the\n // same answer - see `IStaleRunReconciler.reconcileAndSweep`.\n const { reconcile: outcome, sweep } = staleRunReconciler.reconcileAndSweepAsync\n ? await staleRunReconciler.reconcileAndSweepAsync(job.runId)\n : staleRunReconciler.reconcileAndSweep(job.runId);\n if (outcome.repaired) {\n currentSessionJobs?.track(job.runId);\n repaired = true;\n }\n if (sweep.recovered.length > 0) repaired = true;\n }\n // An active runner is useful work for scheduling purposes: keeping\n // the shared scheduler at its floor prevents crash detection from\n // inheriting the idle five-second backoff ceiling.\n return repaired || hasActiveRun;\n },\n });\n cordis.effect(() => unregisterStaleRunReconciler, '@agimon-ai/doompi-team/stale-runs');\n // The orchestration addendum. Registered here rather than inside the\n // `subagent` tool's description because it is behavioural guidance, and it\n // has to land before the model decides whether to reach for the tool at\n // all - see `orchestratorPrompt.ts`. Read config per turn so toggling it\n // does not need a session restart; `loadConfig` is memoized on the file's\n // own mtime, so this is a stat, not a read.\n pi.on('before_agent_start', (event: { systemPrompt?: string }) => {\n if (!active || !shouldInjectOrchestratorPrompt(loadConfig().config)) return undefined;\n return { systemPrompt: appendOrchestratorPrompt(event.systemPrompt) };\n });\n\n const state: SlashCommandState = { baseCwd: undefined };\n registerSlashCommands(\n readinessPi,\n state,\n buildSlashCommandDeps(discovery, skills, spawnPlanner, asyncJobTracker, pollScheduler, management),\n );\n registerAgentListCommand(readinessPi, { discovery, skills, policies: capabilityPolicies });\n registerFleetCommand(readinessPi, {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n management,\n });\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerAgentStatus(pi, requireDoomUiHub(uiContext), {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n });\n });\n registerCompletionRenderer(pi);\n\n const retireSessionBindings = async (): Promise<Error | undefined> => {\n const errors: unknown[] = [];\n const previousCollaboration = collaborationFiber;\n collaborationFiber = undefined;\n try {\n await previousCollaboration?.dispose();\n } catch (error) {\n errors.push(error);\n }\n for (const cleanup of [\n () => capabilityPolicies.clear(),\n () => delegationBridge.abandonAll(),\n () => fablePlanBridge.abandonAll(),\n () => teamRuntime.dispose(),\n ]) {\n try {\n cleanup();\n } catch (error) {\n errors.push(error);\n }\n }\n currentSessionJobs = undefined;\n if (errors.length === 0) return undefined;\n if (errors.length === 1 && errors[0] instanceof Error) return errors[0];\n return new AggregateError(errors, 'Team session cleanup failed.');\n };\n\n // Bind the root session directly into the one intercom transport. Child\n // processes bind from the team environment written during spawn.\n pi.on('session_start', (_event, ctx: ExtensionContext) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort(new Error('Doom Team session initialization was superseded.'));\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n readinessSessionManager = ctx.sessionManager;\n readinessNotificationContext = ctx;\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_team.session_started', {\n 'team.root_session':\n resolveRootSessionId(ctx.sessionManager.getSessionId()) === ctx.sessionManager.getSessionId(),\n });\n // Before anything else: every scoped path helper reads this. A child\n // keeps the root inherited from its spawn environment, while a top-level\n // session falls back to its own Pi session id.\n const sessionId = ctx.sessionManager.getSessionId();\n const scope = createSessionScope(resolveRootSessionId(sessionId));\n setCurrentSessionScope(scope);\n state.baseCwd = ctx.cwd;\n if (watchedScopeKey !== undefined && watchedScopeKey !== scope.scopeKey) {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n }\n const retirement = retireSessionBindings();\n const coordinator = coordinatorFor(ctx);\n const ownsSession = (): boolean =>\n active &&\n ownGeneration === sessionGeneration &&\n readinessSessionManager === ctx.sessionManager &&\n !ownReadinessAbort.signal.aborted;\n\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Doom Team session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${sessionId}:${ownGeneration}`, async (signal) => {\n signal.throwIfAborted();\n const retirementError = await retirement;\n if (retirementError) throw retirementError;\n if (!ownsSession()) return { value: undefined };\n // Claim the scope for this process, so a later sweep can tell an\n // abandoned tree from a live one. Rewritten on every session_start\n // because /resume legitimately re-adopts a scope under a new process.\n await writeScopeOwnerAsync(scope);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n // Prune records whose process is gone, reap sibling scopes holding\n // nothing alive, and REPORT what is suspended. Nothing is restarted:\n // reopening a session must not silently spend tokens on stale work.\n const opened = await openScopeAsync(scope, {\n readStatusAsync: async (runId) =>\n management.statusAsync ? (await management.statusAsync(runId)).status : management.status(runId).status,\n });\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n if (opened.suspended.length > 0 && ctx.hasUI) {\n const message = await formatSuspendedRunsAsync(opened.suspended);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n ctx.ui.notify(message, 'info');\n }\n void activeTelemetry.recordEvent('doom_team.runs_restored', {\n 'team.suspended_count': opened.suspended.length,\n 'team.pruned_count': opened.pruned.length,\n 'team.reaped_count': opened.reaped,\n outcome: 'reported',\n });\n currentSessionJobs = asyncJobTracker.forSession(sessionId);\n // ResultWatcher needs the session scope, but a repeated start for the\n // same scope must not reset its in-flight claims.\n if (watchedScopeKey !== scope.scopeKey) {\n watchedScopeKey = scope.scopeKey;\n resultWatcher.start((result) =>\n currentSessionJobs?.get(result.runId) ? completionNotifier.deliver(result) : false,\n );\n }\n const parentModel = normalizeParentModel(ctx.model);\n const activeSession = activeCordisSession;\n const collaborationParent =\n activeSession?.service.context.sessionManager === ctx.sessionManager ? activeSession.cordis : cordis;\n const nextCollaboration = collaborationParent.plugin(teamCollaborationPlugin, {\n session: {\n sessionId,\n cwd: ctx.cwd,\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n forkSource: captureSessionForkSource(ctx.sessionManager, 'tool'),\n },\n delegation: delegationBridge,\n fablePlan: fablePlanBridge,\n policies: capabilityPolicies,\n observeDelegation: (observation) => recordDelegationObservation(activeTelemetry, observation),\n });\n collaborationFiber = nextCollaboration;\n await nextCollaboration.await();\n if (!ownsSession()) {\n await nextCollaboration.dispose();\n if (collaborationFiber === nextCollaboration) collaborationFiber = undefined;\n return { value: undefined };\n }\n teamRuntime.bindMainSession(sessionId);\n return { value: undefined };\n });\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n return undefined;\n });\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team runtime was disposed.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) await ownedReadiness.dispose();\n else if (pendingReadiness) await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n readinessNotificationContext = undefined;\n },\n '@agimon-ai/doompi-team/session-fence',\n );\n\n /**\n * Every reason suspends, with no exception for `reload`.\n *\n * Pi emits this for `quit`, `reload`, `new`, `resume` and `fork`. Treating\n * `reload` differently - keeping children alive because `/domains`, `/major-mode`\n * and `/profile` only reload the extension - would be the one case someone\n * has to remember, and the one that silently misbehaves if Pi adds a sixth\n * reason. Suspending uniformly costs a respawn on reload; restore continues\n * the child's own transcript rather than restarting its task.\n */\n let shutdownPromise: Promise<void> | undefined;\n const shutdownSession = async (event: { reason?: string }): Promise<void> => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team session ended.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n await Promise.allSettled([\n ...(pendingReadiness ? [pendingReadiness.then((handle) => handle.wait())] : []),\n ...(ownedReadiness ? [ownedReadiness.dispose()] : []),\n ]);\n const scope = tryCurrentSessionScope();\n const suspensionPromise = scope\n ? suspendScopeRuns({\n scope,\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n readStatus: (runId) => management.status(runId).status,\n })\n : Promise.resolve(undefined);\n let suspension: Awaited<ReturnType<typeof suspendScopeRuns>> | undefined;\n try {\n suspension = await suspensionPromise;\n await telemetry?.recordEvent('doom_team.session_finished', {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n 'team.suspended_count': suspension?.suspended.length ?? 0,\n 'team.unstoppable_count': suspension?.unstoppable.length ?? 0,\n outcome: suspension?.unstoppable.length ? 'degraded' : 'suspended',\n });\n } catch (error) {\n await telemetry?.recordError('doom_team.session_shutdown_failed', error, {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n });\n } finally {\n await telemetry?.shutdown();\n telemetry = undefined;\n }\n };\n pi.on('session_shutdown', (event: { reason?: string }) => {\n shutdownPromise ??= shutdownSession(event);\n return shutdownPromise;\n });\n\n return runtime;\n}\n"],"mappings":"mlEA2C0D,EAAA,EAKgD,EAAA,MAc1G,MACM,EAAmC,UACnC,EAAiB,yBAMvB,SAAS,GAAa,EAAsB,EAAgC,CAC1E,IAAM,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAM,EAClD,OAAO,OAAO,GAAU,WAAa,EAAM,KAAK,CAAM,EAAI,CAC5D,CAEA,SAAS,GAA6B,EAAiD,CACrF,IAAM,EAAc,EAAa,YAAY,KAAK,IAAI,EAChD,GAAU,EAAa,OAAO,SAAW,IAAgB,mCAC/D,MAAO,GAAG,EAAa,UAAU,kBAAkB,EAAa,MAAM,IAAI,GAC5E,CAEA,SAAS,GACP,EACA,EACA,EACA,EACA,EACA,EACkB,CAClB,MAAO,CACL,aAAc,EACd,UACA,YACA,YACA,SACA,aACA,eAAkB,EAAW,CAAC,CAAC,MACjC,CACF,CAEA,SAAS,GAA4B,EAA0B,EAA8C,CAC3G,GAAI,EAAY,OAAS,YAAa,CACpC,GAAM,CAAE,SAAU,EAClB,EAAe,YAAY,iCAAkC,CAC3D,aAAc,EAAM,MACpB,UAAW,EAAM,OACjB,KAAM,EAAM,SAAW,YACzB,CAAC,CACH,MAAO,GAAI,EAAY,OAAS,UAAW,CACzC,GAAM,CAAE,SAAU,EAClB,EAAe,YAAY,0BAA2B,CAAE,SAAU,EAAM,MAAO,QAAS,SAAU,CAAC,CACrG,MAAO,GAAI,EAAY,OAAS,UAAW,CACzC,GAAM,CAAE,SAAU,EAClB,EAAe,YAAY,+BAAgC,CACzD,SAAU,EAAM,MAChB,kBAAmB,EAAM,WAAa,EACtC,mBAAoB,EAAM,YAAc,EACxC,mBAAoB,EAAM,QAAU,EACpC,QAAS,EAAM,QAAU,SAC3B,CAAC,CACH,MAAO,GAAI,EAAY,OAAS,WAAY,CAC1C,GAAM,CAAE,SAAU,EAClB,EAAe,YAAY,gCAAiC,CAC1D,SAAU,EAAM,MAChB,kBAAmB,EAAM,WAAa,EACtC,mBAAoB,EAAM,YAAc,EACxC,QAAS,EAAM,MACjB,CAAC,CACH,MACE,EAAe,YAAY,iCAAkC,CAAE,QAAS,WAAY,CAAC,CAEzF,CAWA,SAAgB,EAAmB,EAAiB,EAAwC,CAC1F,IAAI,EACE,EAAgB,IACpB,IAAc,GAAoB,CAChC,YAAa,YACb,YAAa,yBACb,IAAK,EAAI,IACT,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACM,GAEH,IAA0B,EAAe,IAA8C,CAC3F,GAAgB,YAAY,EAAO,CAAU,CAC/C,EACA,EAAO,WACC,SAAY,CAChB,MAAM,GAAW,SAAS,EAC1B,EAAY,IAAA,EACd,EACA,kCACF,EACA,IAAM,EAAU,GAA2B,EAAsB,EAC3D,CACJ,gBACA,cACA,gBACA,kBACA,iBACA,wBACA,YACA,SACA,eACA,qBACA,gBACA,qBACA,aACA,sBACE,EAEA,EAAS,GACT,EAAoB,EACpB,EACA,EACA,EACA,EACA,EACA,EAMJ,EAAO,OAAO,CAAC,CAA2B,EAAI,GAAmB,CAE/D,IAAM,EAAU,CAAE,OAAQ,EAAgB,QAD1B,EAAe,IAAI,CACa,CAAE,EAClD,EAAsB,EACtB,EAAe,eACD,CACN,IAAwB,IAAS,EAAsB,IAAA,GAC7D,EACA,GAAG,EAAe,gBACpB,CACF,CAAC,EACD,IAAM,GAAkB,GAAoD,CAC1E,IAAM,EAAgB,EAChB,EAAY,EAAI,eAAe,aAAa,EAalD,OAXE,GAAe,QAAQ,QAAQ,iBAAmB,EAAI,gBACtD,EAAc,QAAQ,YAAc,EACA,GAA6B,EAAc,MAAM,EAAI,IAAA,MAE3F,IAAwB,GAA+B,CACrD,OAAS,GAAiB,CACxB,IAAM,EAAU,GAA6B,CAAY,EACrD,GAA8B,MAAO,EAA6B,GAAG,OAAO,EAAS,SAAS,EAC7F,QAAQ,YAAY,CAAO,CAClC,CACF,CAAC,EACM,EACT,EACM,EAA0B,MAAO,EAAuB,IAAwC,CACpG,GAAQ,eAAe,EACvB,IAAM,EAAU,EAChB,GAAI,CAAC,EAAS,MAAU,MAAM,mDAAmD,EACjF,GAAI,IAA4B,EAAI,eAClC,MAAU,MAAM,oDAAoD,EAEtE,IAAM,EAAS,MAAM,EAGrB,GAFA,GAAQ,eAAe,EACvB,MAAM,EAAO,KAAK,EAAS,CAAE,QAAO,EAAI,IAAA,EAAS,EAC7C,CAAC,GAAU,IAAY,GAAmB,IAA4B,EAAI,eAC5E,MAAU,MAAM,8DAA8D,CAElF,EACM,EAAc,IAAI,MAAM,EAAI,CAChC,IAAI,EAAQ,EAAU,CAkCpB,OAjCI,IAAa,eACP,GAA+B,CACrC,EAAO,aAAa,CAClB,GAAG,EACH,QAAS,MAAO,EAAY,EAAQ,EAAQ,EAAU,KACpD,MAAM,EAAwB,EAAK,CAAM,EAClC,EAAK,QAAQ,EAAY,EAAQ,EAAQ,EAAU,CAAG,EAEjE,CAAC,CACH,EAEE,IAAa,mBACP,EAAc,IAAkC,CACtD,EAAO,gBAAgB,EAAM,CAC3B,GAAG,EACH,QAAS,MAAO,EAAM,KACpB,MAAM,EAAwB,CAAG,EAC1B,EAAQ,QAAQ,EAAM,CAAG,EAEpC,CAAC,CACH,EAEE,IAAa,oBACP,EAA2D,IAAmC,CACpG,EAAO,iBAAiB,EAAU,CAChC,GAAG,EACH,QAAS,KAAO,KACd,MAAM,EAAwB,CAAG,EAC1B,EAAQ,QAAQ,CAAG,EAE9B,CAAC,CACH,EAEK,GAAa,EAAQ,CAAQ,CACtC,CACF,CAAC,EAED,GAAa,aAAa,CAAW,EAErC,EAAO,OAAO,CAAC,CAAmB,EAAI,GAAc,GAAmC,EAAiB,CAAS,CAAC,CAAC,EAEnH,IAAM,EAAc,EAAY,cAAc,CAAW,EACzD,EAAO,eAAmB,EAAY,QAAQ,EAAG,gCAAgC,EACjF,EAAY,eAAe,CAAW,EAGtC,EAAmB,WAAW,CAAE,EAChC,EAAO,eAAmB,EAAmB,QAAQ,EAAG,oCAAoC,EAE5F,EAAc,MAAM,EACpB,EAAO,eAAmB,EAAc,KAAK,EAAG,gCAAgC,EAEhF,EAAgB,MAAM,EACtB,EAAO,eAAmB,EAAgB,KAAK,EAAG,6BAA6B,EAE/E,IAAI,EACA,EAIA,EACE,EAAmB,EAAuB,CAC9C,QAAS,EACT,aACA,OAAQ,EACR,UAAW,EACX,QAAS,EACT,eAAkB,EAAW,CAAC,CAAC,MACjC,CAAC,EACK,EAAkB,EAAsB,CAC5C,QAAS,GACT,OAAQ,EACR,aACA,SAAU,EACV,QAAS,EAAO,IAAe,CAC7B,GAAgB,YAAY,EAAO,CAAU,CAC/C,CACF,CAAC,EACD,EAAO,WACC,SAAY,CAChB,MAAM,GAAoB,QAAQ,EAClC,EAAqB,IAAA,EACvB,EACA,sCACF,EACA,EAAO,eACO,CACV,EAAc,KAAK,EACnB,EAAkB,IAAA,EACpB,EACA,uCACF,EAEA,IAAM,GAA+B,EAAc,SAAS,CAC1D,GAAI,uBAMJ,WAAY,IACZ,IAAK,SAAY,CACf,IAAI,EAAW,GACX,EAAe,GACnB,IAAK,IAAM,KAAO,GAAoB,KAAK,GAAK,CAAC,EAAG,CAClD,GAAI,EAAI,QAAU,EAA0B,IAAI,EAAI,MAAM,EAAG,SAC7D,EAAe,GAIf,GAAM,CAAE,UAAW,EAAS,SAAU,EAAmB,uBACrD,MAAM,EAAmB,uBAAuB,EAAI,KAAK,EACzD,EAAmB,kBAAkB,EAAI,KAAK,EAC9C,EAAQ,WACV,GAAoB,MAAM,EAAI,KAAK,EACnC,EAAW,IAET,EAAM,UAAU,OAAS,IAAG,EAAW,GAC7C,CAIA,OAAO,GAAY,CACrB,CACF,CAAC,EACD,EAAO,WAAa,GAA8B,mCAAmC,EAOrF,EAAG,GAAG,qBAAuB,GAAqC,CAC5D,MAAC,GAAU,CAAC,EAA+B,EAAW,CAAC,CAAC,MAAM,GAClE,MAAO,CAAE,aAAc,EAAyB,EAAM,YAAY,CAAE,CACtE,CAAC,EAED,IAAM,GAA2B,CAAE,QAAS,IAAA,EAAU,EACtD,EACE,EACA,GACA,GAAsB,EAAW,EAAQ,EAAc,EAAiB,EAAe,CAAU,CACnG,EACA,GAAyB,EAAa,CAAE,YAAW,SAAQ,SAAU,CAAmB,CAAC,EACzF,GAAqB,EAAa,CAChC,UAAW,EACX,QAAS,EACT,YACF,CAAC,EACD,EAAO,OAAO,CAAC,CAAmB,EAAI,GAC7B,GAAoB,EAAI,EAAiB,CAAS,EAAG,CAC1D,UAAW,EACX,QAAS,CACX,CAAC,CACF,EACD,GAA2B,CAAE,EAE7B,IAAM,GAAwB,SAAwC,CACpE,IAAM,EAAoB,CAAC,EACrB,EAAwB,EAC9B,EAAqB,IAAA,GACrB,GAAI,CACF,MAAM,GAAuB,QAAQ,CACvC,OAAS,EAAO,CACd,EAAO,KAAK,CAAK,CACnB,CACA,IAAK,IAAM,IAAW,KACd,EAAmB,MAAM,MACzB,EAAiB,WAAW,MAC5B,EAAgB,WAAW,MAC3B,EAAY,QAAQ,CAC5B,EACE,GAAI,CACF,EAAQ,CACV,OAAS,EAAO,CACd,EAAO,KAAK,CAAK,CACnB,CAEF,KAAqB,IAAA,GACjB,EAAO,SAAW,EAEtB,OADI,EAAO,SAAW,GAAK,EAAO,aAAc,MAAc,EAAO,GAC1D,eAAe,EAAQ,8BAA8B,CAClE,EAIA,EAAG,GAAG,iBAAkB,EAAQ,IAA0B,CACxD,GAAI,CAAC,EAAQ,OACb,IAAM,EAAgB,EAAE,EAClB,EAAoB,EAC1B,GAAgB,MAAU,MAAM,kDAAkD,CAAC,EACnF,IAAM,EAAoB,IAAI,gBAC9B,EAAiB,EACjB,EAA0B,EAAI,eAC9B,EAA+B,EAC/B,IAAM,EAAkB,EAAa,CAAG,EACxC,EAAqB,YAAY,4BAA6B,CAC5D,oBACE,EAAqB,EAAI,eAAe,aAAa,CAAC,IAAM,EAAI,eAAe,aAAa,CAChG,CAAC,EAID,IAAM,EAAY,EAAI,eAAe,aAAa,EAC5C,EAAQ,EAAmB,EAAqB,CAAS,CAAC,EAChE,EAAuB,CAAK,EAC5B,GAAM,QAAU,EAAI,IAChB,IAAoB,IAAA,IAAa,IAAoB,EAAM,WAC7D,EAAc,KAAK,EACnB,EAAkB,IAAA,IAEpB,IAAM,EAAa,GAAsB,EACnC,EAAc,GAAe,CAAG,EAChC,MACJ,GACA,IAAkB,GAClB,IAA4B,EAAI,gBAChC,CAAC,EAAkB,OAAO,QAE5B,GAAmB,SAAgD,CAIjE,GAHI,GACF,MAAM,QAAQ,WAAW,CAAC,EAAkB,KAAM,GAAW,EAAO,KAAK,CAAC,CAAC,CAAC,EAE1E,CAAC,EAAY,EAAG,MAAU,MAAM,kDAAkD,EACtF,OAAO,EAAY,MAAM,EAAgB,GAAG,EAAU,GAAG,IAAiB,KAAO,IAAW,CAC1F,EAAO,eAAe,EACtB,IAAM,EAAkB,MAAM,EAC9B,GAAI,EAAiB,MAAM,EAO3B,GANI,CAAC,EAAY,IAIjB,MAAM,GAAqB,CAAK,EAChC,EAAO,eAAe,EAClB,CAAC,EAAY,GAAG,MAAO,CAAE,MAAO,IAAA,EAAU,EAI9C,IAAM,EAAS,MAAM,GAAe,EAAO,CACzC,gBAAiB,KAAO,IACtB,EAAW,aAAe,MAAM,EAAW,YAAY,CAAK,EAAA,CAAG,OAAS,EAAW,OAAO,CAAK,CAAC,CAAC,MACrG,CAAC,EAED,GADA,EAAO,eAAe,EAClB,CAAC,EAAY,EAAG,MAAO,CAAE,MAAO,IAAA,EAAU,EAC9C,GAAI,EAAO,UAAU,OAAS,GAAK,EAAI,MAAO,CAC5C,IAAM,EAAU,MAAM,GAAyB,EAAO,SAAS,EAE/D,GADA,EAAO,eAAe,EAClB,CAAC,EAAY,EAAG,MAAO,CAAE,MAAO,IAAA,EAAU,EAC9C,EAAI,GAAG,OAAO,EAAS,MAAM,CAC/B,CACA,EAAqB,YAAY,0BAA2B,CAC1D,uBAAwB,EAAO,UAAU,OACzC,oBAAqB,EAAO,OAAO,OACnC,oBAAqB,EAAO,OAC5B,QAAS,UACX,CAAC,EACD,EAAqB,EAAgB,WAAW,CAAS,EAGrD,IAAoB,EAAM,WAC5B,EAAkB,EAAM,SACxB,EAAc,MAAO,GACnB,GAAoB,IAAI,EAAO,KAAK,EAAI,EAAmB,QAAQ,CAAM,EAAI,EAC/E,GAEF,IAAM,EAAc,EAAqB,EAAI,KAAK,EAC5C,EAAgB,EAGhB,GADJ,GAAe,QAAQ,QAAQ,iBAAmB,EAAI,eAAiB,EAAc,OAAS,EAAA,CAClD,OAAO,GAAyB,CAC5E,QAAS,CACP,YACA,IAAK,EAAI,IACT,gBAAiB,EAAwB,EAAI,aAAa,EAC1D,GAAI,EAAc,CAAE,aAAY,EAAI,CAAC,EACrC,WAAY,EAAyB,EAAI,eAAgB,MAAM,CACjE,EACA,WAAY,EACZ,UAAW,EACX,SAAU,EACV,kBAAoB,GAAgB,GAA4B,EAAiB,CAAW,CAC9F,CAAC,EASD,MARA,GAAqB,EACrB,MAAM,EAAkB,MAAM,EACzB,EAAY,GAKjB,EAAY,gBAAgB,CAAS,EAC9B,CAAE,MAAO,IAAA,EAAU,IALxB,MAAM,EAAkB,QAAQ,EAC5B,IAAuB,IAAmB,EAAqB,IAAA,IAC5D,CAAE,MAAO,IAAA,EAAU,EAI9B,CAAC,CACH,EAAA,CAAG,EAEH,QAAa,WAAW,CAAC,EAAgB,KAAM,GAAW,EAAO,KAAK,CAAC,CAAC,CAAC,CAE3E,CAAC,EAED,EAAO,WACC,SAAY,CAChB,EAAS,GACT,GAAqB,EACrB,IAAM,EAAmB,EACzB,EAAkB,IAAA,GAClB,EAA0B,IAAA,GAC1B,GAAgB,MAAU,MAAM,iCAAiC,CAAC,EAClE,EAAiB,IAAA,GACjB,IAAM,EAAiB,EACvB,EAAsB,IAAA,GAClB,EAAgB,MAAM,EAAe,QAAQ,EACxC,GAAkB,MAAM,QAAQ,WAAW,CAAC,EAAiB,KAAM,GAAW,EAAO,KAAK,CAAC,CAAC,CAAC,EACtG,EAA+B,IAAA,EACjC,EACA,sCACF,EAYA,IAAI,EACE,GAAkB,KAAO,IAA8C,CAC3E,EAAS,GACT,GAAqB,EACrB,IAAM,EAAmB,EACzB,EAAkB,IAAA,GAClB,EAA0B,IAAA,GAC1B,GAAgB,MAAU,MAAM,0BAA0B,CAAC,EAC3D,EAAiB,IAAA,GACjB,IAAM,EAAiB,EACvB,EAAsB,IAAA,GACtB,MAAM,QAAQ,WAAW,CACvB,GAAI,EAAmB,CAAC,EAAiB,KAAM,GAAW,EAAO,KAAK,CAAC,CAAC,EAAI,CAAC,EAC7E,GAAI,EAAiB,CAAC,EAAe,QAAQ,CAAC,EAAI,CAAC,CACrD,CAAC,EACD,IAAM,EAAQ,EAAuB,EAC/B,EAAoB,EACtB,EAAiB,CACf,QACA,OAAQ,EAAM,QAAU,EACxB,WAAa,GAAU,EAAW,OAAO,CAAK,CAAC,CAAC,MAClD,CAAC,EACD,QAAQ,QAAQ,IAAA,EAAS,EACzB,EACJ,GAAI,CACF,EAAa,MAAM,EACnB,MAAM,GAAW,YAAY,6BAA8B,CACzD,OAAQ,EAAM,QAAU,EACxB,uBAAwB,GAAY,UAAU,QAAU,EACxD,yBAA0B,GAAY,YAAY,QAAU,EAC5D,QAAS,GAAY,YAAY,OAAS,WAAa,WACzD,CAAC,CACH,OAAS,EAAO,CACd,MAAM,GAAW,YAAY,oCAAqC,EAAO,CACvE,OAAQ,EAAM,QAAU,CAC1B,CAAC,CACH,QAAU,CACR,MAAM,GAAW,SAAS,EAC1B,EAAY,IAAA,EACd,CACF,EAMA,OALA,EAAG,GAAG,mBAAqB,IACzB,IAAoB,GAAgB,CAAK,EAClC,EACR,EAEM,CACT"}
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Install the Team feature into one package-local Cordis root.\n *\n * The standard Pi factory owns that root and disposes it when Pi emits\n * `session_shutdown`. Each factory invocation therefore creates fresh session\n * state; no process-global container or replacement-root handshake participates\n * in reload. Long-lived services are registered as Cordis effects, and stale\n * asynchronous session-start continuations are fenced by a generation token.\n */\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport {\n DOOM_CONTEXT_CONTRIBUTIONS_SERVICE,\n requireDoomContextContributions,\n} from '@agimon-ai/doompi-extension-contracts/context-contributions';\nimport {\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n requireDoomMcpToolResolver,\n} from '@agimon-ai/doompi-extension-contracts/mcp-tool-resolver';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context, Fiber } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n registerSlashCommands,\n type SlashCommandDeps,\n type SlashCommandState,\n} from '../../commands/slash/slashCommands.ts';\nimport { loadConfig } from '../../extensions/config.ts';\nimport { createDelegationBridge } from '../../extensions/delegationBridge.ts';\nimport { createFablePlanBridge } from '../../extensions/fablePlanBridge.ts';\nimport type { IManagementActions } from '../../extensions/managementActions.ts';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from '../../extensions/orchestratorPrompt.ts';\nimport { captureSessionForkSource, type ISpawnPlanner } from '../../extensions/spawnPlan.ts';\nimport type { ISkillDiscoveryService } from '../../services/agents/skills.ts';\nimport type { IAgentDiscoveryService } from '../../services/agents/types.ts';\nimport { formatTeamContextSnapshot, readActiveTeamSnapshot } from '../../services/api/teamSnapshot.ts';\nimport {\n type IAsyncJobTracker,\n type ITrackedAsyncJobs,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../../services/runs/background/asyncJobTracker.ts';\nimport { openScopeAsync, suspendScopeRuns } from '../../services/runs/registry/sessionLifecycle.ts';\nimport { formatSuspendedRunsAsync } from '../../services/runs/registry/suspendedRuns.ts';\nimport { normalizeParentModel } from '../../services/runs/shared/modelFallback.ts';\nimport { authenticatedModelInfos } from '../../shared/modelResolution.ts';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../../shared/paths.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\nimport { writeScopeOwnerAsync } from '../../shared/scopeOwner.ts';\nimport { registerCompletionRenderer } from '../../tui/completionNotice.ts';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from '../../tui/register.ts';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration.ts';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime.ts';\n\n/** See the subscriber's own comment for why crash detection does not need the 250ms floor. */\nconst STALE_RUN_RECONCILE_INTERVAL_MS = 2_000;\nconst SESSION_SHUTDOWN_REASON_FALLBACK = 'unknown';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-team';\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\n\nfunction boundPiValue(target: ExtensionAPI, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction readinessNotificationMessage(notification: DoomReadinessNotification): string {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n return `${notification.packageId} initialization ${notification.state}: ${detail}`;\n}\n\nfunction buildSlashCommandDeps(\n discovery: IAgentDiscoveryService,\n skills: ISkillDiscoveryService,\n planner: ISpawnPlanner,\n tracker: IAsyncJobTracker,\n scheduler: IPollScheduler,\n management: IManagementActions,\n): SlashCommandDeps {\n return {\n spawnPlanner: planner,\n tracker,\n scheduler,\n discovery,\n skills,\n management,\n loadConfig: () => loadConfig().config,\n };\n}\n\nfunction recordDelegationObservation(telemetry: DoomTelemetry, observation: TeamDelegationObservation): void {\n if (observation.kind === 'requested') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_requested', {\n 'agent.name': event.agent,\n 'task.id': event.taskId,\n mode: event.runMode ?? 'foreground',\n });\n } else if (observation.kind === 'started') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.child_started', { 'run.id': event.runId, outcome: 'started' });\n } else if (observation.kind === 'updated') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_updated', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n 'team.token_count': event.tokens ?? 0,\n outcome: event.status ?? 'updated',\n });\n } else if (observation.kind === 'finished') {\n const { event } = observation;\n void telemetry.recordEvent('doom_team.delegation_finished', {\n 'run.id': event.runId,\n 'team.tool_count': event.toolCount ?? 0,\n 'team.duration_ms': event.durationMs ?? 0,\n outcome: event.status,\n });\n } else {\n void telemetry.recordEvent('doom_team.delegation_cancelled', { outcome: 'cancelled' });\n }\n}\n\n/**\n * The extension factory pi's loader calls, exported as the module default\n * (see the override this file carries in `vibe-lint.config.yaml`). This is an\n * ESM `.ts` module, so it CANNOT use the `export =` form that\n * `subagentPromptRuntimeEntry.cts` is required to use - that file is `.cts`\n * and is resolved by raw path, this one is resolved as a package subpath and\n * matches the `export default` convention every sibling extension in this repo\n * already uses (`doom-task`, `doom-file-edit`, `doom-pi-ui`).\n */\nexport function installTeamRuntime(cordis: Context, pi: ExtensionAPI): TeamExtensionRuntime {\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-team',\n packageName: '@agimon-ai/doompi-team',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n const reportConcurrencyEvent = (event: string, attributes: Record<string, unknown>): void => {\n void telemetry?.recordEvent(event, attributes);\n };\n cordis.effect(\n () => async () => {\n await telemetry?.shutdown();\n telemetry = undefined;\n },\n '@agimon-ai/doompi-team/telemetry',\n );\n const runtime = createTeamExtensionRuntime(reportConcurrencyEvent);\n const {\n subagentTool,\n teamChannel,\n pollScheduler,\n asyncJobTracker,\n subagentWaiter,\n asyncSubagentSpawner,\n discovery,\n skills,\n spawnPlanner,\n completionNotifier,\n resultWatcher,\n staleRunReconciler,\n management,\n capabilityPolicies,\n mcpToolResolver,\n } = runtime;\n\n let active = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let readinessSessionManager: object | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n let readinessNotificationContext: ExtensionContext | undefined;\n let activeCordisSession:\n | {\n readonly cordis: Context;\n readonly service: DoomCordisSessionService;\n }\n | undefined;\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], (sessionContext) => {\n const service = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const binding = { cordis: sessionContext, service };\n activeCordisSession = binding;\n sessionContext.inject([DOOM_MCP_TOOL_RESOLVER_SERVICE], (resolverContext) =>\n mcpToolResolver.bind(requireDoomMcpToolResolver(resolverContext)),\n );\n sessionContext.inject([DOOM_CONTEXT_CONTRIBUTIONS_SERVICE], (contributionContext) => {\n const registration = requireDoomContextContributions(contributionContext).register({\n source: PACKAGE_SOURCE,\n id: 'runtime',\n label: 'Team',\n order: 200,\n snapshot: () => formatTeamContextSnapshot(readActiveTeamSnapshot()),\n });\n return () => registration.dispose();\n });\n sessionContext.effect(\n () => () => {\n if (activeCordisSession === binding) activeCordisSession = undefined;\n },\n `${PACKAGE_SOURCE}/cordis-session`,\n );\n });\n const coordinatorFor = (ctx: ExtensionContext): DoomReadinessCoordinator => {\n const cordisSession = activeCordisSession;\n const sessionId = ctx.sessionManager.getSessionId();\n const activeSessionMatches =\n cordisSession?.service.context.sessionManager === ctx.sessionManager &&\n cordisSession.service.sessionId === sessionId;\n const shared = activeSessionMatches ? readDoomReadinessCoordinator(cordisSession.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n const message = readinessNotificationMessage(notification);\n if (readinessNotificationContext?.hasUI) readinessNotificationContext.ui.notify(message, 'warning');\n else process.emitWarning(message);\n },\n });\n return standaloneReadiness;\n };\n const waitForSessionReadiness = async (ctx: ExtensionContext, signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Doom Team session initialization has not started.');\n if (readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale Pi session.');\n }\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!active || pending !== readinessHandle || readinessSessionManager !== ctx.sessionManager) {\n throw new Error('Doom Team readiness belongs to a stale extension generation.');\n }\n };\n const readinessPi = new Proxy(pi, {\n get(target, property) {\n if (property === 'registerTool') {\n return (tool: RegisteredTool): void => {\n target.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, ctx) => {\n await waitForSessionReadiness(ctx, signal);\n return tool.execute(toolCallId, params, signal, onUpdate, ctx);\n },\n });\n };\n }\n if (property === 'registerCommand') {\n return (name: string, options: CommandOptions): void => {\n target.registerCommand(name, {\n ...options,\n handler: async (args, ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(args, ctx);\n },\n });\n };\n }\n if (property === 'registerShortcut') {\n return (shortcut: Parameters<ExtensionAPI['registerShortcut']>[0], options: ShortcutOptions): void => {\n target.registerShortcut(shortcut, {\n ...options,\n handler: async (ctx) => {\n await waitForSessionReadiness(ctx);\n return options.handler(ctx);\n },\n });\n };\n }\n return boundPiValue(target, property);\n },\n });\n\n subagentTool.registerTool(readinessPi);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerSubagentLeaderContribution(requireDoomUiHub(uiContext)));\n\n const teamRuntime = teamChannel.createRuntime(readinessPi);\n cordis.effect(() => () => teamRuntime.dispose(), '@agimon-ai/doompi-team/channel');\n teamChannel.registerClient(readinessPi);\n\n // Attach before `ResultWatcher.start()`, which `session_start` drives.\n completionNotifier.attachHost(pi);\n cordis.effect(() => () => completionNotifier.dispose(), '@agimon-ai/doompi-team/completions');\n\n pollScheduler.start();\n cordis.effect(() => () => pollScheduler.stop(), '@agimon-ai/doompi-team/polling');\n\n asyncJobTracker.start();\n cordis.effect(() => () => asyncJobTracker.stop(), '@agimon-ai/doompi-team/jobs');\n\n let collaborationFiber: Fiber | undefined;\n let currentSessionJobs: ITrackedAsyncJobs | undefined;\n // The scope `ResultWatcher` is currently watching. See its start site in\n // the `session_start` handler for why the watcher is latched on this\n // rather than started once.\n let watchedScopeKey: string | undefined;\n const delegationBridge = createDelegationBridge({\n planner: spawnPlanner,\n management,\n waiter: subagentWaiter,\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n loadConfig: () => loadConfig().config,\n });\n const fablePlanBridge = createFablePlanBridge({\n spawner: asyncSubagentSpawner,\n waiter: subagentWaiter,\n management,\n policies: capabilityPolicies,\n report: (event, attributes) => {\n void telemetry?.recordEvent(event, attributes);\n },\n });\n cordis.effect(\n () => async () => {\n await collaborationFiber?.dispose();\n collaborationFiber = undefined;\n },\n '@agimon-ai/doompi-team/collaboration',\n );\n cordis.effect(\n () => () => {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n },\n '@agimon-ai/doompi-team/result-watcher',\n );\n\n const unregisterStaleRunReconciler = pollScheduler.register({\n id: 'stale-run-reconciler',\n // Crash detection, not status freshness - `AsyncJobTracker` owns that and\n // polls on its own 250ms. This subscriber only ever acts on a run whose\n // process is provably dead, so noticing that 2s later is invisible, while\n // running it 4x/second per active run was not: each pass is a status read,\n // a run-id resolve and a pid probe that a healthy child always discards.\n intervalMs: STALE_RUN_RECONCILE_INTERVAL_MS,\n run: async () => {\n let repaired = false;\n let hasActiveRun = false;\n for (const job of currentSessionJobs?.list() ?? []) {\n if (job.status && TERMINAL_ASYNC_JOB_STATES.has(job.status)) continue;\n hasActiveRun = true;\n // One pass, one `inspect()`. Calling `reconcile` and\n // `sweepOrphanedClaims` separately probed the same pid twice for the\n // same answer - see `IStaleRunReconciler.reconcileAndSweep`.\n const { reconcile: outcome, sweep } = staleRunReconciler.reconcileAndSweepAsync\n ? await staleRunReconciler.reconcileAndSweepAsync(job.runId)\n : staleRunReconciler.reconcileAndSweep(job.runId);\n if (outcome.repaired) {\n currentSessionJobs?.track(job.runId);\n repaired = true;\n }\n if (sweep.recovered.length > 0) repaired = true;\n }\n // An active runner is useful work for scheduling purposes: keeping\n // the shared scheduler at its floor prevents crash detection from\n // inheriting the idle five-second backoff ceiling.\n return repaired || hasActiveRun;\n },\n });\n cordis.effect(() => unregisterStaleRunReconciler, '@agimon-ai/doompi-team/stale-runs');\n // The orchestration addendum. Registered here rather than inside the\n // `subagent` tool's description because it is behavioural guidance, and it\n // has to land before the model decides whether to reach for the tool at\n // all - see `orchestratorPrompt.ts`. Read config per turn so toggling it\n // does not need a session restart; `loadConfig` is memoized on the file's\n // own mtime, so this is a stat, not a read.\n pi.on('before_agent_start', (event: { systemPrompt?: string }) => {\n if (!active || !shouldInjectOrchestratorPrompt(loadConfig().config)) return undefined;\n return { systemPrompt: appendOrchestratorPrompt(event.systemPrompt) };\n });\n\n const state: SlashCommandState = { baseCwd: undefined };\n registerSlashCommands(\n readinessPi,\n state,\n buildSlashCommandDeps(discovery, skills, spawnPlanner, asyncJobTracker, pollScheduler, management),\n );\n registerAgentListCommand(readinessPi, { discovery, skills, policies: capabilityPolicies });\n registerFleetCommand(readinessPi, {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n management,\n });\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerAgentStatus(pi, requireDoomUiHub(uiContext), {\n scheduler: pollScheduler,\n tracker: asyncJobTracker,\n });\n });\n registerCompletionRenderer(pi);\n\n const retireSessionBindings = async (): Promise<Error | undefined> => {\n const errors: unknown[] = [];\n const previousCollaboration = collaborationFiber;\n collaborationFiber = undefined;\n try {\n await previousCollaboration?.dispose();\n } catch (error) {\n errors.push(error);\n }\n for (const cleanup of [\n () => capabilityPolicies.clear(),\n () => delegationBridge.abandonAll(),\n () => fablePlanBridge.abandonAll(),\n () => teamRuntime.dispose(),\n ]) {\n try {\n cleanup();\n } catch (error) {\n errors.push(error);\n }\n }\n currentSessionJobs = undefined;\n if (errors.length === 0) return undefined;\n if (errors.length === 1 && errors[0] instanceof Error) return errors[0];\n return new AggregateError(errors, 'Team session cleanup failed.');\n };\n\n // Bind the root session directly into the one intercom transport. Child\n // processes bind from the team environment written during spawn.\n pi.on('session_start', (_event, ctx: ExtensionContext) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort(new Error('Doom Team session initialization was superseded.'));\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n readinessSessionManager = ctx.sessionManager;\n readinessNotificationContext = ctx;\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_team.session_started', {\n 'team.root_session':\n resolveRootSessionId(ctx.sessionManager.getSessionId()) === ctx.sessionManager.getSessionId(),\n });\n // Before anything else: every scoped path helper reads this. A child\n // keeps the root inherited from its spawn environment, while a top-level\n // session falls back to its own Pi session id.\n const sessionId = ctx.sessionManager.getSessionId();\n const scope = createSessionScope(resolveRootSessionId(sessionId));\n setCurrentSessionScope(scope);\n state.baseCwd = ctx.cwd;\n if (watchedScopeKey !== undefined && watchedScopeKey !== scope.scopeKey) {\n resultWatcher.stop();\n watchedScopeKey = undefined;\n }\n const retirement = retireSessionBindings();\n const coordinator = coordinatorFor(ctx);\n const ownsSession = (): boolean =>\n active &&\n ownGeneration === sessionGeneration &&\n readinessSessionManager === ctx.sessionManager &&\n !ownReadinessAbort.signal.aborted;\n\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Doom Team session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${sessionId}:${ownGeneration}`, async (signal) => {\n signal.throwIfAborted();\n const retirementError = await retirement;\n if (retirementError) throw retirementError;\n if (!ownsSession()) return { value: undefined };\n // Claim the scope for this process, so a later sweep can tell an\n // abandoned tree from a live one. Rewritten on every session_start\n // because /resume legitimately re-adopts a scope under a new process.\n await writeScopeOwnerAsync(scope);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n // Prune records whose process is gone, reap sibling scopes holding\n // nothing alive, and REPORT what is suspended. Nothing is restarted:\n // reopening a session must not silently spend tokens on stale work.\n const opened = await openScopeAsync(scope, {\n readStatusAsync: async (runId) =>\n management.statusAsync ? (await management.statusAsync(runId)).status : management.status(runId).status,\n });\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n if (opened.suspended.length > 0 && ctx.hasUI) {\n const message = await formatSuspendedRunsAsync(opened.suspended);\n signal.throwIfAborted();\n if (!ownsSession()) return { value: undefined };\n ctx.ui.notify(message, 'info');\n }\n void activeTelemetry.recordEvent('doom_team.runs_restored', {\n 'team.suspended_count': opened.suspended.length,\n 'team.pruned_count': opened.pruned.length,\n 'team.reaped_count': opened.reaped,\n outcome: 'reported',\n });\n currentSessionJobs = asyncJobTracker.forSession(sessionId);\n // ResultWatcher needs the session scope, but a repeated start for the\n // same scope must not reset its in-flight claims.\n if (watchedScopeKey !== scope.scopeKey) {\n watchedScopeKey = scope.scopeKey;\n resultWatcher.start((result) =>\n currentSessionJobs?.get(result.runId) ? completionNotifier.deliver(result) : false,\n );\n }\n const parentModel = normalizeParentModel(ctx.model);\n const activeSession = activeCordisSession;\n const collaborationParent =\n activeSession?.service.context.sessionManager === ctx.sessionManager ? activeSession.cordis : cordis;\n const nextCollaboration = collaborationParent.plugin(teamCollaborationPlugin, {\n session: {\n sessionId,\n cwd: ctx.cwd,\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n forkSource: captureSessionForkSource(ctx.sessionManager, 'tool'),\n },\n delegation: delegationBridge,\n fablePlan: fablePlanBridge,\n policies: capabilityPolicies,\n observeDelegation: (observation) => recordDelegationObservation(activeTelemetry, observation),\n });\n collaborationFiber = nextCollaboration;\n await nextCollaboration.await();\n if (!ownsSession()) {\n await nextCollaboration.dispose();\n if (collaborationFiber === nextCollaboration) collaborationFiber = undefined;\n return { value: undefined };\n }\n teamRuntime.bindMainSession(sessionId);\n return { value: undefined };\n });\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n return undefined;\n });\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team runtime was disposed.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) await ownedReadiness.dispose();\n else if (pendingReadiness) await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n readinessNotificationContext = undefined;\n },\n '@agimon-ai/doompi-team/session-fence',\n );\n\n /**\n * Every reason suspends, with no exception for `reload`.\n *\n * Pi emits this for `quit`, `reload`, `new`, `resume` and `fork`. Treating\n * `reload` differently - keeping children alive because `/domains`, `/major-mode`\n * and `/profile` only reload the extension - would be the one case someone\n * has to remember, and the one that silently misbehaves if Pi adds a sixth\n * reason. Suspending uniformly costs a respawn on reload; restore continues\n * the child's own transcript rather than restarting its task.\n */\n let shutdownPromise: Promise<void> | undefined;\n const shutdownSession = async (event: { reason?: string }): Promise<void> => {\n active = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessSessionManager = undefined;\n readinessAbort?.abort(new Error('Doom Team session ended.'));\n readinessAbort = undefined;\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n await Promise.allSettled([\n ...(pendingReadiness ? [pendingReadiness.then((handle) => handle.wait())] : []),\n ...(ownedReadiness ? [ownedReadiness.dispose()] : []),\n ]);\n const scope = tryCurrentSessionScope();\n const suspensionPromise = scope\n ? suspendScopeRuns({\n scope,\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n readStatus: (runId) => management.status(runId).status,\n })\n : Promise.resolve(undefined);\n let suspension: Awaited<ReturnType<typeof suspendScopeRuns>> | undefined;\n try {\n suspension = await suspensionPromise;\n await telemetry?.recordEvent('doom_team.session_finished', {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n 'team.suspended_count': suspension?.suspended.length ?? 0,\n 'team.unstoppable_count': suspension?.unstoppable.length ?? 0,\n outcome: suspension?.unstoppable.length ? 'degraded' : 'suspended',\n });\n } catch (error) {\n await telemetry?.recordError('doom_team.session_shutdown_failed', error, {\n reason: event.reason ?? SESSION_SHUTDOWN_REASON_FALLBACK,\n });\n } finally {\n await telemetry?.shutdown();\n telemetry = undefined;\n }\n };\n pi.on('session_shutdown', (event: { reason?: string }) => {\n shutdownPromise ??= shutdownSession(event);\n return shutdownPromise;\n });\n\n return runtime;\n}\n"],"mappings":"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"}
|