@agimon-ai/doompi-team 0.0.1-alpha.34 → 0.0.1-alpha.35
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/dist/src/adapters/pi/commands/slash/slashCommands.cjs +3 -3
- package/dist/src/adapters/pi/commands/slash/slashCommands.cjs.map +1 -1
- package/dist/src/adapters/pi/commands/slash/slashCommands.mjs +3 -3
- package/dist/src/adapters/pi/commands/slash/slashCommands.mjs.map +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/tui/agentCatalog.cjs +2 -1
- package/dist/src/adapters/pi/tui/agentCatalog.cjs.map +1 -1
- package/dist/src/adapters/pi/tui/agentCatalog.mjs +2 -1
- package/dist/src/adapters/pi/tui/agentCatalog.mjs.map +1 -1
- package/dist/src/adapters/pi/tui/fleet.cjs +2 -2
- package/dist/src/adapters/pi/tui/fleet.cjs.map +1 -1
- package/dist/src/adapters/pi/tui/fleet.mjs +2 -2
- package/dist/src/adapters/pi/tui/fleet.mjs.map +1 -1
- package/dist/src/adapters/pi/tui/register.cjs +1 -1
- package/dist/src/adapters/pi/tui/register.cjs.map +1 -1
- package/dist/src/adapters/pi/tui/register.mjs +1 -1
- package/dist/src/adapters/pi/tui/register.mjs.map +1 -1
- package/dist/src/adapters/pi/tui/slashRunNotice.cjs +3 -0
- package/dist/src/adapters/pi/tui/slashRunNotice.cjs.map +1 -0
- package/dist/src/adapters/pi/tui/slashRunNotice.mjs +3 -0
- package/dist/src/adapters/pi/tui/slashRunNotice.mjs.map +1 -0
- package/package.json +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require("../../../../services/models/modelResolution.cjs"),t=require("../../../runs/shared/modelFallback.cjs"),n=require("../../extensions/spawnPlan.cjs"),r=require("../../../asyncJobTracker.cjs"),i=require("./chainExpression.cjs"),a=require("./doctor.cjs"),o=require("./spawnRequestMapping.cjs"),s=require("./subagentLaunch.cjs")
|
|
2
|
-
`)}`)}function
|
|
3
|
-
`)}exports.registerSlashCommands=y;
|
|
1
|
+
const e=require("../../../../services/models/modelResolution.cjs"),t=require("../../../runs/shared/modelFallback.cjs"),n=require("../../extensions/spawnPlan.cjs"),r=require("../../../asyncJobTracker.cjs"),i=require("./chainExpression.cjs"),a=require("./doctor.cjs"),o=require("./spawnRequestMapping.cjs"),s=require("./subagentLaunch.cjs"),c=`subagent-slash-result`;function l(e,t,n){e.sendMessage({customType:c,content:t,display:!0,...n?{details:n}:{}})}function u(e,t){e.hasUI&&e.ui.setStatus(`subagent-slash`,t)}function d(e,t){e.ui.notify(t,`error`)}function f(e,t){e.ui.notify(t,`info`)}function p(e){return e?e.attentionReason?`${e.status??`running`} - needs attention: ${e.attentionReason}`:e.activityState?`${e.status??`running`} - ${e.activityState}`:e.status??`running`:`starting…`}function m(e,t,n,i,a,o){s.watchTrackedRunUntilTerminal(n.scheduler,i,a,n=>{if(u(t,`${o} (${a}): ${p(n)}`),n?.status===void 0||!r.TERMINAL_ASYNC_JOB_STATES.has(n.status))return;u(t,void 0);let i=n.status===`complete`||n.status===`completed`?`completed`:n.status;l(e,n.error?`## Subagent ${i}\n\n${o} (${a})\n\n${n.error}`:`## Subagent ${i}\n\n${o} (${a})`,[{agent:o,runId:a,status:i,...n.error?{error:n.error}:{}}])})}function h(e,t,n,r,i){let a=i.outcomes.filter(e=>e.runId),o=i.outcomes.filter(e=>!e.runId);if(a.length>0){l(e,`## Subagent started\n\n${a.map(e=>`${e.agent} (${e.runId})${e.warning?`\n Warning: ${e.warning}`:``}`).join(`, `)}`,a.map(e=>({agent:e.agent,runId:e.runId??``,status:`started`,...e.warning?{warning:e.warning}:{}}))),u(t,`${a.length} run${a.length===1?``:`s`} started…`);for(let i of a)i.runId&&m(e,t,n,r,i.runId,i.agent)}o.length>0&&d(t,`Some subagents failed to start:\n${o.map(e=>`${e.agent}: ${e.error??`spawn failed`}`).join(`
|
|
2
|
+
`)}`)}function g(e,t){if(e.baseCwd)return e.baseCwd;d(t,`Subagent session cwd is not initialized yet`)}function _(e,t,n,r){return e.discovery.discover(t,`both`).agents.find(e=>e.name===n)?!0:(d(r,`Unknown agent: ${n}`),!1)}async function v(r,a,c,l,u){let d=c.baseCwd;if(!d)return{ok:!1,message:`Subagent session cwd is not initialized yet`};if(!l.discovery.discover(d,`both`).agents.find(e=>e.name===u.agent))return{ok:!1,message:`Unknown agent: ${u.agent}`};let f=l.tracker.forSession(a.sessionManager.getSessionId());try{let i=n.captureSessionForkSource(a.sessionManager,`settled`),c=t.normalizeParentModel(a.model),p=o.taskInputFromParsedStep({name:u.agent,config:u.config??{},task:u.task},d,u.fork?`fork`:void 0),m=await s.launchSingleSubagent(l.spawnPlanner,f,{agent:p.agent,task:p.task??``,cwd:p.cwd??d,agentScope:`both`,parentSessionId:a.sessionManager.getSessionId(),...p.model?{model:p.model}:{},...p.context?{context:p.context}:{},...i?{parentSessionFile:i.sessionFile,parentLeafId:i.leafId}:{},availableModels:e.authenticatedModelInfos(a.modelRegistry),...c?{parentModel:c}:{}},l.loadConfig());return h(r,a,l,f,m),{ok:!0,result:m}}catch(e){if(e instanceof o.UnsupportedInlineConfigError||e instanceof i.SlashParseError)return{ok:!1,message:e.message};throw e}}function y(e,t,n,r,i){v(e,t,n,r,i).then(e=>{e.ok||d(t,e.message)},e=>{d(t,`Subagent launch failed: ${e instanceof Error?e.message:String(e)}`)})}function b(e,t){if(t instanceof o.UnsupportedInlineConfigError||t instanceof i.SlashParseError){d(e,t.message);return}throw t}function x(e){let t=e.trim();if(t.includes(` -> `)){let e=t.split(` -> `).map(e=>e.trim()).filter(Boolean).map(e=>i.parseSingleTaskToken(e));return e.length===0?void 0:{steps:e,task:e.find(e=>e.task)?.task??``,perStep:!0}}let n=t.indexOf(` -- `);if(n===-1)return;let r=t.slice(0,n).trim(),a=t.slice(n+4).trim();if(!r||!a)return;let o=r.split(/\s+/).filter(Boolean).map(e=>i.parseSingleTaskToken(e));if(o.length!==0)return{steps:o,task:a,perStep:!1}}function S(c,u,p){c.registerCommand(`run`,{description:`Run a subagent in the background: /run agent[model=x] [task] [--fork]`,handler:async(e,t)=>{let{args:n,fork:r}=i.extractForkFlag(e),a=n.trim();if(!a){d(t,`Usage: /run <agent> [task] [--fork]`);return}let o=a.indexOf(` `),{name:s,config:l}=i.parseAgentToken(o===-1?a:a.slice(0,o)),f=await v(c,t,u,p,{agent:s,task:o===-1?``:a.slice(o+1).trim(),config:l,fork:r});f.ok||d(t,f.message)}}),c.registerCommand(`parallel`,{description:`Run agents in parallel: /parallel scout "task1" -> reviewer "task2" [--fork]`,handler:async(r,a)=>{let l=p.tracker.forSession(a.sessionManager.getSessionId()),{args:f,fork:m}=i.extractForkFlag(r),v=g(u,a);if(!v)return;let y=x(f);if(!y){d(a,`Usage: /parallel agent1 "task1" -> agent2 "task2"`);return}for(let e of y.steps)if(!_(p,v,e.name,a))return;if(!y.steps.some(e=>e.task)&&!y.task){d(a,`At least one step must have a task`);return}try{let r=n.captureSessionForkSource(a.sessionManager,`settled`),i=t.normalizeParentModel(a.model),u=y.steps.map(e=>o.taskInputFromParsedStep({name:e.name,config:e.config,task:e.task??y.task},v,m?`fork`:void 0));h(c,a,p,l,await s.launchParallelSubagents(p.spawnPlanner,l,{tasks:u,cwd:v,agentScope:`both`,parentSessionId:a.sessionManager.getSessionId(),...r?{parentSessionFile:r.sessionFile,parentLeafId:r.leafId}:{},availableModels:e.authenticatedModelInfos(a.modelRegistry),...i?{parentModel:i}:{}},p.loadConfig()))}catch(e){b(a,e)}}}),c.registerCommand(`subagents-doctor`,{description:`Show subagent diagnostics`,handler:async(e,t)=>{l(c,a.buildDoctorReport({cwd:t.cwd,agentScope:`both`},{discovery:p.discovery,skills:p.skills}))}}),c.registerCommand(`subagents-stop`,{description:`Stop a running subagent: /subagents-stop [run-id]`,handler:async(e,t)=>{let n=p.tracker.forSession(t.sessionManager.getSessionId()),i=e.trim();if(!i){l(c,C(n.list()));return}try{p.management.stop(r.resolveTrackedRunId(n,i)),f(t,`Stop requested for ${i}. The run reports its own final state once it acknowledges.`)}catch(e){d(t,e instanceof Error?e.message:`Could not stop '${i}'.`)}}})}function C(e){let t=e.filter(e=>e.status===`running`||e.status===`pending`);return t.length===0?`No running subagents to stop.`:[`Running subagents:`,...t.map(e=>`- ${e.runId}${e.status?` (${e.status})`:``}`),``,"Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively."].join(`
|
|
3
|
+
`)}exports.SLASH_RESULT_CUSTOM_TYPE=c,exports.launchSingleAgentRun=v,exports.registerSlashCommands=S,exports.startSingleAgentRun=y;
|
|
4
4
|
//# sourceMappingURL=slashCommands.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slashCommands.cjs","names":["TERMINAL_ASYNC_JOB_STATES","UnsupportedInlineConfigError","SlashParseError","parseSingleTaskToken","extractForkFlag","parseAgentToken","captureSessionForkSource","normalizeParentModel","taskInputFromParsedStep","launchSingleSubagent","authenticatedModelInfos","launchParallelSubagents","buildDoctorReport","resolveTrackedRunId"],"sources":["../../../../../../src/adapters/pi/commands/slash/slashCommands.ts"],"sourcesContent":["/**\n * The core `/run`, `/chain`, `/parallel` slash commands. Replaces the\n * always-blocking predecessor with the async-only shape this port settled\n * on: a command launches a spawn, sends an initial status message, and\n * hands off to `watchTrackedRunUntilTerminal` (render-key gated, backed by\n * `PollScheduler`) to update the status bar and finalize the message once\n * the run reaches a terminal state - never by awaiting completion. See\n * `subagentLaunch.ts`'s module doc for the full reasoning.\n *\n * WHAT IS NOT HERE, AND WHY:\n * - `/run-chain`, `/prompt-workflow` and `/chain-prompts`: the whole SAVED\n * work surface - saved agent pipelines (`ChainConfig`, never ported) and\n * saved `.md` prompt templates (ported, then deleted). REMOVED BY\n * DECISION, not deferred: overly complicated for the use they were\n * getting. Do not re-add them because a reader notices the predecessor had\n * them. Ad-hoc chaining (`/chain scout \"x\" -> planner`) is a different\n * feature, lives in `chainExpression.ts`, and stays\n * - `/subagent-cost`: REMOVED BY DECISION. It reads usage/cost data\n * (`totalTokens`/`totalCost`) that nothing in this package's\n * runs/extensions surface tracks - a genuinely absent data source, and\n * building it would mean threading usage out of every child process\n * - `/subagents-check-profile`: removed at the source. Calls\n * `checkSubagentProfile`/`listSubagentProfiles`, which are referenced but\n * defined nowhere in the entire predecessor package - a live\n * `ReferenceError` that only shipped because that package sets\n * `noCheck: true`. Typecheck is on here; porting it faithfully would not\n * compile, and it was asked to be removed independently of that\n * - The `SUBAGENT_FLEET_COMMAND` registration and its `Ctrl+Alt+F` shortcut:\n * fleet view is its own piece, registered by whoever builds it\n * - Inline parallel groups within `/chain` (`(a | b)` syntax): the field\n * mapping for a group's own config exists (`spawnRequestMapping.ts`),\n * but wiring a group INTO a chain request is left for the same pass that\n * revisits per-task field support, so `/chain` reports a clear\n * not-yet-supported message rather than silently flattening a group\n * - `/subagents` (admin) command registration: a separate file, not yet\n * ported\n *\n * `/subagents-doctor` IS here, in `doctor.ts` - read (not ported) the\n * predecessor's foreground-executor `doctor` action before deciding, and it\n * turned out to be a small, mostly-mechanical port. See that module's own\n * doc for what it deliberately leaves out (chain counts, spawn-budget\n * reporting).\n *\n * AVOID:\n * - Awaiting a SINGLE/PARALLEL spawn for a result that will not exist yet.\n * See `subagentLaunch.ts`\n * - A private polling loop for a message's live status. Use\n * `watchTrackedRunUntilTerminal`\n */\n\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { ExtensionConfig } from '../../extensions/config';\nimport type { ManagementActionsContract } from '../../extensions/managementActions';\nimport { captureSessionForkSource, type SpawnPlannerContract, type SpawnPlanResult } from '../../extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../../../agents/skills';\nimport type { AgentScope, AgentDiscoveryContract } from '../../../agents/types';\nimport type { AsyncJobTrackerContract, TrackedAsyncJobsContract, TrackedAsyncJob } from '../../../asyncJobTracker';\nimport { resolveTrackedRunId, TERMINAL_ASYNC_JOB_STATES } from '../../../asyncJobTracker';\nimport { normalizeParentModel } from '../../../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../../../services/models/modelResolution';\nimport type { PollSchedulerContract } from '../../../pollScheduler';\nimport {\n extractForkFlag,\n type ParsedStep,\n parseAgentToken,\n parseSingleTaskToken,\n SlashParseError,\n} from './chainExpression';\nimport { buildDoctorReport } from './doctor';\nimport { taskInputFromParsedStep, UnsupportedInlineConfigError } from './spawnRequestMapping';\nimport { launchParallelSubagents, launchSingleSubagent, watchTrackedRunUntilTerminal } from './subagentLaunch';\n\nexport interface SlashCommandDeps {\n spawnPlanner: SpawnPlannerContract;\n skills: SkillDiscoveryContract;\n tracker: AsyncJobTrackerContract;\n scheduler: PollSchedulerContract;\n discovery: AgentDiscoveryContract;\n /**\n * Used by `/subagents-stop`. Preferred over calling `requestSlashRunStop`\n * directly because it resolves an id PREFIX through `RunIdResolver` and\n * raises a real error for an unknown or ambiguous one, instead of writing a\n * stop request into a directory for a run that does not exist.\n */\n management: ManagementActionsContract;\n loadConfig: () => ExtensionConfig;\n}\n\nexport interface SlashCommandState {\n baseCwd: string | undefined;\n}\n\nconst SLASH_STATUS_KEY = 'subagent-slash';\nconst SLASH_RESULT_CUSTOM_TYPE = 'subagent-slash-result';\n\nfunction sendSlashText(pi: ExtensionAPI, text: string): void {\n pi.sendMessage({ customType: SLASH_RESULT_CUSTOM_TYPE, content: text, display: true });\n}\n\nfunction setSlashStatus(ctx: ExtensionContext, text: string | undefined): void {\n if (ctx.hasUI) ctx.ui.setStatus(SLASH_STATUS_KEY, text);\n}\n\nfunction notifyError(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'error');\n}\n\nfunction notifyInfo(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'info');\n}\n\nfunction statusTextFor(job: TrackedAsyncJob | undefined): string {\n if (!job) return 'starting…';\n if (job.attentionReason) return `${job.status ?? 'running'} - needs attention: ${job.attentionReason}`;\n if (job.activityState) return `${job.status ?? 'running'} - ${job.activityState}`;\n return job.status ?? 'running';\n}\n\n/**\n * Watches one launched run to a terminal state and finalizes its message.\n * Each launched run gets its own subscriber, so a PARALLEL launch's\n * siblings finalize independently rather than all waiting on the slowest.\n */\nfunction watchAndFinalize(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n runId: string,\n agent: string,\n): void {\n watchTrackedRunUntilTerminal(deps.scheduler, jobs, runId, (job) => {\n setSlashStatus(ctx, `${agent} (${runId}): ${statusTextFor(job)}`);\n if (job?.status === undefined || !TERMINAL_ASYNC_JOB_STATES.has(job.status)) return;\n setSlashStatus(ctx, undefined);\n const outcome = job.status === 'complete' || job.status === 'completed' ? 'completed' : job.status;\n sendSlashText(\n pi,\n job.error\n ? `## Subagent ${outcome}\\n\\n${agent} (${runId})\\n\\n${job.error}`\n : `## Subagent ${outcome}\\n\\n${agent} (${runId})`,\n );\n });\n}\n\nfunction reportSpawnResult(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n result: SpawnPlanResult,\n): void {\n const started = result.outcomes.filter((outcome) => outcome.runId);\n const failed = result.outcomes.filter((outcome) => !outcome.runId);\n if (started.length > 0) {\n const label = started\n .map(\n (outcome) => `${outcome.agent} (${outcome.runId})${outcome.warning ? `\\n Warning: ${outcome.warning}` : ''}`,\n )\n .join(', ');\n sendSlashText(pi, `## Subagent started\\n\\n${label}`);\n setSlashStatus(ctx, `${started.length} run${started.length === 1 ? '' : 's'} started…`);\n for (const outcome of started) {\n if (outcome.runId) watchAndFinalize(pi, ctx, deps, jobs, outcome.runId, outcome.agent);\n }\n }\n if (failed.length > 0) {\n const label = failed.map((outcome) => `${outcome.agent}: ${outcome.error ?? 'spawn failed'}`).join('\\n');\n notifyError(ctx, `Some subagents failed to start:\\n${label}`);\n }\n}\n\nfunction requireBaseCwd(state: SlashCommandState, ctx: ExtensionContext): string | undefined {\n if (state.baseCwd) return state.baseCwd;\n notifyError(ctx, 'Subagent session cwd is not initialized yet');\n return undefined;\n}\n\nfunction findAgentOrNotify(deps: SlashCommandDeps, baseCwd: string, name: string, ctx: ExtensionContext): boolean {\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (agents.find((agent) => agent.name === name)) return true;\n notifyError(ctx, `Unknown agent: ${name}`);\n return false;\n}\n\nfunction reportKnownErrorOrRethrow(ctx: ExtensionContext, error: unknown): void {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n notifyError(ctx, error.message);\n return;\n }\n throw error;\n}\n\n/**\n * Shared arg parsing for /chain (no inline group) and /parallel:\n * \"agent1 task1 -> agent2 task2\" or \"agent1 agent2 -- shared task\".\n */\nfunction parseAgentArgsFallback(input: string): { steps: ParsedStep[]; task: string; perStep: boolean } | undefined {\n const trimmed = input.trim();\n if (trimmed.includes(' -> ')) {\n const steps = trimmed\n .split(' -> ')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .map((segment) => parseSingleTaskToken(segment));\n if (steps.length === 0) return undefined;\n return { steps, task: steps.find((step) => step.task)?.task ?? '', perStep: true };\n }\n const delimiterIndex = trimmed.indexOf(' -- ');\n if (delimiterIndex === -1) return undefined;\n const agentsPart = trimmed.slice(0, delimiterIndex).trim();\n const sharedTask = trimmed.slice(delimiterIndex + 4).trim();\n if (!agentsPart || !sharedTask) return undefined;\n const steps = agentsPart\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => parseSingleTaskToken(token));\n if (steps.length === 0) return undefined;\n return { steps, task: sharedTask, perStep: false };\n}\n\nexport function registerSlashCommands(pi: ExtensionAPI, state: SlashCommandState, deps: SlashCommandDeps): void {\n pi.registerCommand('run', {\n description: 'Run a subagent in the background: /run agent[model=x] [task] [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const input = cleanedArgs.trim();\n if (!input) {\n notifyError(ctx, 'Usage: /run <agent> [task] [--fork]');\n return;\n }\n const firstSpace = input.indexOf(' ');\n const { name: agentName, config } = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace));\n const task = firstSpace === -1 ? '' : input.slice(firstSpace + 1).trim();\n\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n if (!findAgentOrNotify(deps, baseCwd, agentName, ctx)) return;\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const taskInput = taskInputFromParsedStep(\n { name: agentName, config, task },\n baseCwd,\n fork ? 'fork' : undefined,\n );\n const result = await launchSingleSubagent(\n deps.spawnPlanner,\n jobs,\n {\n agent: taskInput.agent,\n task: taskInput.task ?? '',\n cwd: taskInput.cwd ?? baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(taskInput.model ? { model: taskInput.model } : {}),\n ...(taskInput.context ? { context: taskInput.context } : {}),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('parallel', {\n description: 'Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n\n const parsed = parseAgentArgsFallback(cleanedArgs);\n if (!parsed) {\n notifyError(ctx, 'Usage: /parallel agent1 \"task1\" -> agent2 \"task2\"');\n return;\n }\n for (const step of parsed.steps) {\n if (!findAgentOrNotify(deps, baseCwd, step.name, ctx)) return;\n }\n if (!parsed.steps.some((step) => step.task) && !parsed.task) {\n notifyError(ctx, 'At least one step must have a task');\n return;\n }\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const tasks = parsed.steps.map((step) =>\n taskInputFromParsedStep(\n { name: step.name, config: step.config, task: step.task ?? parsed.task },\n baseCwd,\n fork ? 'fork' : undefined,\n ),\n );\n const result = await launchParallelSubagents(\n deps.spawnPlanner,\n jobs,\n {\n tasks,\n cwd: baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('subagents-doctor', {\n description: 'Show subagent diagnostics',\n handler: async (_args, ctx) => {\n sendSlashText(\n pi,\n buildDoctorReport({ cwd: ctx.cwd, agentScope: 'both' }, { discovery: deps.discovery, skills: deps.skills }),\n );\n },\n });\n\n pi.registerCommand('subagents-stop', {\n description: 'Stop a running subagent: /subagents-stop [run-id]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const id = args.trim();\n if (!id) {\n sendSlashText(pi, stoppableRunsReport(jobs.list()));\n return;\n }\n try {\n deps.management.stop(resolveTrackedRunId(jobs, id));\n // Deliberately reports the REQUEST, not the outcome. Stop is\n // asynchronous in this package: the request is a file the child\n // claims on its next control-channel tick, so claiming \"stopped\"\n // here would assert something this process has not observed. The\n // run's own status is what confirms it, via /subagents-fleet or a\n // completion notification.\n notifyInfo(ctx, `Stop requested for ${id}. The run reports its own final state once it acknowledges.`);\n } catch (error) {\n // `ManagementActions.stop` throws only for an id that resolves to no\n // run or to more than one. Both are bad user input, not internal\n // faults, so they are notified rather than rethrown at the host - the\n // same treatment `reportKnownErrorOrRethrow` gives a parse error.\n notifyError(ctx, error instanceof Error ? error.message : `Could not stop '${id}'.`);\n }\n },\n });\n}\n\n/**\n * The no-argument `/subagents-stop` listing.\n *\n * The predecessor opened a TUI selector overlay here. This reports the same\n * information as text instead, for one reason worth stating rather than\n * hiding: a selector is a second, independent renderer of run state, and this\n * package already has one in `/subagents-fleet` that shows more (live status,\n * transcripts, and the full set of runtime controls including stop). Building\n * a second, weaker one would mean two things to keep in step. Passing an\n * explicit id stays the direct path, and the fleet overlay is the interactive\n * one.\n */\nfunction stoppableRunsReport(runs: readonly TrackedAsyncJob[]): string {\n const stoppable = runs.filter((run) => run.status === 'running' || run.status === 'pending');\n if (stoppable.length === 0) return 'No running subagents to stop.';\n const lines = stoppable.map((run) => `- ${run.runId}${run.status ? ` (${run.status})` : ''}`);\n return [\n 'Running subagents:',\n ...lines,\n '',\n 'Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slashCommands.cjs","names":["TERMINAL_ASYNC_JOB_STATES","captureSessionForkSource","normalizeParentModel","taskInputFromParsedStep","launchSingleSubagent","authenticatedModelInfos","UnsupportedInlineConfigError","SlashParseError","parseSingleTaskToken","extractForkFlag","parseAgentToken","launchParallelSubagents","buildDoctorReport","resolveTrackedRunId"],"sources":["../../../../../../src/adapters/pi/commands/slash/slashCommands.ts"],"sourcesContent":["/**\n * The core `/run`, `/chain`, `/parallel` slash commands. Replaces the\n * always-blocking predecessor with the async-only shape this port settled\n * on: a command launches a spawn, sends an initial status message, and\n * hands off to `watchTrackedRunUntilTerminal` (render-key gated, backed by\n * `PollScheduler`) to update the status bar and finalize the message once\n * the run reaches a terminal state - never by awaiting completion. See\n * `subagentLaunch.ts`'s module doc for the full reasoning.\n *\n * WHAT IS NOT HERE, AND WHY:\n * - `/run-chain`, `/prompt-workflow` and `/chain-prompts`: the whole SAVED\n * work surface - saved agent pipelines (`ChainConfig`, never ported) and\n * saved `.md` prompt templates (ported, then deleted). REMOVED BY\n * DECISION, not deferred: overly complicated for the use they were\n * getting. Do not re-add them because a reader notices the predecessor had\n * them. Ad-hoc chaining (`/chain scout \"x\" -> planner`) is a different\n * feature, lives in `chainExpression.ts`, and stays\n * - `/subagent-cost`: REMOVED BY DECISION. It reads usage/cost data\n * (`totalTokens`/`totalCost`) that nothing in this package's\n * runs/extensions surface tracks - a genuinely absent data source, and\n * building it would mean threading usage out of every child process\n * - `/subagents-check-profile`: removed at the source. Calls\n * `checkSubagentProfile`/`listSubagentProfiles`, which are referenced but\n * defined nowhere in the entire predecessor package - a live\n * `ReferenceError` that only shipped because that package sets\n * `noCheck: true`. Typecheck is on here; porting it faithfully would not\n * compile, and it was asked to be removed independently of that\n * - The `SUBAGENT_FLEET_COMMAND` registration and its `Ctrl+Alt+F` shortcut:\n * fleet view is its own piece, registered by whoever builds it\n * - Inline parallel groups within `/chain` (`(a | b)` syntax): the field\n * mapping for a group's own config exists (`spawnRequestMapping.ts`),\n * but wiring a group INTO a chain request is left for the same pass that\n * revisits per-task field support, so `/chain` reports a clear\n * not-yet-supported message rather than silently flattening a group\n * - `/subagents` (admin) command registration: a separate file, not yet\n * ported\n *\n * `/subagents-doctor` IS here, in `doctor.ts` - read (not ported) the\n * predecessor's foreground-executor `doctor` action before deciding, and it\n * turned out to be a small, mostly-mechanical port. See that module's own\n * doc for what it deliberately leaves out (chain counts, spawn-budget\n * reporting).\n *\n * AVOID:\n * - Awaiting a SINGLE/PARALLEL spawn for a result that will not exist yet.\n * See `subagentLaunch.ts`\n * - A private polling loop for a message's live status. Use\n * `watchTrackedRunUntilTerminal`\n */\n\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { ExtensionConfig } from '../../extensions/config';\nimport type { ManagementActionsContract } from '../../extensions/managementActions';\nimport { captureSessionForkSource, type SpawnPlannerContract, type SpawnPlanResult } from '../../extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../../../agents/skills';\nimport type { AgentScope, AgentDiscoveryContract } from '../../../agents/types';\nimport type { AsyncJobTrackerContract, TrackedAsyncJobsContract, TrackedAsyncJob } from '../../../asyncJobTracker';\nimport { resolveTrackedRunId, TERMINAL_ASYNC_JOB_STATES } from '../../../asyncJobTracker';\nimport { normalizeParentModel } from '../../../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../../../services/models/modelResolution';\nimport type { PollSchedulerContract } from '../../../pollScheduler';\nimport {\n extractForkFlag,\n type InlineConfig,\n type ParsedStep,\n parseAgentToken,\n parseSingleTaskToken,\n SlashParseError,\n} from './chainExpression';\nimport { buildDoctorReport } from './doctor';\nimport { taskInputFromParsedStep, UnsupportedInlineConfigError } from './spawnRequestMapping';\nimport { launchParallelSubagents, launchSingleSubagent, watchTrackedRunUntilTerminal } from './subagentLaunch';\n\nexport interface SlashCommandDeps {\n spawnPlanner: SpawnPlannerContract;\n skills: SkillDiscoveryContract;\n tracker: AsyncJobTrackerContract;\n scheduler: PollSchedulerContract;\n discovery: AgentDiscoveryContract;\n /**\n * Used by `/subagents-stop`. Preferred over calling `requestSlashRunStop`\n * directly because it resolves an id PREFIX through `RunIdResolver` and\n * raises a real error for an unknown or ambiguous one, instead of writing a\n * stop request into a directory for a run that does not exist.\n */\n management: ManagementActionsContract;\n loadConfig: () => ExtensionConfig;\n}\n\nexport interface SlashCommandState {\n baseCwd: string | undefined;\n}\n\nconst SLASH_STATUS_KEY = 'subagent-slash';\nconst STARTED_STATUS = 'started';\n\n/**\n * The custom-message type a slash launch renders under. Cross-process\n * significant the same way `SUBAGENT_NOTIFY_MESSAGE_TYPE` is: the child-side\n * prompt runtime strips this type out of a child's inherited history\n * (`PARENT_ONLY_CUSTOM_MESSAGE_TYPES`), so both sides must agree on the literal.\n */\nexport const SLASH_RESULT_CUSTOM_TYPE = 'subagent-slash-result';\n\n/**\n * One run's line in a slash-result message. `status` is the tracker's own\n * status string (plus `started`), not a closed set this module can narrow.\n */\nexport interface SlashRunDetail {\n agent: string;\n runId: string;\n status: string;\n error?: string;\n warning?: string;\n}\n\nfunction sendSlashText(pi: ExtensionAPI, text: string, details?: SlashRunDetail[]): void {\n pi.sendMessage({\n customType: SLASH_RESULT_CUSTOM_TYPE,\n content: text,\n display: true,\n ...(details ? { details } : {}),\n });\n}\n\nfunction setSlashStatus(ctx: ExtensionContext, text: string | undefined): void {\n if (ctx.hasUI) ctx.ui.setStatus(SLASH_STATUS_KEY, text);\n}\n\nfunction notifyError(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'error');\n}\n\nfunction notifyInfo(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'info');\n}\n\nfunction statusTextFor(job: TrackedAsyncJob | undefined): string {\n if (!job) return 'starting…';\n if (job.attentionReason) return `${job.status ?? 'running'} - needs attention: ${job.attentionReason}`;\n if (job.activityState) return `${job.status ?? 'running'} - ${job.activityState}`;\n return job.status ?? 'running';\n}\n\n/**\n * Watches one launched run to a terminal state and finalizes its message.\n * Each launched run gets its own subscriber, so a PARALLEL launch's\n * siblings finalize independently rather than all waiting on the slowest.\n */\nfunction watchAndFinalize(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n runId: string,\n agent: string,\n): void {\n watchTrackedRunUntilTerminal(deps.scheduler, jobs, runId, (job) => {\n setSlashStatus(ctx, `${agent} (${runId}): ${statusTextFor(job)}`);\n if (job?.status === undefined || !TERMINAL_ASYNC_JOB_STATES.has(job.status)) return;\n setSlashStatus(ctx, undefined);\n const outcome = job.status === 'complete' || job.status === 'completed' ? 'completed' : job.status;\n sendSlashText(\n pi,\n job.error\n ? `## Subagent ${outcome}\\n\\n${agent} (${runId})\\n\\n${job.error}`\n : `## Subagent ${outcome}\\n\\n${agent} (${runId})`,\n [{ agent, runId, status: outcome, ...(job.error ? { error: job.error } : {}) }],\n );\n });\n}\n\nfunction reportSpawnResult(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n result: SpawnPlanResult,\n): void {\n const started = result.outcomes.filter((outcome) => outcome.runId);\n const failed = result.outcomes.filter((outcome) => !outcome.runId);\n if (started.length > 0) {\n const label = started\n .map(\n (outcome) => `${outcome.agent} (${outcome.runId})${outcome.warning ? `\\n Warning: ${outcome.warning}` : ''}`,\n )\n .join(', ');\n sendSlashText(\n pi,\n `## Subagent started\\n\\n${label}`,\n started.map((outcome) => ({\n agent: outcome.agent,\n runId: outcome.runId ?? '',\n status: STARTED_STATUS,\n ...(outcome.warning ? { warning: outcome.warning } : {}),\n })),\n );\n setSlashStatus(ctx, `${started.length} run${started.length === 1 ? '' : 's'} started…`);\n for (const outcome of started) {\n if (outcome.runId) watchAndFinalize(pi, ctx, deps, jobs, outcome.runId, outcome.agent);\n }\n }\n if (failed.length > 0) {\n const label = failed.map((outcome) => `${outcome.agent}: ${outcome.error ?? 'spawn failed'}`).join('\\n');\n notifyError(ctx, `Some subagents failed to start:\\n${label}`);\n }\n}\n\nfunction requireBaseCwd(state: SlashCommandState, ctx: ExtensionContext): string | undefined {\n if (state.baseCwd) return state.baseCwd;\n notifyError(ctx, 'Subagent session cwd is not initialized yet');\n return undefined;\n}\n\nfunction findAgentOrNotify(deps: SlashCommandDeps, baseCwd: string, name: string, ctx: ExtensionContext): boolean {\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (agents.find((agent) => agent.name === name)) return true;\n notifyError(ctx, `Unknown agent: ${name}`);\n return false;\n}\n\nexport interface SingleAgentRunRequest {\n agent: string;\n task: string;\n /** Inline `agent[model=x]` config from a slash token; surfaces without that syntax send none. */\n config?: InlineConfig;\n fork?: boolean;\n}\n\nexport type SingleAgentRunOutcome = { ok: true; result: SpawnPlanResult } | { ok: false; message: string };\n\n/**\n * One agent, one task: the shared body of `/run` and the agent catalog's\n * launch key (`SPC a l`, `r`/`R`).\n *\n * Returns `ok: false` with a user-facing message for the validation failures\n * both surfaces share rather than notifying itself, because the two report\n * in different idioms - a slash command notifies, and a fullscreen overlay\n * writes a notice into its own body, where a notification would be covered.\n * Started runs are still reported here through `reportSpawnResult`, which is\n * what tracks them and finalizes their message; that is identical for both.\n */\nexport async function launchSingleAgentRun(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n state: SlashCommandState,\n deps: SlashCommandDeps,\n request: SingleAgentRunRequest,\n): Promise<SingleAgentRunOutcome> {\n const baseCwd = state.baseCwd;\n if (!baseCwd) return { ok: false, message: 'Subagent session cwd is not initialized yet' };\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (!agents.find((agent) => agent.name === request.agent)) {\n return { ok: false, message: `Unknown agent: ${request.agent}` };\n }\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const taskInput = taskInputFromParsedStep(\n { name: request.agent, config: request.config ?? {}, task: request.task },\n baseCwd,\n request.fork ? 'fork' : undefined,\n );\n const result = await launchSingleSubagent(\n deps.spawnPlanner,\n jobs,\n {\n agent: taskInput.agent,\n task: taskInput.task ?? '',\n cwd: taskInput.cwd ?? baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(taskInput.model ? { model: taskInput.model } : {}),\n ...(taskInput.context ? { context: taskInput.context } : {}),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n return { ok: true, result };\n } catch (error) {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n return { ok: false, message: error.message };\n }\n throw error;\n }\n}\n\n/**\n * `launchSingleAgentRun` for a surface that cannot await it - the agent\n * catalog closes on launch, so nothing is left to receive the outcome. The\n * failure paths report themselves here, once the overlay is gone and a\n * notification is visible again.\n */\nexport function startSingleAgentRun(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n state: SlashCommandState,\n deps: SlashCommandDeps,\n request: SingleAgentRunRequest,\n): void {\n void launchSingleAgentRun(pi, ctx, state, deps, request).then(\n (outcome) => {\n if (!outcome.ok) notifyError(ctx, outcome.message);\n },\n (error: unknown) => {\n notifyError(ctx, `Subagent launch failed: ${error instanceof Error ? error.message : String(error)}`);\n },\n );\n}\n\nfunction reportKnownErrorOrRethrow(ctx: ExtensionContext, error: unknown): void {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n notifyError(ctx, error.message);\n return;\n }\n throw error;\n}\n\n/**\n * Shared arg parsing for /chain (no inline group) and /parallel:\n * \"agent1 task1 -> agent2 task2\" or \"agent1 agent2 -- shared task\".\n */\nfunction parseAgentArgsFallback(input: string): { steps: ParsedStep[]; task: string; perStep: boolean } | undefined {\n const trimmed = input.trim();\n if (trimmed.includes(' -> ')) {\n const steps = trimmed\n .split(' -> ')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .map((segment) => parseSingleTaskToken(segment));\n if (steps.length === 0) return undefined;\n return { steps, task: steps.find((step) => step.task)?.task ?? '', perStep: true };\n }\n const delimiterIndex = trimmed.indexOf(' -- ');\n if (delimiterIndex === -1) return undefined;\n const agentsPart = trimmed.slice(0, delimiterIndex).trim();\n const sharedTask = trimmed.slice(delimiterIndex + 4).trim();\n if (!agentsPart || !sharedTask) return undefined;\n const steps = agentsPart\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => parseSingleTaskToken(token));\n if (steps.length === 0) return undefined;\n return { steps, task: sharedTask, perStep: false };\n}\n\nexport function registerSlashCommands(pi: ExtensionAPI, state: SlashCommandState, deps: SlashCommandDeps): void {\n pi.registerCommand('run', {\n description: 'Run a subagent in the background: /run agent[model=x] [task] [--fork]',\n handler: async (args, ctx) => {\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const input = cleanedArgs.trim();\n if (!input) {\n notifyError(ctx, 'Usage: /run <agent> [task] [--fork]');\n return;\n }\n const firstSpace = input.indexOf(' ');\n const { name: agentName, config } = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace));\n const task = firstSpace === -1 ? '' : input.slice(firstSpace + 1).trim();\n const outcome = await launchSingleAgentRun(pi, ctx, state, deps, { agent: agentName, task, config, fork });\n if (!outcome.ok) notifyError(ctx, outcome.message);\n },\n });\n\n pi.registerCommand('parallel', {\n description: 'Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n\n const parsed = parseAgentArgsFallback(cleanedArgs);\n if (!parsed) {\n notifyError(ctx, 'Usage: /parallel agent1 \"task1\" -> agent2 \"task2\"');\n return;\n }\n for (const step of parsed.steps) {\n if (!findAgentOrNotify(deps, baseCwd, step.name, ctx)) return;\n }\n if (!parsed.steps.some((step) => step.task) && !parsed.task) {\n notifyError(ctx, 'At least one step must have a task');\n return;\n }\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const tasks = parsed.steps.map((step) =>\n taskInputFromParsedStep(\n { name: step.name, config: step.config, task: step.task ?? parsed.task },\n baseCwd,\n fork ? 'fork' : undefined,\n ),\n );\n const result = await launchParallelSubagents(\n deps.spawnPlanner,\n jobs,\n {\n tasks,\n cwd: baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('subagents-doctor', {\n description: 'Show subagent diagnostics',\n handler: async (_args, ctx) => {\n sendSlashText(\n pi,\n buildDoctorReport({ cwd: ctx.cwd, agentScope: 'both' }, { discovery: deps.discovery, skills: deps.skills }),\n );\n },\n });\n\n pi.registerCommand('subagents-stop', {\n description: 'Stop a running subagent: /subagents-stop [run-id]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const id = args.trim();\n if (!id) {\n sendSlashText(pi, stoppableRunsReport(jobs.list()));\n return;\n }\n try {\n deps.management.stop(resolveTrackedRunId(jobs, id));\n // Deliberately reports the REQUEST, not the outcome. Stop is\n // asynchronous in this package: the request is a file the child\n // claims on its next control-channel tick, so claiming \"stopped\"\n // here would assert something this process has not observed. The\n // run's own status is what confirms it, via /subagents-fleet or a\n // completion notification.\n notifyInfo(ctx, `Stop requested for ${id}. The run reports its own final state once it acknowledges.`);\n } catch (error) {\n // `ManagementActions.stop` throws only for an id that resolves to no\n // run or to more than one. Both are bad user input, not internal\n // faults, so they are notified rather than rethrown at the host - the\n // same treatment `reportKnownErrorOrRethrow` gives a parse error.\n notifyError(ctx, error instanceof Error ? error.message : `Could not stop '${id}'.`);\n }\n },\n });\n}\n\n/**\n * The no-argument `/subagents-stop` listing.\n *\n * The predecessor opened a TUI selector overlay here. This reports the same\n * information as text instead, for one reason worth stating rather than\n * hiding: a selector is a second, independent renderer of run state, and this\n * package already has one in `/subagents-fleet` that shows more (live status,\n * transcripts, and the full set of runtime controls including stop). Building\n * a second, weaker one would mean two things to keep in step. Passing an\n * explicit id stays the direct path, and the fleet overlay is the interactive\n * one.\n */\nfunction stoppableRunsReport(runs: readonly TrackedAsyncJob[]): string {\n const stoppable = runs.filter((run) => run.status === 'running' || run.status === 'pending');\n if (stoppable.length === 0) return 'No running subagents to stop.';\n const lines = stoppable.map((run) => `- ${run.runId}${run.status ? ` (${run.status})` : ''}`);\n return [\n 'Running subagents:',\n ...lines,\n '',\n 'Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{authenticatedModelInfos as e}from"../../../../services/models/modelResolution.mjs";import{normalizeParentModel as t}from"../../../runs/shared/modelFallback.mjs";import{captureSessionForkSource as n}from"../../extensions/spawnPlan.mjs";import{TERMINAL_ASYNC_JOB_STATES as r,init_asyncJobTracker as i,resolveTrackedRunId as a}from"../../../asyncJobTracker.mjs";import{SlashParseError as o,extractForkFlag as s,parseAgentToken as c,parseSingleTaskToken as l}from"./chainExpression.mjs";import{buildDoctorReport as u}from"./doctor.mjs";import{UnsupportedInlineConfigError as d,taskInputFromParsedStep as f}from"./spawnRequestMapping.mjs";import{launchParallelSubagents as p,launchSingleSubagent as m,watchTrackedRunUntilTerminal as h}from"./subagentLaunch.mjs";i();function
|
|
2
|
-
`)}`)}function
|
|
3
|
-
`)}export{D as
|
|
1
|
+
import{authenticatedModelInfos as e}from"../../../../services/models/modelResolution.mjs";import{normalizeParentModel as t}from"../../../runs/shared/modelFallback.mjs";import{captureSessionForkSource as n}from"../../extensions/spawnPlan.mjs";import{TERMINAL_ASYNC_JOB_STATES as r,init_asyncJobTracker as i,resolveTrackedRunId as a}from"../../../asyncJobTracker.mjs";import{SlashParseError as o,extractForkFlag as s,parseAgentToken as c,parseSingleTaskToken as l}from"./chainExpression.mjs";import{buildDoctorReport as u}from"./doctor.mjs";import{UnsupportedInlineConfigError as d,taskInputFromParsedStep as f}from"./spawnRequestMapping.mjs";import{launchParallelSubagents as p,launchSingleSubagent as m,watchTrackedRunUntilTerminal as h}from"./subagentLaunch.mjs";i();const g=`subagent-slash-result`;function _(e,t,n){e.sendMessage({customType:g,content:t,display:!0,...n?{details:n}:{}})}function v(e,t){e.hasUI&&e.ui.setStatus(`subagent-slash`,t)}function y(e,t){e.ui.notify(t,`error`)}function b(e,t){e.ui.notify(t,`info`)}function x(e){return e?e.attentionReason?`${e.status??`running`} - needs attention: ${e.attentionReason}`:e.activityState?`${e.status??`running`} - ${e.activityState}`:e.status??`running`:`starting…`}function S(e,t,n,i,a,o){h(n.scheduler,i,a,n=>{if(v(t,`${o} (${a}): ${x(n)}`),n?.status===void 0||!r.has(n.status))return;v(t,void 0);let i=n.status===`complete`||n.status===`completed`?`completed`:n.status;_(e,n.error?`## Subagent ${i}\n\n${o} (${a})\n\n${n.error}`:`## Subagent ${i}\n\n${o} (${a})`,[{agent:o,runId:a,status:i,...n.error?{error:n.error}:{}}])})}function C(e,t,n,r,i){let a=i.outcomes.filter(e=>e.runId),o=i.outcomes.filter(e=>!e.runId);if(a.length>0){_(e,`## Subagent started\n\n${a.map(e=>`${e.agent} (${e.runId})${e.warning?`\n Warning: ${e.warning}`:``}`).join(`, `)}`,a.map(e=>({agent:e.agent,runId:e.runId??``,status:`started`,...e.warning?{warning:e.warning}:{}}))),v(t,`${a.length} run${a.length===1?``:`s`} started…`);for(let i of a)i.runId&&S(e,t,n,r,i.runId,i.agent)}o.length>0&&y(t,`Some subagents failed to start:\n${o.map(e=>`${e.agent}: ${e.error??`spawn failed`}`).join(`
|
|
2
|
+
`)}`)}function w(e,t){if(e.baseCwd)return e.baseCwd;y(t,`Subagent session cwd is not initialized yet`)}function T(e,t,n,r){return e.discovery.discover(t,`both`).agents.find(e=>e.name===n)?!0:(y(r,`Unknown agent: ${n}`),!1)}async function E(r,i,a,s,c){let l=a.baseCwd;if(!l)return{ok:!1,message:`Subagent session cwd is not initialized yet`};if(!s.discovery.discover(l,`both`).agents.find(e=>e.name===c.agent))return{ok:!1,message:`Unknown agent: ${c.agent}`};let u=s.tracker.forSession(i.sessionManager.getSessionId());try{let a=n(i.sessionManager,`settled`),o=t(i.model),d=f({name:c.agent,config:c.config??{},task:c.task},l,c.fork?`fork`:void 0),p=await m(s.spawnPlanner,u,{agent:d.agent,task:d.task??``,cwd:d.cwd??l,agentScope:`both`,parentSessionId:i.sessionManager.getSessionId(),...d.model?{model:d.model}:{},...d.context?{context:d.context}:{},...a?{parentSessionFile:a.sessionFile,parentLeafId:a.leafId}:{},availableModels:e(i.modelRegistry),...o?{parentModel:o}:{}},s.loadConfig());return C(r,i,s,u,p),{ok:!0,result:p}}catch(e){if(e instanceof d||e instanceof o)return{ok:!1,message:e.message};throw e}}function D(e,t,n,r,i){E(e,t,n,r,i).then(e=>{e.ok||y(t,e.message)},e=>{y(t,`Subagent launch failed: ${e instanceof Error?e.message:String(e)}`)})}function O(e,t){if(t instanceof d||t instanceof o){y(e,t.message);return}throw t}function k(e){let t=e.trim();if(t.includes(` -> `)){let e=t.split(` -> `).map(e=>e.trim()).filter(Boolean).map(e=>l(e));return e.length===0?void 0:{steps:e,task:e.find(e=>e.task)?.task??``,perStep:!0}}let n=t.indexOf(` -- `);if(n===-1)return;let r=t.slice(0,n).trim(),i=t.slice(n+4).trim();if(!r||!i)return;let a=r.split(/\s+/).filter(Boolean).map(e=>l(e));if(a.length!==0)return{steps:a,task:i,perStep:!1}}function A(r,i,o){r.registerCommand(`run`,{description:`Run a subagent in the background: /run agent[model=x] [task] [--fork]`,handler:async(e,t)=>{let{args:n,fork:a}=s(e),l=n.trim();if(!l){y(t,`Usage: /run <agent> [task] [--fork]`);return}let u=l.indexOf(` `),{name:d,config:f}=c(u===-1?l:l.slice(0,u)),p=await E(r,t,i,o,{agent:d,task:u===-1?``:l.slice(u+1).trim(),config:f,fork:a});p.ok||y(t,p.message)}}),r.registerCommand(`parallel`,{description:`Run agents in parallel: /parallel scout "task1" -> reviewer "task2" [--fork]`,handler:async(a,c)=>{let l=o.tracker.forSession(c.sessionManager.getSessionId()),{args:u,fork:d}=s(a),m=w(i,c);if(!m)return;let h=k(u);if(!h){y(c,`Usage: /parallel agent1 "task1" -> agent2 "task2"`);return}for(let e of h.steps)if(!T(o,m,e.name,c))return;if(!h.steps.some(e=>e.task)&&!h.task){y(c,`At least one step must have a task`);return}try{let i=n(c.sessionManager,`settled`),a=t(c.model),s=h.steps.map(e=>f({name:e.name,config:e.config,task:e.task??h.task},m,d?`fork`:void 0));C(r,c,o,l,await p(o.spawnPlanner,l,{tasks:s,cwd:m,agentScope:`both`,parentSessionId:c.sessionManager.getSessionId(),...i?{parentSessionFile:i.sessionFile,parentLeafId:i.leafId}:{},availableModels:e(c.modelRegistry),...a?{parentModel:a}:{}},o.loadConfig()))}catch(e){O(c,e)}}}),r.registerCommand(`subagents-doctor`,{description:`Show subagent diagnostics`,handler:async(e,t)=>{_(r,u({cwd:t.cwd,agentScope:`both`},{discovery:o.discovery,skills:o.skills}))}}),r.registerCommand(`subagents-stop`,{description:`Stop a running subagent: /subagents-stop [run-id]`,handler:async(e,t)=>{let n=o.tracker.forSession(t.sessionManager.getSessionId()),i=e.trim();if(!i){_(r,j(n.list()));return}try{o.management.stop(a(n,i)),b(t,`Stop requested for ${i}. The run reports its own final state once it acknowledges.`)}catch(e){y(t,e instanceof Error?e.message:`Could not stop '${i}'.`)}}})}function j(e){let t=e.filter(e=>e.status===`running`||e.status===`pending`);return t.length===0?`No running subagents to stop.`:[`Running subagents:`,...t.map(e=>`- ${e.runId}${e.status?` (${e.status})`:``}`),``,"Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively."].join(`
|
|
3
|
+
`)}export{g as SLASH_RESULT_CUSTOM_TYPE,E as launchSingleAgentRun,A as registerSlashCommands,D as startSingleAgentRun};
|
|
4
4
|
//# sourceMappingURL=slashCommands.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slashCommands.mjs","names":[],"sources":["../../../../../../src/adapters/pi/commands/slash/slashCommands.ts"],"sourcesContent":["/**\n * The core `/run`, `/chain`, `/parallel` slash commands. Replaces the\n * always-blocking predecessor with the async-only shape this port settled\n * on: a command launches a spawn, sends an initial status message, and\n * hands off to `watchTrackedRunUntilTerminal` (render-key gated, backed by\n * `PollScheduler`) to update the status bar and finalize the message once\n * the run reaches a terminal state - never by awaiting completion. See\n * `subagentLaunch.ts`'s module doc for the full reasoning.\n *\n * WHAT IS NOT HERE, AND WHY:\n * - `/run-chain`, `/prompt-workflow` and `/chain-prompts`: the whole SAVED\n * work surface - saved agent pipelines (`ChainConfig`, never ported) and\n * saved `.md` prompt templates (ported, then deleted). REMOVED BY\n * DECISION, not deferred: overly complicated for the use they were\n * getting. Do not re-add them because a reader notices the predecessor had\n * them. Ad-hoc chaining (`/chain scout \"x\" -> planner`) is a different\n * feature, lives in `chainExpression.ts`, and stays\n * - `/subagent-cost`: REMOVED BY DECISION. It reads usage/cost data\n * (`totalTokens`/`totalCost`) that nothing in this package's\n * runs/extensions surface tracks - a genuinely absent data source, and\n * building it would mean threading usage out of every child process\n * - `/subagents-check-profile`: removed at the source. Calls\n * `checkSubagentProfile`/`listSubagentProfiles`, which are referenced but\n * defined nowhere in the entire predecessor package - a live\n * `ReferenceError` that only shipped because that package sets\n * `noCheck: true`. Typecheck is on here; porting it faithfully would not\n * compile, and it was asked to be removed independently of that\n * - The `SUBAGENT_FLEET_COMMAND` registration and its `Ctrl+Alt+F` shortcut:\n * fleet view is its own piece, registered by whoever builds it\n * - Inline parallel groups within `/chain` (`(a | b)` syntax): the field\n * mapping for a group's own config exists (`spawnRequestMapping.ts`),\n * but wiring a group INTO a chain request is left for the same pass that\n * revisits per-task field support, so `/chain` reports a clear\n * not-yet-supported message rather than silently flattening a group\n * - `/subagents` (admin) command registration: a separate file, not yet\n * ported\n *\n * `/subagents-doctor` IS here, in `doctor.ts` - read (not ported) the\n * predecessor's foreground-executor `doctor` action before deciding, and it\n * turned out to be a small, mostly-mechanical port. See that module's own\n * doc for what it deliberately leaves out (chain counts, spawn-budget\n * reporting).\n *\n * AVOID:\n * - Awaiting a SINGLE/PARALLEL spawn for a result that will not exist yet.\n * See `subagentLaunch.ts`\n * - A private polling loop for a message's live status. Use\n * `watchTrackedRunUntilTerminal`\n */\n\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { ExtensionConfig } from '../../extensions/config';\nimport type { ManagementActionsContract } from '../../extensions/managementActions';\nimport { captureSessionForkSource, type SpawnPlannerContract, type SpawnPlanResult } from '../../extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../../../agents/skills';\nimport type { AgentScope, AgentDiscoveryContract } from '../../../agents/types';\nimport type { AsyncJobTrackerContract, TrackedAsyncJobsContract, TrackedAsyncJob } from '../../../asyncJobTracker';\nimport { resolveTrackedRunId, TERMINAL_ASYNC_JOB_STATES } from '../../../asyncJobTracker';\nimport { normalizeParentModel } from '../../../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../../../services/models/modelResolution';\nimport type { PollSchedulerContract } from '../../../pollScheduler';\nimport {\n extractForkFlag,\n type ParsedStep,\n parseAgentToken,\n parseSingleTaskToken,\n SlashParseError,\n} from './chainExpression';\nimport { buildDoctorReport } from './doctor';\nimport { taskInputFromParsedStep, UnsupportedInlineConfigError } from './spawnRequestMapping';\nimport { launchParallelSubagents, launchSingleSubagent, watchTrackedRunUntilTerminal } from './subagentLaunch';\n\nexport interface SlashCommandDeps {\n spawnPlanner: SpawnPlannerContract;\n skills: SkillDiscoveryContract;\n tracker: AsyncJobTrackerContract;\n scheduler: PollSchedulerContract;\n discovery: AgentDiscoveryContract;\n /**\n * Used by `/subagents-stop`. Preferred over calling `requestSlashRunStop`\n * directly because it resolves an id PREFIX through `RunIdResolver` and\n * raises a real error for an unknown or ambiguous one, instead of writing a\n * stop request into a directory for a run that does not exist.\n */\n management: ManagementActionsContract;\n loadConfig: () => ExtensionConfig;\n}\n\nexport interface SlashCommandState {\n baseCwd: string | undefined;\n}\n\nconst SLASH_STATUS_KEY = 'subagent-slash';\nconst SLASH_RESULT_CUSTOM_TYPE = 'subagent-slash-result';\n\nfunction sendSlashText(pi: ExtensionAPI, text: string): void {\n pi.sendMessage({ customType: SLASH_RESULT_CUSTOM_TYPE, content: text, display: true });\n}\n\nfunction setSlashStatus(ctx: ExtensionContext, text: string | undefined): void {\n if (ctx.hasUI) ctx.ui.setStatus(SLASH_STATUS_KEY, text);\n}\n\nfunction notifyError(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'error');\n}\n\nfunction notifyInfo(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'info');\n}\n\nfunction statusTextFor(job: TrackedAsyncJob | undefined): string {\n if (!job) return 'starting…';\n if (job.attentionReason) return `${job.status ?? 'running'} - needs attention: ${job.attentionReason}`;\n if (job.activityState) return `${job.status ?? 'running'} - ${job.activityState}`;\n return job.status ?? 'running';\n}\n\n/**\n * Watches one launched run to a terminal state and finalizes its message.\n * Each launched run gets its own subscriber, so a PARALLEL launch's\n * siblings finalize independently rather than all waiting on the slowest.\n */\nfunction watchAndFinalize(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n runId: string,\n agent: string,\n): void {\n watchTrackedRunUntilTerminal(deps.scheduler, jobs, runId, (job) => {\n setSlashStatus(ctx, `${agent} (${runId}): ${statusTextFor(job)}`);\n if (job?.status === undefined || !TERMINAL_ASYNC_JOB_STATES.has(job.status)) return;\n setSlashStatus(ctx, undefined);\n const outcome = job.status === 'complete' || job.status === 'completed' ? 'completed' : job.status;\n sendSlashText(\n pi,\n job.error\n ? `## Subagent ${outcome}\\n\\n${agent} (${runId})\\n\\n${job.error}`\n : `## Subagent ${outcome}\\n\\n${agent} (${runId})`,\n );\n });\n}\n\nfunction reportSpawnResult(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n result: SpawnPlanResult,\n): void {\n const started = result.outcomes.filter((outcome) => outcome.runId);\n const failed = result.outcomes.filter((outcome) => !outcome.runId);\n if (started.length > 0) {\n const label = started\n .map(\n (outcome) => `${outcome.agent} (${outcome.runId})${outcome.warning ? `\\n Warning: ${outcome.warning}` : ''}`,\n )\n .join(', ');\n sendSlashText(pi, `## Subagent started\\n\\n${label}`);\n setSlashStatus(ctx, `${started.length} run${started.length === 1 ? '' : 's'} started…`);\n for (const outcome of started) {\n if (outcome.runId) watchAndFinalize(pi, ctx, deps, jobs, outcome.runId, outcome.agent);\n }\n }\n if (failed.length > 0) {\n const label = failed.map((outcome) => `${outcome.agent}: ${outcome.error ?? 'spawn failed'}`).join('\\n');\n notifyError(ctx, `Some subagents failed to start:\\n${label}`);\n }\n}\n\nfunction requireBaseCwd(state: SlashCommandState, ctx: ExtensionContext): string | undefined {\n if (state.baseCwd) return state.baseCwd;\n notifyError(ctx, 'Subagent session cwd is not initialized yet');\n return undefined;\n}\n\nfunction findAgentOrNotify(deps: SlashCommandDeps, baseCwd: string, name: string, ctx: ExtensionContext): boolean {\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (agents.find((agent) => agent.name === name)) return true;\n notifyError(ctx, `Unknown agent: ${name}`);\n return false;\n}\n\nfunction reportKnownErrorOrRethrow(ctx: ExtensionContext, error: unknown): void {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n notifyError(ctx, error.message);\n return;\n }\n throw error;\n}\n\n/**\n * Shared arg parsing for /chain (no inline group) and /parallel:\n * \"agent1 task1 -> agent2 task2\" or \"agent1 agent2 -- shared task\".\n */\nfunction parseAgentArgsFallback(input: string): { steps: ParsedStep[]; task: string; perStep: boolean } | undefined {\n const trimmed = input.trim();\n if (trimmed.includes(' -> ')) {\n const steps = trimmed\n .split(' -> ')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .map((segment) => parseSingleTaskToken(segment));\n if (steps.length === 0) return undefined;\n return { steps, task: steps.find((step) => step.task)?.task ?? '', perStep: true };\n }\n const delimiterIndex = trimmed.indexOf(' -- ');\n if (delimiterIndex === -1) return undefined;\n const agentsPart = trimmed.slice(0, delimiterIndex).trim();\n const sharedTask = trimmed.slice(delimiterIndex + 4).trim();\n if (!agentsPart || !sharedTask) return undefined;\n const steps = agentsPart\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => parseSingleTaskToken(token));\n if (steps.length === 0) return undefined;\n return { steps, task: sharedTask, perStep: false };\n}\n\nexport function registerSlashCommands(pi: ExtensionAPI, state: SlashCommandState, deps: SlashCommandDeps): void {\n pi.registerCommand('run', {\n description: 'Run a subagent in the background: /run agent[model=x] [task] [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const input = cleanedArgs.trim();\n if (!input) {\n notifyError(ctx, 'Usage: /run <agent> [task] [--fork]');\n return;\n }\n const firstSpace = input.indexOf(' ');\n const { name: agentName, config } = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace));\n const task = firstSpace === -1 ? '' : input.slice(firstSpace + 1).trim();\n\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n if (!findAgentOrNotify(deps, baseCwd, agentName, ctx)) return;\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const taskInput = taskInputFromParsedStep(\n { name: agentName, config, task },\n baseCwd,\n fork ? 'fork' : undefined,\n );\n const result = await launchSingleSubagent(\n deps.spawnPlanner,\n jobs,\n {\n agent: taskInput.agent,\n task: taskInput.task ?? '',\n cwd: taskInput.cwd ?? baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(taskInput.model ? { model: taskInput.model } : {}),\n ...(taskInput.context ? { context: taskInput.context } : {}),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('parallel', {\n description: 'Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n\n const parsed = parseAgentArgsFallback(cleanedArgs);\n if (!parsed) {\n notifyError(ctx, 'Usage: /parallel agent1 \"task1\" -> agent2 \"task2\"');\n return;\n }\n for (const step of parsed.steps) {\n if (!findAgentOrNotify(deps, baseCwd, step.name, ctx)) return;\n }\n if (!parsed.steps.some((step) => step.task) && !parsed.task) {\n notifyError(ctx, 'At least one step must have a task');\n return;\n }\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const tasks = parsed.steps.map((step) =>\n taskInputFromParsedStep(\n { name: step.name, config: step.config, task: step.task ?? parsed.task },\n baseCwd,\n fork ? 'fork' : undefined,\n ),\n );\n const result = await launchParallelSubagents(\n deps.spawnPlanner,\n jobs,\n {\n tasks,\n cwd: baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('subagents-doctor', {\n description: 'Show subagent diagnostics',\n handler: async (_args, ctx) => {\n sendSlashText(\n pi,\n buildDoctorReport({ cwd: ctx.cwd, agentScope: 'both' }, { discovery: deps.discovery, skills: deps.skills }),\n );\n },\n });\n\n pi.registerCommand('subagents-stop', {\n description: 'Stop a running subagent: /subagents-stop [run-id]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const id = args.trim();\n if (!id) {\n sendSlashText(pi, stoppableRunsReport(jobs.list()));\n return;\n }\n try {\n deps.management.stop(resolveTrackedRunId(jobs, id));\n // Deliberately reports the REQUEST, not the outcome. Stop is\n // asynchronous in this package: the request is a file the child\n // claims on its next control-channel tick, so claiming \"stopped\"\n // here would assert something this process has not observed. The\n // run's own status is what confirms it, via /subagents-fleet or a\n // completion notification.\n notifyInfo(ctx, `Stop requested for ${id}. The run reports its own final state once it acknowledges.`);\n } catch (error) {\n // `ManagementActions.stop` throws only for an id that resolves to no\n // run or to more than one. Both are bad user input, not internal\n // faults, so they are notified rather than rethrown at the host - the\n // same treatment `reportKnownErrorOrRethrow` gives a parse error.\n notifyError(ctx, error instanceof Error ? error.message : `Could not stop '${id}'.`);\n }\n },\n });\n}\n\n/**\n * The no-argument `/subagents-stop` listing.\n *\n * The predecessor opened a TUI selector overlay here. This reports the same\n * information as text instead, for one reason worth stating rather than\n * hiding: a selector is a second, independent renderer of run state, and this\n * package already has one in `/subagents-fleet` that shows more (live status,\n * transcripts, and the full set of runtime controls including stop). Building\n * a second, weaker one would mean two things to keep in step. Passing an\n * explicit id stays the direct path, and the fleet overlay is the interactive\n * one.\n */\nfunction stoppableRunsReport(runs: readonly TrackedAsyncJob[]): string {\n const stoppable = runs.filter((run) => run.status === 'running' || run.status === 'pending');\n if (stoppable.length === 0) return 'No running subagents to stop.';\n const lines = stoppable.map((run) => `- ${run.runId}${run.status ? ` (${run.status})` : ''}`);\n return [\n 'Running subagents:',\n ...lines,\n '',\n 'Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slashCommands.mjs","names":[],"sources":["../../../../../../src/adapters/pi/commands/slash/slashCommands.ts"],"sourcesContent":["/**\n * The core `/run`, `/chain`, `/parallel` slash commands. Replaces the\n * always-blocking predecessor with the async-only shape this port settled\n * on: a command launches a spawn, sends an initial status message, and\n * hands off to `watchTrackedRunUntilTerminal` (render-key gated, backed by\n * `PollScheduler`) to update the status bar and finalize the message once\n * the run reaches a terminal state - never by awaiting completion. See\n * `subagentLaunch.ts`'s module doc for the full reasoning.\n *\n * WHAT IS NOT HERE, AND WHY:\n * - `/run-chain`, `/prompt-workflow` and `/chain-prompts`: the whole SAVED\n * work surface - saved agent pipelines (`ChainConfig`, never ported) and\n * saved `.md` prompt templates (ported, then deleted). REMOVED BY\n * DECISION, not deferred: overly complicated for the use they were\n * getting. Do not re-add them because a reader notices the predecessor had\n * them. Ad-hoc chaining (`/chain scout \"x\" -> planner`) is a different\n * feature, lives in `chainExpression.ts`, and stays\n * - `/subagent-cost`: REMOVED BY DECISION. It reads usage/cost data\n * (`totalTokens`/`totalCost`) that nothing in this package's\n * runs/extensions surface tracks - a genuinely absent data source, and\n * building it would mean threading usage out of every child process\n * - `/subagents-check-profile`: removed at the source. Calls\n * `checkSubagentProfile`/`listSubagentProfiles`, which are referenced but\n * defined nowhere in the entire predecessor package - a live\n * `ReferenceError` that only shipped because that package sets\n * `noCheck: true`. Typecheck is on here; porting it faithfully would not\n * compile, and it was asked to be removed independently of that\n * - The `SUBAGENT_FLEET_COMMAND` registration and its `Ctrl+Alt+F` shortcut:\n * fleet view is its own piece, registered by whoever builds it\n * - Inline parallel groups within `/chain` (`(a | b)` syntax): the field\n * mapping for a group's own config exists (`spawnRequestMapping.ts`),\n * but wiring a group INTO a chain request is left for the same pass that\n * revisits per-task field support, so `/chain` reports a clear\n * not-yet-supported message rather than silently flattening a group\n * - `/subagents` (admin) command registration: a separate file, not yet\n * ported\n *\n * `/subagents-doctor` IS here, in `doctor.ts` - read (not ported) the\n * predecessor's foreground-executor `doctor` action before deciding, and it\n * turned out to be a small, mostly-mechanical port. See that module's own\n * doc for what it deliberately leaves out (chain counts, spawn-budget\n * reporting).\n *\n * AVOID:\n * - Awaiting a SINGLE/PARALLEL spawn for a result that will not exist yet.\n * See `subagentLaunch.ts`\n * - A private polling loop for a message's live status. Use\n * `watchTrackedRunUntilTerminal`\n */\n\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { ExtensionConfig } from '../../extensions/config';\nimport type { ManagementActionsContract } from '../../extensions/managementActions';\nimport { captureSessionForkSource, type SpawnPlannerContract, type SpawnPlanResult } from '../../extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../../../agents/skills';\nimport type { AgentScope, AgentDiscoveryContract } from '../../../agents/types';\nimport type { AsyncJobTrackerContract, TrackedAsyncJobsContract, TrackedAsyncJob } from '../../../asyncJobTracker';\nimport { resolveTrackedRunId, TERMINAL_ASYNC_JOB_STATES } from '../../../asyncJobTracker';\nimport { normalizeParentModel } from '../../../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../../../services/models/modelResolution';\nimport type { PollSchedulerContract } from '../../../pollScheduler';\nimport {\n extractForkFlag,\n type InlineConfig,\n type ParsedStep,\n parseAgentToken,\n parseSingleTaskToken,\n SlashParseError,\n} from './chainExpression';\nimport { buildDoctorReport } from './doctor';\nimport { taskInputFromParsedStep, UnsupportedInlineConfigError } from './spawnRequestMapping';\nimport { launchParallelSubagents, launchSingleSubagent, watchTrackedRunUntilTerminal } from './subagentLaunch';\n\nexport interface SlashCommandDeps {\n spawnPlanner: SpawnPlannerContract;\n skills: SkillDiscoveryContract;\n tracker: AsyncJobTrackerContract;\n scheduler: PollSchedulerContract;\n discovery: AgentDiscoveryContract;\n /**\n * Used by `/subagents-stop`. Preferred over calling `requestSlashRunStop`\n * directly because it resolves an id PREFIX through `RunIdResolver` and\n * raises a real error for an unknown or ambiguous one, instead of writing a\n * stop request into a directory for a run that does not exist.\n */\n management: ManagementActionsContract;\n loadConfig: () => ExtensionConfig;\n}\n\nexport interface SlashCommandState {\n baseCwd: string | undefined;\n}\n\nconst SLASH_STATUS_KEY = 'subagent-slash';\nconst STARTED_STATUS = 'started';\n\n/**\n * The custom-message type a slash launch renders under. Cross-process\n * significant the same way `SUBAGENT_NOTIFY_MESSAGE_TYPE` is: the child-side\n * prompt runtime strips this type out of a child's inherited history\n * (`PARENT_ONLY_CUSTOM_MESSAGE_TYPES`), so both sides must agree on the literal.\n */\nexport const SLASH_RESULT_CUSTOM_TYPE = 'subagent-slash-result';\n\n/**\n * One run's line in a slash-result message. `status` is the tracker's own\n * status string (plus `started`), not a closed set this module can narrow.\n */\nexport interface SlashRunDetail {\n agent: string;\n runId: string;\n status: string;\n error?: string;\n warning?: string;\n}\n\nfunction sendSlashText(pi: ExtensionAPI, text: string, details?: SlashRunDetail[]): void {\n pi.sendMessage({\n customType: SLASH_RESULT_CUSTOM_TYPE,\n content: text,\n display: true,\n ...(details ? { details } : {}),\n });\n}\n\nfunction setSlashStatus(ctx: ExtensionContext, text: string | undefined): void {\n if (ctx.hasUI) ctx.ui.setStatus(SLASH_STATUS_KEY, text);\n}\n\nfunction notifyError(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'error');\n}\n\nfunction notifyInfo(ctx: ExtensionContext, message: string): void {\n ctx.ui.notify(message, 'info');\n}\n\nfunction statusTextFor(job: TrackedAsyncJob | undefined): string {\n if (!job) return 'starting…';\n if (job.attentionReason) return `${job.status ?? 'running'} - needs attention: ${job.attentionReason}`;\n if (job.activityState) return `${job.status ?? 'running'} - ${job.activityState}`;\n return job.status ?? 'running';\n}\n\n/**\n * Watches one launched run to a terminal state and finalizes its message.\n * Each launched run gets its own subscriber, so a PARALLEL launch's\n * siblings finalize independently rather than all waiting on the slowest.\n */\nfunction watchAndFinalize(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n runId: string,\n agent: string,\n): void {\n watchTrackedRunUntilTerminal(deps.scheduler, jobs, runId, (job) => {\n setSlashStatus(ctx, `${agent} (${runId}): ${statusTextFor(job)}`);\n if (job?.status === undefined || !TERMINAL_ASYNC_JOB_STATES.has(job.status)) return;\n setSlashStatus(ctx, undefined);\n const outcome = job.status === 'complete' || job.status === 'completed' ? 'completed' : job.status;\n sendSlashText(\n pi,\n job.error\n ? `## Subagent ${outcome}\\n\\n${agent} (${runId})\\n\\n${job.error}`\n : `## Subagent ${outcome}\\n\\n${agent} (${runId})`,\n [{ agent, runId, status: outcome, ...(job.error ? { error: job.error } : {}) }],\n );\n });\n}\n\nfunction reportSpawnResult(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n deps: SlashCommandDeps,\n jobs: TrackedAsyncJobsContract,\n result: SpawnPlanResult,\n): void {\n const started = result.outcomes.filter((outcome) => outcome.runId);\n const failed = result.outcomes.filter((outcome) => !outcome.runId);\n if (started.length > 0) {\n const label = started\n .map(\n (outcome) => `${outcome.agent} (${outcome.runId})${outcome.warning ? `\\n Warning: ${outcome.warning}` : ''}`,\n )\n .join(', ');\n sendSlashText(\n pi,\n `## Subagent started\\n\\n${label}`,\n started.map((outcome) => ({\n agent: outcome.agent,\n runId: outcome.runId ?? '',\n status: STARTED_STATUS,\n ...(outcome.warning ? { warning: outcome.warning } : {}),\n })),\n );\n setSlashStatus(ctx, `${started.length} run${started.length === 1 ? '' : 's'} started…`);\n for (const outcome of started) {\n if (outcome.runId) watchAndFinalize(pi, ctx, deps, jobs, outcome.runId, outcome.agent);\n }\n }\n if (failed.length > 0) {\n const label = failed.map((outcome) => `${outcome.agent}: ${outcome.error ?? 'spawn failed'}`).join('\\n');\n notifyError(ctx, `Some subagents failed to start:\\n${label}`);\n }\n}\n\nfunction requireBaseCwd(state: SlashCommandState, ctx: ExtensionContext): string | undefined {\n if (state.baseCwd) return state.baseCwd;\n notifyError(ctx, 'Subagent session cwd is not initialized yet');\n return undefined;\n}\n\nfunction findAgentOrNotify(deps: SlashCommandDeps, baseCwd: string, name: string, ctx: ExtensionContext): boolean {\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (agents.find((agent) => agent.name === name)) return true;\n notifyError(ctx, `Unknown agent: ${name}`);\n return false;\n}\n\nexport interface SingleAgentRunRequest {\n agent: string;\n task: string;\n /** Inline `agent[model=x]` config from a slash token; surfaces without that syntax send none. */\n config?: InlineConfig;\n fork?: boolean;\n}\n\nexport type SingleAgentRunOutcome = { ok: true; result: SpawnPlanResult } | { ok: false; message: string };\n\n/**\n * One agent, one task: the shared body of `/run` and the agent catalog's\n * launch key (`SPC a l`, `r`/`R`).\n *\n * Returns `ok: false` with a user-facing message for the validation failures\n * both surfaces share rather than notifying itself, because the two report\n * in different idioms - a slash command notifies, and a fullscreen overlay\n * writes a notice into its own body, where a notification would be covered.\n * Started runs are still reported here through `reportSpawnResult`, which is\n * what tracks them and finalizes their message; that is identical for both.\n */\nexport async function launchSingleAgentRun(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n state: SlashCommandState,\n deps: SlashCommandDeps,\n request: SingleAgentRunRequest,\n): Promise<SingleAgentRunOutcome> {\n const baseCwd = state.baseCwd;\n if (!baseCwd) return { ok: false, message: 'Subagent session cwd is not initialized yet' };\n const agents = deps.discovery.discover(baseCwd, 'both' satisfies AgentScope).agents;\n if (!agents.find((agent) => agent.name === request.agent)) {\n return { ok: false, message: `Unknown agent: ${request.agent}` };\n }\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const taskInput = taskInputFromParsedStep(\n { name: request.agent, config: request.config ?? {}, task: request.task },\n baseCwd,\n request.fork ? 'fork' : undefined,\n );\n const result = await launchSingleSubagent(\n deps.spawnPlanner,\n jobs,\n {\n agent: taskInput.agent,\n task: taskInput.task ?? '',\n cwd: taskInput.cwd ?? baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(taskInput.model ? { model: taskInput.model } : {}),\n ...(taskInput.context ? { context: taskInput.context } : {}),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n return { ok: true, result };\n } catch (error) {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n return { ok: false, message: error.message };\n }\n throw error;\n }\n}\n\n/**\n * `launchSingleAgentRun` for a surface that cannot await it - the agent\n * catalog closes on launch, so nothing is left to receive the outcome. The\n * failure paths report themselves here, once the overlay is gone and a\n * notification is visible again.\n */\nexport function startSingleAgentRun(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n state: SlashCommandState,\n deps: SlashCommandDeps,\n request: SingleAgentRunRequest,\n): void {\n void launchSingleAgentRun(pi, ctx, state, deps, request).then(\n (outcome) => {\n if (!outcome.ok) notifyError(ctx, outcome.message);\n },\n (error: unknown) => {\n notifyError(ctx, `Subagent launch failed: ${error instanceof Error ? error.message : String(error)}`);\n },\n );\n}\n\nfunction reportKnownErrorOrRethrow(ctx: ExtensionContext, error: unknown): void {\n if (error instanceof UnsupportedInlineConfigError || error instanceof SlashParseError) {\n notifyError(ctx, error.message);\n return;\n }\n throw error;\n}\n\n/**\n * Shared arg parsing for /chain (no inline group) and /parallel:\n * \"agent1 task1 -> agent2 task2\" or \"agent1 agent2 -- shared task\".\n */\nfunction parseAgentArgsFallback(input: string): { steps: ParsedStep[]; task: string; perStep: boolean } | undefined {\n const trimmed = input.trim();\n if (trimmed.includes(' -> ')) {\n const steps = trimmed\n .split(' -> ')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .map((segment) => parseSingleTaskToken(segment));\n if (steps.length === 0) return undefined;\n return { steps, task: steps.find((step) => step.task)?.task ?? '', perStep: true };\n }\n const delimiterIndex = trimmed.indexOf(' -- ');\n if (delimiterIndex === -1) return undefined;\n const agentsPart = trimmed.slice(0, delimiterIndex).trim();\n const sharedTask = trimmed.slice(delimiterIndex + 4).trim();\n if (!agentsPart || !sharedTask) return undefined;\n const steps = agentsPart\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => parseSingleTaskToken(token));\n if (steps.length === 0) return undefined;\n return { steps, task: sharedTask, perStep: false };\n}\n\nexport function registerSlashCommands(pi: ExtensionAPI, state: SlashCommandState, deps: SlashCommandDeps): void {\n pi.registerCommand('run', {\n description: 'Run a subagent in the background: /run agent[model=x] [task] [--fork]',\n handler: async (args, ctx) => {\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const input = cleanedArgs.trim();\n if (!input) {\n notifyError(ctx, 'Usage: /run <agent> [task] [--fork]');\n return;\n }\n const firstSpace = input.indexOf(' ');\n const { name: agentName, config } = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace));\n const task = firstSpace === -1 ? '' : input.slice(firstSpace + 1).trim();\n const outcome = await launchSingleAgentRun(pi, ctx, state, deps, { agent: agentName, task, config, fork });\n if (!outcome.ok) notifyError(ctx, outcome.message);\n },\n });\n\n pi.registerCommand('parallel', {\n description: 'Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--fork]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const { args: cleanedArgs, fork } = extractForkFlag(args);\n const baseCwd = requireBaseCwd(state, ctx);\n if (!baseCwd) return;\n\n const parsed = parseAgentArgsFallback(cleanedArgs);\n if (!parsed) {\n notifyError(ctx, 'Usage: /parallel agent1 \"task1\" -> agent2 \"task2\"');\n return;\n }\n for (const step of parsed.steps) {\n if (!findAgentOrNotify(deps, baseCwd, step.name, ctx)) return;\n }\n if (!parsed.steps.some((step) => step.task) && !parsed.task) {\n notifyError(ctx, 'At least one step must have a task');\n return;\n }\n\n try {\n const parentForkSource = captureSessionForkSource(ctx.sessionManager, 'settled');\n const parentModel = normalizeParentModel(ctx.model);\n const tasks = parsed.steps.map((step) =>\n taskInputFromParsedStep(\n { name: step.name, config: step.config, task: step.task ?? parsed.task },\n baseCwd,\n fork ? 'fork' : undefined,\n ),\n );\n const result = await launchParallelSubagents(\n deps.spawnPlanner,\n jobs,\n {\n tasks,\n cwd: baseCwd,\n agentScope: 'both',\n parentSessionId: ctx.sessionManager.getSessionId(),\n ...(parentForkSource\n ? { parentSessionFile: parentForkSource.sessionFile, parentLeafId: parentForkSource.leafId }\n : {}),\n availableModels: authenticatedModelInfos(ctx.modelRegistry),\n ...(parentModel ? { parentModel } : {}),\n },\n deps.loadConfig(),\n );\n reportSpawnResult(pi, ctx, deps, jobs, result);\n } catch (error) {\n reportKnownErrorOrRethrow(ctx, error);\n }\n },\n });\n\n pi.registerCommand('subagents-doctor', {\n description: 'Show subagent diagnostics',\n handler: async (_args, ctx) => {\n sendSlashText(\n pi,\n buildDoctorReport({ cwd: ctx.cwd, agentScope: 'both' }, { discovery: deps.discovery, skills: deps.skills }),\n );\n },\n });\n\n pi.registerCommand('subagents-stop', {\n description: 'Stop a running subagent: /subagents-stop [run-id]',\n handler: async (args, ctx) => {\n const jobs = deps.tracker.forSession(ctx.sessionManager.getSessionId());\n const id = args.trim();\n if (!id) {\n sendSlashText(pi, stoppableRunsReport(jobs.list()));\n return;\n }\n try {\n deps.management.stop(resolveTrackedRunId(jobs, id));\n // Deliberately reports the REQUEST, not the outcome. Stop is\n // asynchronous in this package: the request is a file the child\n // claims on its next control-channel tick, so claiming \"stopped\"\n // here would assert something this process has not observed. The\n // run's own status is what confirms it, via /subagents-fleet or a\n // completion notification.\n notifyInfo(ctx, `Stop requested for ${id}. The run reports its own final state once it acknowledges.`);\n } catch (error) {\n // `ManagementActions.stop` throws only for an id that resolves to no\n // run or to more than one. Both are bad user input, not internal\n // faults, so they are notified rather than rethrown at the host - the\n // same treatment `reportKnownErrorOrRethrow` gives a parse error.\n notifyError(ctx, error instanceof Error ? error.message : `Could not stop '${id}'.`);\n }\n },\n });\n}\n\n/**\n * The no-argument `/subagents-stop` listing.\n *\n * The predecessor opened a TUI selector overlay here. This reports the same\n * information as text instead, for one reason worth stating rather than\n * hiding: a selector is a second, independent renderer of run state, and this\n * package already has one in `/subagents-fleet` that shows more (live status,\n * transcripts, and the full set of runtime controls including stop). Building\n * a second, weaker one would mean two things to keep in step. Passing an\n * explicit id stays the direct path, and the fleet overlay is the interactive\n * one.\n */\nfunction stoppableRunsReport(runs: readonly TrackedAsyncJob[]): string {\n const stoppable = runs.filter((run) => run.status === 'running' || run.status === 'pending');\n if (stoppable.length === 0) return 'No running subagents to stop.';\n const lines = stoppable.map((run) => `- ${run.runId}${run.status ? ` (${run.status})` : ''}`);\n return [\n 'Running subagents:',\n ...lines,\n '',\n 'Stop one with `/subagents-stop <run-id>`, or open `/subagents-fleet` to inspect and control them interactively.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../filesystem/paths.cjs"),t=require("../api/teamSnapshot.cjs"),n=require("../../services/models/modelResolution.cjs"),r=require("../runs/shared/modelFallback.cjs"),i=require("./extensions/spawnPlan.cjs"),a=require("../asyncJobTracker.cjs"),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"),d=require("../runs/registry/sessionLifecycle.cjs"),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;
|
|
1
|
+
const e=require("../filesystem/paths.cjs"),t=require("../api/teamSnapshot.cjs"),n=require("../../services/models/modelResolution.cjs"),r=require("../runs/shared/modelFallback.cjs"),i=require("./extensions/spawnPlan.cjs"),a=require("../asyncJobTracker.cjs"),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"),d=require("../runs/registry/sessionLifecycle.cjs"),f=require("./tui/completionNotice.cjs"),p=require("./tui/slashRunNotice.cjs"),m=require("./tui/register.cjs"),ne=require("./collaboration.cjs"),h=require("./teamRuntime.cjs");let g=require("@agimon-ai/doompi-extension-contracts/child-process"),_=require("@agimon-ai/doompi-extension-contracts/cordis-host"),v=require("@agimon-ai/doompi-extension-contracts/context-contributions"),re=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"),ie=require("@agimon-ai/doompi-telemetry");const x=`unknown`,S=`@agimon-ai/doompi-team`;function ae(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function oe(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`;return`${e.packageId} initialization ${e.state}: ${n}`}function se(e,t,n,r,i,a){return{spawnPlanner:n,tracker:r,scheduler:i,discovery:e,skills:t,management:a,loadConfig:()=>s.loadConfig().config}}function ce(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,le=e=>(T??=(0,ie.createDoomTelemetry)({serviceName:`doom-team`,packageName:`@agimon-ai/doompi-team`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),T),ue=(e,t)=>{T?.recordEvent(e,t)};C.effect(()=>async()=>{await T?.shutdown(),T=void 0},`@agimon-ai/doompi-team/telemetry`);let E=h.createTeamExtensionRuntime(ue),{subagentTool:de,teamChannel:D,pollScheduler:O,asyncJobTracker:k,subagentWaiter:A,asyncSubagentSpawner:fe,discovery:j,skills:M,spawnPlanner:N,completionNotifier:P,resultWatcher:F,staleRunReconciler:I,management:L,capabilityPolicies:R,mcpToolResolver:pe}=E,z=!0,B=0,V,H,U,W,G,K;C.inject([_.DOOM_CORDIS_SESSION_SERVICE],e=>{let n={cordis:e,service:e.get(_.DOOM_CORDIS_SESSION_SERVICE)};K=n,e.inject([re.DOOM_MCP_TOOL_RESOLVER_SERVICE],e=>pe.bind((0,re.requireDoomMcpToolResolver)(e))),e.inject([v.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE],e=>{let n=(0,v.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 me=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=oe(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))})}:ae(e,t)}});de.registerTool(J),C.inject([b.DOOM_UI_HUB_SERVICE],e=>m.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,he=c.createDelegationBridge({planner:N,management:L,waiter:A,scheduler:O,tracker:k,loadConfig:()=>s.loadConfig().config}),ge=l.createFablePlanBridge({spawner:fe,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 _e=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(()=>_e,`@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},ve=se(j,M,N,k,O,L);o.registerSlashCommands(J,$,ve),m.registerAgentListCommand(J,{discovery:j,skills:M,policies:R,launchAgent:(e,t)=>o.startSingleAgentRun(J,e,$,ve,{agent:t.agent,task:t.task,fork:t.context===`fork`})}),m.registerFleetCommand(J,{scheduler:O,tracker:k,management:L}),C.inject([b.DOOM_UI_HUB_SERVICE],e=>m.registerAgentStatus(w,(0,b.requireDoomUiHub)(e),{scheduler:O,tracker:k})),f.registerCompletionRenderer(w),p.registerSlashRunRenderer(w);let ye=async()=>{let e=[],t=X;X=void 0;try{await t?.dispose()}catch(t){e.push(t)}for(let t of[()=>R.clear(),()=>he.abandonAll(),()=>ge.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=le(a);l.recordEvent(`doom_team.session_started`,{"team.root_session":(0,g.resolveRootSessionId)(a.sessionManager.getSessionId())===a.sessionManager.getSessionId()});let u=a.sessionManager.getSessionId(),f=e.createSessionScope((0,g.resolveRootSessionId)(u));e.setCurrentSessionScope(f),$.baseCwd=a.cwd,Q!==void 0&&Q!==f.scopeKey&&(F.stop(),Q=void 0);let p=ye(),m=me(a),h=()=>z&&o===B&&U===a.sessionManager&&!c.signal.aborted;H=(async()=>{if(s&&await Promise.allSettled([s.then(e=>e.wait())]),!h())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(!h()||(await ee.writeScopeOwnerAsync(f),e.throwIfAborted(),!h()))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(),!h())return{value:void 0};if(o.suspended.length>0&&a.hasUI){let t=await te.formatSuspendedRunsAsync(o.suspended);if(e.throwIfAborted(),!h())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:he,fablePlan:ge,policies:R,observeDelegation:e=>ce(l,e)});return X=m,await m.await(),h()?(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 be,xe=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=>(be??=xe(e),be)),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","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 { registerSlashCommands, type SlashCommandDeps, type SlashCommandState } from './commands/slash/slashCommands';\nimport { loadConfig } from './extensions/config';\nimport { createDelegationBridge } from './extensions/delegationBridge';\nimport { createFablePlanBridge } from './extensions/fablePlanBridge';\nimport type { ManagementActionsContract } from './extensions/managementActions';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from './extensions/orchestratorPrompt';\nimport { captureSessionForkSource, type SpawnPlannerContract } from './extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../agents/skills';\nimport type { AgentDiscoveryContract } from '../agents/types';\nimport { formatTeamContextSnapshot, readActiveTeamSnapshot } from '../api/teamSnapshot';\nimport {\n type AsyncJobTrackerContract,\n type TrackedAsyncJobsContract,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../asyncJobTracker';\nimport { openScopeAsync, suspendScopeRuns } from '../runs/registry/sessionLifecycle';\nimport { formatSuspendedRunsAsync } from '../suspendedRuns';\nimport { normalizeParentModel } from '../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../services/models/modelResolution';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../filesystem/paths';\nimport type { PollSchedulerContract } from '../pollScheduler';\nimport { writeScopeOwnerAsync } from '../scopeOwner';\nimport { registerCompletionRenderer } from './tui/completionNotice';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from './tui/register';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime';\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: AgentDiscoveryContract,\n skills: SkillDiscoveryContract,\n planner: SpawnPlannerContract,\n tracker: AsyncJobTrackerContract,\n scheduler: PollSchedulerContract,\n management: ManagementActionsContract,\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: TrackedAsyncJobsContract | 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 `StaleRunReconcilerContract.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","startSingleAgentRun","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 startSingleAgentRun,\n type SlashCommandDeps,\n type SlashCommandState,\n} from './commands/slash/slashCommands';\nimport { loadConfig } from './extensions/config';\nimport { createDelegationBridge } from './extensions/delegationBridge';\nimport { createFablePlanBridge } from './extensions/fablePlanBridge';\nimport type { ManagementActionsContract } from './extensions/managementActions';\nimport { appendOrchestratorPrompt, shouldInjectOrchestratorPrompt } from './extensions/orchestratorPrompt';\nimport { captureSessionForkSource, type SpawnPlannerContract } from './extensions/spawnPlan';\nimport type { SkillDiscoveryContract } from '../agents/skills';\nimport type { AgentDiscoveryContract } from '../agents/types';\nimport { formatTeamContextSnapshot, readActiveTeamSnapshot } from '../api/teamSnapshot';\nimport {\n type AsyncJobTrackerContract,\n type TrackedAsyncJobsContract,\n TERMINAL_ASYNC_JOB_STATES,\n} from '../asyncJobTracker';\nimport { openScopeAsync, suspendScopeRuns } from '../runs/registry/sessionLifecycle';\nimport { formatSuspendedRunsAsync } from '../suspendedRuns';\nimport { normalizeParentModel } from '../runs/shared/modelFallback';\nimport { authenticatedModelInfos } from '../../services/models/modelResolution';\nimport { createSessionScope, setCurrentSessionScope, tryCurrentSessionScope } from '../filesystem/paths';\nimport type { PollSchedulerContract } from '../pollScheduler';\nimport { writeScopeOwnerAsync } from '../scopeOwner';\nimport { registerCompletionRenderer } from './tui/completionNotice';\nimport { registerSlashRunRenderer } from './tui/slashRunNotice';\nimport {\n registerAgentListCommand,\n registerAgentStatus,\n registerFleetCommand,\n registerSubagentLeaderContribution,\n} from './tui/register';\nimport { teamCollaborationPlugin, type TeamDelegationObservation } from './collaboration';\nimport { createTeamExtensionRuntime, type TeamExtensionRuntime } from './teamRuntime';\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: AgentDiscoveryContract,\n skills: SkillDiscoveryContract,\n planner: SpawnPlannerContract,\n tracker: AsyncJobTrackerContract,\n scheduler: PollSchedulerContract,\n management: ManagementActionsContract,\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: TrackedAsyncJobsContract | 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 `StaleRunReconcilerContract.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 const slashCommandDeps = buildSlashCommandDeps(\n discovery,\n skills,\n spawnPlanner,\n asyncJobTracker,\n pollScheduler,\n management,\n );\n registerSlashCommands(readinessPi, state, slashCommandDeps);\n registerAgentListCommand(readinessPi, {\n discovery,\n skills,\n policies: capabilityPolicies,\n // The catalog's r/R keys spawn through the same path as `/run`, so a run\n // started from the overlay is tracked and reported like any other.\n launchAgent: (ctx, request) =>\n startSingleAgentRun(readinessPi, ctx, state, slashCommandDeps, {\n agent: request.agent,\n task: request.task,\n fork: request.context === 'fork',\n }),\n });\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 registerSlashRunRenderer(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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"}
|