@agimon-ai/doompi-team 0.0.1-alpha.58 → 0.0.1-alpha.64
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/runs/piModuleAlias.d.cts +1 -2
- package/dist/runs/piModuleAlias.d.cts.map +1 -1
- package/dist/runs/piModuleAlias.d.mts +1 -2
- package/dist/runs/piModuleAlias.d.mts.map +1 -1
- package/dist/runs/sdkRunnerEntry.cjs +1 -1
- package/dist/runs/sdkRunnerEntry.cjs.map +1 -1
- package/dist/runs/sdkRunnerEntry.d.cts +1 -2
- package/dist/runs/sdkRunnerEntry.d.cts.map +1 -1
- package/dist/runs/sdkRunnerEntry.d.mts +1 -2
- package/dist/runs/sdkRunnerEntry.d.mts.map +1 -1
- package/dist/runs/sdkRunnerEntry.mjs +1 -1
- package/dist/runs/sdkRunnerEntry.mjs.map +1 -1
- package/dist/src/adapters/agents/loader.cjs +1 -1
- package/dist/src/adapters/agents/loader.cjs.map +1 -1
- package/dist/src/adapters/agents/loader.mjs +1 -1
- package/dist/src/adapters/agents/loader.mjs.map +1 -1
- package/dist/src/adapters/agents/memory.cjs +1 -1
- package/dist/src/adapters/agents/memory.cjs.map +1 -1
- package/dist/src/adapters/agents/memory.mjs +1 -1
- package/dist/src/adapters/agents/memory.mjs.map +1 -1
- package/dist/src/adapters/agents/settings.cjs +1 -1
- package/dist/src/adapters/agents/settings.cjs.map +1 -1
- package/dist/src/adapters/agents/settings.mjs +1 -1
- package/dist/src/adapters/agents/settings.mjs.map +1 -1
- package/dist/src/adapters/agents/types.d.cts +9 -10
- package/dist/src/adapters/agents/types.d.cts.map +1 -1
- package/dist/src/adapters/agents/types.d.mts +9 -10
- package/dist/src/adapters/agents/types.d.mts.map +1 -1
- package/dist/src/adapters/api/teamSnapshot.d.cts +4 -5
- package/dist/src/adapters/api/teamSnapshot.d.cts.map +1 -1
- package/dist/src/adapters/api/teamSnapshot.d.mts +4 -5
- package/dist/src/adapters/api/teamSnapshot.d.mts.map +1 -1
- package/dist/src/adapters/asyncJobTracker.cjs +1 -1
- package/dist/src/adapters/asyncJobTracker.cjs.map +1 -1
- package/dist/src/adapters/asyncJobTracker.mjs +1 -1
- package/dist/src/adapters/asyncJobTracker.mjs.map +1 -1
- package/dist/src/adapters/intercom/nativeTeamChannel.cjs +2 -2
- package/dist/src/adapters/intercom/nativeTeamChannel.cjs.map +1 -1
- package/dist/src/adapters/intercom/nativeTeamChannel.d.cts +4 -5
- package/dist/src/adapters/intercom/nativeTeamChannel.d.cts.map +1 -1
- package/dist/src/adapters/intercom/nativeTeamChannel.d.mts +4 -5
- package/dist/src/adapters/intercom/nativeTeamChannel.d.mts.map +1 -1
- package/dist/src/adapters/intercom/nativeTeamChannel.mjs +2 -2
- package/dist/src/adapters/intercom/nativeTeamChannel.mjs.map +1 -1
- package/dist/src/adapters/intercom/supervisorControlChannel.cjs +1 -1
- package/dist/src/adapters/intercom/supervisorControlChannel.cjs.map +1 -1
- package/dist/src/adapters/intercom/supervisorControlChannel.mjs +1 -1
- package/dist/src/adapters/intercom/supervisorControlChannel.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/extensions/fablePlanBridge.cjs +1 -1
- package/dist/src/adapters/pi/extensions/fablePlanBridge.cjs.map +1 -1
- package/dist/src/adapters/pi/extensions/fablePlanBridge.mjs +1 -1
- package/dist/src/adapters/pi/extensions/fablePlanBridge.mjs.map +1 -1
- package/dist/src/adapters/pi/extensions/subagentPromptRuntime.d.cts +2 -3
- package/dist/src/adapters/pi/extensions/subagentPromptRuntime.d.cts.map +1 -1
- package/dist/src/adapters/pi/extensions/subagentPromptRuntime.d.mts +2 -3
- package/dist/src/adapters/pi/extensions/subagentPromptRuntime.d.mts.map +1 -1
- package/dist/src/adapters/pi/standard.d.cts +2 -2
- package/dist/src/adapters/pi/standard.d.cts.map +1 -1
- package/dist/src/adapters/pi/standard.d.mts +2 -2
- package/dist/src/adapters/pi/standard.d.mts.map +1 -1
- package/dist/src/adapters/process/childTranscript.cjs +1 -1
- package/dist/src/adapters/process/childTranscript.cjs.map +1 -1
- package/dist/src/adapters/process/childTranscript.mjs +1 -1
- package/dist/src/adapters/process/childTranscript.mjs.map +1 -1
- package/dist/src/adapters/processTerminal.cjs +1 -1
- package/dist/src/adapters/processTerminal.cjs.map +1 -1
- package/dist/src/adapters/processTerminal.mjs +1 -1
- package/dist/src/adapters/processTerminal.mjs.map +1 -1
- package/dist/src/adapters/resultWatcher.cjs +1 -1
- package/dist/src/adapters/resultWatcher.cjs.map +1 -1
- package/dist/src/adapters/resultWatcher.mjs +1 -1
- package/dist/src/adapters/resultWatcher.mjs.map +1 -1
- package/dist/src/adapters/runRegistry.cjs +1 -1
- package/dist/src/adapters/runRegistry.cjs.map +1 -1
- package/dist/src/adapters/runRegistry.mjs +1 -1
- package/dist/src/adapters/runRegistry.mjs.map +1 -1
- package/dist/src/adapters/runs/shared/modelFallback.cjs +1 -1
- package/dist/src/adapters/runs/shared/modelFallback.cjs.map +1 -1
- package/dist/src/adapters/runs/shared/modelFallback.mjs +1 -1
- package/dist/src/adapters/runs/shared/modelFallback.mjs.map +1 -1
- package/dist/src/adapters/scopeOwner.cjs +1 -1
- package/dist/src/adapters/scopeOwner.cjs.map +1 -1
- package/dist/src/adapters/scopeOwner.mjs +1 -1
- package/dist/src/adapters/scopeOwner.mjs.map +1 -1
- package/dist/src/adapters/sessionCatalogSnapshot.cjs +1 -1
- package/dist/src/adapters/sessionCatalogSnapshot.cjs.map +1 -1
- package/dist/src/adapters/sessionCatalogSnapshot.mjs +1 -1
- package/dist/src/adapters/sessionCatalogSnapshot.mjs.map +1 -1
- package/dist/src/adapters/subagentLaunchContract.d.cts +4 -5
- package/dist/src/adapters/subagentLaunchContract.d.cts.map +1 -1
- package/dist/src/adapters/subagentLaunchContract.d.mts +4 -5
- package/dist/src/adapters/subagentLaunchContract.d.mts.map +1 -1
- package/dist/src/adapters/teamCatalogApi.d.cts +6 -7
- package/dist/src/adapters/teamCatalogApi.d.cts.map +1 -1
- package/dist/src/adapters/teamCatalogApi.d.mts +6 -7
- package/dist/src/adapters/teamCatalogApi.d.mts.map +1 -1
- package/dist/src/adapters/webHubChannels.d.cts +1 -2
- package/dist/src/adapters/webHubChannels.d.cts.map +1 -1
- package/dist/src/adapters/webHubChannels.d.mts +1 -2
- package/dist/src/adapters/webHubChannels.d.mts.map +1 -1
- package/dist/src/adapters/webSubagentCatalogChannel.d.cts +2 -3
- package/dist/src/adapters/webSubagentCatalogChannel.d.cts.map +1 -1
- package/dist/src/adapters/webSubagentCatalogChannel.d.mts +2 -3
- package/dist/src/adapters/webSubagentCatalogChannel.d.mts.map +1 -1
- package/dist/src/adapters/webSubagentWatcher.d.cts +2 -3
- package/dist/src/adapters/webSubagentWatcher.d.cts.map +1 -1
- package/dist/src/adapters/webSubagentWatcher.d.mts +2 -3
- package/dist/src/adapters/webSubagentWatcher.d.mts.map +1 -1
- package/dist/src/adapters/webSubagentsChannel.d.cts +1 -2
- package/dist/src/adapters/webSubagentsChannel.d.cts.map +1 -1
- package/dist/src/adapters/webSubagentsChannel.d.mts +1 -2
- package/dist/src/adapters/webSubagentsChannel.d.mts.map +1 -1
- package/dist/src/schemas/team/capabilityCeiling.d.cts +10 -10
- package/dist/src/schemas/team/capabilityCeiling.d.cts.map +1 -1
- package/dist/src/schemas/team/capabilityCeiling.d.mts +10 -10
- package/dist/src/schemas/team/capabilityCeiling.d.mts.map +1 -1
- package/dist/src/schemas/team/delegation.d.cts +40 -41
- package/dist/src/schemas/team/delegation.d.cts.map +1 -1
- package/dist/src/schemas/team/delegation.d.mts +40 -41
- package/dist/src/schemas/team/delegation.d.mts.map +1 -1
- package/dist/src/schemas/team/packageConfig.cjs +1 -1
- package/dist/src/schemas/team/packageConfig.cjs.map +1 -1
- package/dist/src/schemas/team/packageConfig.mjs +1 -1
- package/dist/src/schemas/team/packageConfig.mjs.map +1 -1
- package/dist/src/services/webSubagentCatalog.d.cts +1 -2
- package/dist/src/services/webSubagentCatalog.d.cts.map +1 -1
- package/dist/src/services/webSubagentCatalog.d.mts +1 -2
- package/dist/src/services/webSubagentCatalog.d.mts.map +1 -1
- package/dist/src/services/webSubagentRuns.cjs +1 -1
- package/dist/src/services/webSubagentRuns.cjs.map +1 -1
- package/dist/src/services/webSubagentRuns.mjs +1 -1
- package/dist/src/services/webSubagentRuns.mjs.map +1 -1
- package/dist/src/types/environment.d.cts +47 -47
- package/dist/src/types/environment.d.cts.map +1 -1
- package/dist/src/types/environment.d.mts +47 -47
- package/dist/src/types/environment.d.mts.map +1 -1
- package/dist/src/types/index.d.cts +2 -3
- package/dist/src/types/index.d.cts.map +1 -1
- package/dist/src/types/index.d.mts +2 -3
- package/dist/src/types/index.d.mts.map +1 -1
- package/dist/src/types/webSubagents.d.cts +3 -4
- package/dist/src/types/webSubagents.d.cts.map +1 -1
- package/dist/src/types/webSubagents.d.mts +3 -4
- package/dist/src/types/webSubagents.d.mts.map +1 -1
- package/package.json +21 -21
- package/src/web/{AgentCatalogDrawer.tsx → components/AgentCatalogDrawer.tsx} +3 -3
- package/src/web/{AgentThreadPanel.tsx → components/AgentThreadPanel.tsx} +34 -15
- package/src/web/{AgentsActivitySection.tsx → components/AgentsActivitySection.tsx} +4 -4
- package/src/web/{IntercomToolMessage.tsx → components/IntercomToolMessage.tsx} +1 -1
- package/src/web/{LaunchAgentDialog.tsx → components/LaunchAgentDialog.tsx} +4 -4
- package/src/web/{RunControl.tsx → components/RunControl.tsx} +3 -3
- package/src/web/{SubagentToolMessage.tsx → components/SubagentToolMessage.tsx} +1 -1
- package/src/web/{SubagentsPanel.tsx → components/SubagentsPanel.tsx} +9 -9
- package/src/web/index.ts +6 -6
- package/src/web/{launchCommand.ts → lib/launchCommand.ts} +1 -1
- package/src/web/{catalogStore.ts → stores/catalogStore.ts} +1 -1
- package/src/web/{subagentsStore.ts → stores/subagentsStore.ts} +1 -1
- /package/src/web/{runActionsSlot.ts → api/runActionsSlot.ts} +0 -0
- /package/src/web/{toolRenderers.ts → components/toolRenderers.ts} +0 -0
- /package/src/web/{format.ts → lib/format.ts} +0 -0
- /package/src/web/{toolText.ts → lib/toolText.ts} +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* The file URL resolution should pretend the Pi import came from, or
|
|
4
4
|
* undefined when the parent provided no usable package root.
|
|
5
5
|
*/
|
|
6
|
-
declare function resolvePiAliasAnchor(env?: NodeJS.ProcessEnv): string | undefined;
|
|
6
|
+
export declare function resolvePiAliasAnchor(env?: NodeJS.ProcessEnv): string | undefined;
|
|
7
7
|
//#endregion
|
|
8
|
-
export { resolvePiAliasAnchor };
|
|
9
8
|
//# sourceMappingURL=piModuleAlias.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"piModuleAlias.d.cts","names":[],"sources":["../../src/adapters/process/piModuleAlias.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"piModuleAlias.d.cts","names":[],"sources":["../../src/adapters/process/piModuleAlias.ts"],"mappings":";;;;;wBA2BgB,qBAAqB,MAAK,OAAO"}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* The file URL resolution should pretend the Pi import came from, or
|
|
4
4
|
* undefined when the parent provided no usable package root.
|
|
5
5
|
*/
|
|
6
|
-
declare function resolvePiAliasAnchor(env?: NodeJS.ProcessEnv): string | undefined;
|
|
6
|
+
export declare function resolvePiAliasAnchor(env?: NodeJS.ProcessEnv): string | undefined;
|
|
7
7
|
//#endregion
|
|
8
|
-
export { resolvePiAliasAnchor };
|
|
9
8
|
//# sourceMappingURL=piModuleAlias.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"piModuleAlias.d.mts","names":[],"sources":["../../src/adapters/process/piModuleAlias.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"piModuleAlias.d.mts","names":[],"sources":["../../src/adapters/process/piModuleAlias.ts"],"mappings":";;;;;wBA2BgB,qBAAqB,MAAK,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../src/types/environment.cjs"),n=require("../src/adapters/atomicJson.cjs"),r=require("../src/adapters/filesystem/paths.cjs"),i=require("../src/adapters/process/childTranscript.cjs"),a=require("../src/adapters/runs/background/parentWatchdog.cjs"),o=require("../src/services/runs/extensionErrorTelemetry.cjs");let s=require("node:fs");s=e.__toESM(s,1);let c=require("@agimon-ai/doompi-telemetry"),l=require("@earendil-works/pi-coding-agent"),u=require("@agimon-ai/doompi-extension-contracts/child-process");const d=`doom_team.child_finished`,f=`doom_team.child_failed`;function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e){return e instanceof Error?e.message:String(e)}function h(e){let t=r.currentRunConfigPath(e),n=JSON.parse(s.readFileSync(t,`utf8`));if(!p(n)||n.runId!==e||!p(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function g(e){let{cwd:t,sdk:n}=e;return n.sessionFile?l.SessionManager.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?l.SessionManager.create(t,n.sessionDir):l.SessionManager.inMemory(t)}function _(e,t){let r=e?.handshakePath
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../src/types/environment.cjs"),n=require("../src/adapters/atomicJson.cjs"),r=require("../src/adapters/filesystem/paths.cjs"),i=require("../src/adapters/process/childTranscript.cjs"),a=require("../src/adapters/runs/background/parentWatchdog.cjs"),o=require("../src/services/runs/extensionErrorTelemetry.cjs");let s=require("node:fs");s=e.__toESM(s,1);let c=require("@agimon-ai/doompi-telemetry"),l=require("@earendil-works/pi-coding-agent"),u=require("@agimon-ai/doompi-extension-contracts/child-process");const d=`doom_team.child_finished`,f=`doom_team.child_failed`;function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e){return e instanceof Error?e.message:String(e)}function h(e){let t=r.currentRunConfigPath(e),n=JSON.parse(s.readFileSync(t,`utf8`));if(!p(n)||n.runId!==e||!p(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function g(e){let{cwd:t,sdk:n}=e;return n.sessionFile?l.SessionManager.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?l.SessionManager.create(t,n.sessionDir):l.SessionManager.inMemory(t)}function _(e,t){let r=e?.handshakePath;r&&!s.existsSync(r)&&n.writeAtomicJson(r,{state:`error`,error:m(t)})}let v,y;async function b(e,t,n){let r=y;y=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function x(){let e=Date.now();y=(0,c.createDoomTelemetry)({serviceName:`doom-team-sdk-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let n=process.env[t.SUBAGENT_RUN_ID_ENV]?.trim();if(!n)throw Error(`${t.SUBAGENT_RUN_ID_ENV} is required.`);if(!r.adoptSessionScopeFromEnv())throw Error(`${u.SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);let s;try{s=h(n);let t=s;await y?.recordEvent(`doom_team.child_started`,{runtime:`sdk`,"agent.name":t.agent,...t.sdk.model?{"model.id":t.sdk.model}:{},outcome:`started`});let{sdk:r}=t,c=(0,l.getAgentDir)(),u=await(0,l.createAgentSessionServices)({cwd:s.cwd,agentDir:c,resourceLoaderOptions:{additionalExtensionPaths:r.extensions,additionalSkillPaths:r.skillPaths,noExtensions:r.noAmbientExtensions,noSkills:r.noSkills,noContextFiles:r.noContextFiles,...r.systemPromptMode===`replace`?{systemPrompt:r.systemPrompt}:{},...r.systemPrompt&&r.systemPromptMode!==`replace`?{appendSystemPrompt:[r.systemPrompt]}:{}}}),f=u.diagnostics.find(e=>e.type===`error`);if(f)throw Error(f.message);let p=r.model?(0,l.resolveCliModel)({cliModel:r.model,modelRuntime:u.modelRuntime}):void 0;if(p&&!p.model)throw Error(p.error??`Model '${r.model}' was not found.`);let{session:m}=await(0,l.createAgentSessionFromServices)({services:u,sessionManager:g(s),...p?.model?{model:p.model}:{},...p?.thinkingLevel?{thinkingLevel:p.thinkingLevel}:{},...r.tools?{tools:r.tools}:{},...r.noTools?{noTools:r.noTools}:{},...r.excludeTools?{excludeTools:r.excludeTools}:{}});v=a.startParentWatchdog({onParentLost:()=>{m.dispose(),b(d,{runtime:`sdk`,"agent.name":t.agent,duration_ms:Date.now()-e,outcome:`parent_lost`}).finally(()=>process.exit(0))}});let _=s.transcriptPath?i.createChildTranscriptWriter({transcriptPath:s.transcriptPath,source:`async`,runId:s.runId,agent:s.agent,childIndex:s.childIndex,cwd:s.cwd}):void 0;_?.writeInitialUserMessage(s.task);let x=m.subscribe(n=>{_?.writeChildEvent(n),n.type===`agent_end`&&setImmediate(()=>{m.agent.hasQueuedMessages()||(m.dispose(),b(d,{runtime:`sdk`,"agent.name":t.agent,duration_ms:Date.now()-e,outcome:`completed`}).finally(()=>process.exit(0)))})});try{await m.bindExtensions({mode:`print`,onError:e=>{o.recordNonBlockingExtensionError(y,e)}}),await m.prompt(s.task)}finally{v?.(),x(),m.dispose(),await b(d,{runtime:`sdk`,"agent.name":t.agent,duration_ms:Date.now()-e,outcome:`completed`})}}catch(e){throw _(s,e),await b(f,{outcome:`failed`},e),e}}x().then(()=>{process.exit(0)},async e=>{await b(f,{outcome:`failed`},e);let t=e instanceof Error?e:Error(`Doom Team SDK child failed`,{cause:e});setImmediate(()=>{throw t})}),exports.runSdkChild=x;
|
|
2
2
|
//# sourceMappingURL=sdkRunnerEntry.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdkRunnerEntry.cjs","names":["currentRunConfigPath","fs","SessionManager","createDoomTelemetry","SUBAGENT_RUN_ID_ENV","adoptSessionScopeFromEnv","SUBAGENT_ROOT_SESSION_ENV","getAgentDir","createAgentSessionServices","resolveCliModel","createAgentSessionFromServices","startParentWatchdog","createChildTranscriptWriter"],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../runs/background/asyncExecution';\nimport { startParentWatchdog } from '../runs/background/parentWatchdog';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry';\nimport { writeAtomicJson } from '../atomicJson';\nimport { createChildTranscriptWriter } from './childTranscript';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../filesystem/paths';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../types/environment';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdkRunnerEntry.cjs","names":["currentRunConfigPath","fs","SessionManager","createDoomTelemetry","SUBAGENT_RUN_ID_ENV","adoptSessionScopeFromEnv","SUBAGENT_ROOT_SESSION_ENV","getAgentDir","createAgentSessionServices","resolveCliModel","createAgentSessionFromServices","startParentWatchdog","createChildTranscriptWriter"],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../runs/background/asyncExecution';\nimport { startParentWatchdog } from '../runs/background/parentWatchdog';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry';\nimport { writeAtomicJson } from '../atomicJson';\nimport { createChildTranscriptWriter } from './childTranscript';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../filesystem/paths';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../types/environment';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdkRunnerEntry.d.cts","names":[],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"sdkRunnerEntry.d.cts","names":[],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";wBAkEsB,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdkRunnerEntry.d.mts","names":[],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"sdkRunnerEntry.d.mts","names":[],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";wBAkEsB,eAAe"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{SUBAGENT_ROOT_SESSION_ENV as e,SUBAGENT_RUN_ID_ENV as t,init_environment as n}from"../src/types/environment.mjs";import{init_atomicJson as r,writeAtomicJson as i}from"../src/adapters/atomicJson.mjs";import{adoptSessionScopeFromEnv as a,currentRunConfigPath as o,init_paths as s}from"../src/adapters/filesystem/paths.mjs";import{createChildTranscriptWriter as c,init_childTranscript as l}from"../src/adapters/process/childTranscript.mjs";import{startParentWatchdog as u}from"../src/adapters/runs/background/parentWatchdog.mjs";import{recordNonBlockingExtensionError as d}from"../src/services/runs/extensionErrorTelemetry.mjs";import*as f from"node:fs";import{createDoomTelemetry as p}from"@agimon-ai/doompi-telemetry";import{SessionManager as m,createAgentSessionFromServices as h,createAgentSessionServices as g,getAgentDir as _,resolveCliModel as v}from"@earendil-works/pi-coding-agent";r(),l(),s(),n();const y=`doom_team.child_finished`,b=`doom_team.child_failed`;function x(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function S(e){return e instanceof Error?e.message:String(e)}function C(e){let t=o(e),n=JSON.parse(f.readFileSync(t,`utf8`));if(!x(n)||n.runId!==e||!x(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function w(e){let{cwd:t,sdk:n}=e;return n.sessionFile?m.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?m.create(t,n.sessionDir):m.inMemory(t)}function T(e,t){let n=e?.handshakePath
|
|
1
|
+
import{SUBAGENT_ROOT_SESSION_ENV as e,SUBAGENT_RUN_ID_ENV as t,init_environment as n}from"../src/types/environment.mjs";import{init_atomicJson as r,writeAtomicJson as i}from"../src/adapters/atomicJson.mjs";import{adoptSessionScopeFromEnv as a,currentRunConfigPath as o,init_paths as s}from"../src/adapters/filesystem/paths.mjs";import{createChildTranscriptWriter as c,init_childTranscript as l}from"../src/adapters/process/childTranscript.mjs";import{startParentWatchdog as u}from"../src/adapters/runs/background/parentWatchdog.mjs";import{recordNonBlockingExtensionError as d}from"../src/services/runs/extensionErrorTelemetry.mjs";import*as f from"node:fs";import{createDoomTelemetry as p}from"@agimon-ai/doompi-telemetry";import{SessionManager as m,createAgentSessionFromServices as h,createAgentSessionServices as g,getAgentDir as _,resolveCliModel as v}from"@earendil-works/pi-coding-agent";r(),l(),s(),n();const y=`doom_team.child_finished`,b=`doom_team.child_failed`;function x(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function S(e){return e instanceof Error?e.message:String(e)}function C(e){let t=o(e),n=JSON.parse(f.readFileSync(t,`utf8`));if(!x(n)||n.runId!==e||!x(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function w(e){let{cwd:t,sdk:n}=e;return n.sessionFile?m.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?m.create(t,n.sessionDir):m.inMemory(t)}function T(e,t){let n=e?.handshakePath;n&&!f.existsSync(n)&&i(n,{state:`error`,error:S(t)})}let E,D;async function O(e,t,n){let r=D;D=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function k(){let n=Date.now();D=p({serviceName:`doom-team-sdk-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let r=process.env[t]?.trim();if(!r)throw Error(`${t} is required.`);if(!a())throw Error(`${e} is required: a child cannot resolve its session scope without it.`);let i;try{i=C(r);let e=i;await D?.recordEvent(`doom_team.child_started`,{runtime:`sdk`,"agent.name":e.agent,...e.sdk.model?{"model.id":e.sdk.model}:{},outcome:`started`});let{sdk:t}=e,a=_(),o=await g({cwd:i.cwd,agentDir:a,resourceLoaderOptions:{additionalExtensionPaths:t.extensions,additionalSkillPaths:t.skillPaths,noExtensions:t.noAmbientExtensions,noSkills:t.noSkills,noContextFiles:t.noContextFiles,...t.systemPromptMode===`replace`?{systemPrompt:t.systemPrompt}:{},...t.systemPrompt&&t.systemPromptMode!==`replace`?{appendSystemPrompt:[t.systemPrompt]}:{}}}),s=o.diagnostics.find(e=>e.type===`error`);if(s)throw Error(s.message);let l=t.model?v({cliModel:t.model,modelRuntime:o.modelRuntime}):void 0;if(l&&!l.model)throw Error(l.error??`Model '${t.model}' was not found.`);let{session:f}=await h({services:o,sessionManager:w(i),...l?.model?{model:l.model}:{},...l?.thinkingLevel?{thinkingLevel:l.thinkingLevel}:{},...t.tools?{tools:t.tools}:{},...t.noTools?{noTools:t.noTools}:{},...t.excludeTools?{excludeTools:t.excludeTools}:{}});E=u({onParentLost:()=>{f.dispose(),O(y,{runtime:`sdk`,"agent.name":e.agent,duration_ms:Date.now()-n,outcome:`parent_lost`}).finally(()=>process.exit(0))}});let p=i.transcriptPath?c({transcriptPath:i.transcriptPath,source:`async`,runId:i.runId,agent:i.agent,childIndex:i.childIndex,cwd:i.cwd}):void 0;p?.writeInitialUserMessage(i.task);let m=f.subscribe(t=>{p?.writeChildEvent(t),t.type===`agent_end`&&setImmediate(()=>{f.agent.hasQueuedMessages()||(f.dispose(),O(y,{runtime:`sdk`,"agent.name":e.agent,duration_ms:Date.now()-n,outcome:`completed`}).finally(()=>process.exit(0)))})});try{await f.bindExtensions({mode:`print`,onError:e=>{d(D,e)}}),await f.prompt(i.task)}finally{E?.(),m(),f.dispose(),await O(y,{runtime:`sdk`,"agent.name":e.agent,duration_ms:Date.now()-n,outcome:`completed`})}}catch(e){throw T(i,e),await O(b,{outcome:`failed`},e),e}}k().then(()=>{process.exit(0)},async e=>{await O(b,{outcome:`failed`},e);let t=e instanceof Error?e:Error(`Doom Team SDK child failed`,{cause:e});setImmediate(()=>{throw t})});export{k as runSdkChild};
|
|
2
2
|
//# sourceMappingURL=sdkRunnerEntry.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdkRunnerEntry.mjs","names":["fs"],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../runs/background/asyncExecution';\nimport { startParentWatchdog } from '../runs/background/parentWatchdog';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry';\nimport { writeAtomicJson } from '../atomicJson';\nimport { createChildTranscriptWriter } from './childTranscript';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../filesystem/paths';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../types/environment';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdkRunnerEntry.mjs","names":["fs"],"sources":["../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../runs/background/asyncExecution';\nimport { startParentWatchdog } from '../runs/background/parentWatchdog';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry';\nimport { writeAtomicJson } from '../atomicJson';\nimport { createChildTranscriptWriter } from './childTranscript';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../filesystem/paths';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../types/environment';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../filesystem/configDir.cjs"),n=require("./frontmatter.cjs"),r=require("./memory.cjs"),i=require("./settings.cjs");let a=require("node:fs");a=e.__toESM(a,1);let o=require("node:path");o=e.__toESM(o,1);const s=`delegate`;function c(e){return e===s?`append`:`replace`}function l(e){return e===s}function u(){return!1}const d=new Set([`name`,`package`,`description`,`tools`,`model`,`fallbackModels`,`thinking`,`systemPromptMode`,`inheritProjectContext`,`inheritSkills`,`defaultContext`,`timeoutMs`,`skill`,`skills`,`skillPath`,`extensions`,`subagentOnlyExtensions`,`output`,`defaultReads`,`defaultProgress`,`interactive`,`maxSubagentDepth`,`completionGuard`,`toolBudget`,`memory`]),f=`true`,p=`false`;function m(e){if(e===f)return!0;if(e===p)return!1}const h=/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/;function g(e){let t=e?.trim();if(t)return t.toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9.-]/g,``).replace(/-+/g,`-`).replace(/\.+/g,`.`).replace(/(?:^[-.]+|[-.]+$)/g,``)}function _(e,t=`package`){if(e===void 0||e===!1||e===``)return{packageName:void 0};if(typeof e!=`string`)return{error:`${t} must be a string or false when provided.`};let n=g(e);return!n||!h.test(n)?{error:`${t} is invalid after sanitization.`}:{packageName:n}}function v(e,t){let n=t?.trim();return n?`${n}.${e}`:e}function y(e){let t=[],n=[];for(let r of e??[])r.startsWith(`mcp:`)?t.push(r.slice(4)):n.push(r);return{...e===void 0?{}:{tools:n},...t.length>0?{mcpDirectTools:t}:{}}}const b=new Set([`.git`,`node_modules`]),x=`.agents`;function S(e){try{return a.statSync(e).isDirectory()}catch{return!1}}function C(e){return S(t.getProjectConfigDir(e))||S(o.join(e,x))}function w(e,t,n){return b.has(n)||a.existsSync(o.join(t,`.git`))?!0:o.resolve(t)!==o.resolve(e)&&C(t)}function T(e,t,n=e){let r=[];if(!a.existsSync(e))return r;let i;try{i=a.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))}catch{return r}for(let a of i){let i=o.join(e,a.name);if(a.isDirectory()){w(n,i,a.name)||r.push(...T(i,t,n));continue}
|
|
1
|
+
const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../filesystem/configDir.cjs"),n=require("./frontmatter.cjs"),r=require("./memory.cjs"),i=require("./settings.cjs");let a=require("node:fs");a=e.__toESM(a,1);let o=require("node:path");o=e.__toESM(o,1);const s=`delegate`;function c(e){return e===s?`append`:`replace`}function l(e){return e===s}function u(){return!1}const d=new Set([`name`,`package`,`description`,`tools`,`model`,`fallbackModels`,`thinking`,`systemPromptMode`,`inheritProjectContext`,`inheritSkills`,`defaultContext`,`timeoutMs`,`skill`,`skills`,`skillPath`,`extensions`,`subagentOnlyExtensions`,`output`,`defaultReads`,`defaultProgress`,`interactive`,`maxSubagentDepth`,`completionGuard`,`toolBudget`,`memory`]),f=`true`,p=`false`;function m(e){if(e===f)return!0;if(e===p)return!1}const h=/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/;function g(e){let t=e?.trim();if(t)return t.toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9.-]/g,``).replace(/-+/g,`-`).replace(/\.+/g,`.`).replace(/(?:^[-.]+|[-.]+$)/g,``)}function _(e,t=`package`){if(e===void 0||e===!1||e===``)return{packageName:void 0};if(typeof e!=`string`)return{error:`${t} must be a string or false when provided.`};let n=g(e);return!n||!h.test(n)?{error:`${t} is invalid after sanitization.`}:{packageName:n}}function v(e,t){let n=t?.trim();return n?`${n}.${e}`:e}function y(e){let t=[],n=[];for(let r of e??[])r.startsWith(`mcp:`)?t.push(r.slice(4)):n.push(r);return{...e===void 0?{}:{tools:n},...t.length>0?{mcpDirectTools:t}:{}}}const b=new Set([`.git`,`node_modules`]),x=`.agents`;function S(e){try{return a.statSync(e).isDirectory()}catch{return!1}}function C(e){return S(t.getProjectConfigDir(e))||S(o.join(e,x))}function w(e,t,n){return b.has(n)||a.existsSync(o.join(t,`.git`))?!0:o.resolve(t)!==o.resolve(e)&&C(t)}function T(e,t,n=e){let r=[];if(!a.existsSync(e))return r;let i;try{i=a.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))}catch{return r}for(let a of i){let i=o.join(e,a.name);if(a.isDirectory()){w(n,i,a.name)||r.push(...T(i,t,n));continue}(a.isFile()||a.isSymbolicLink())&&t(a.name)&&r.push(i)}return r}function E(e,t){let n=o.relative(e,t).split(o.sep).map(e=>e.toLowerCase());return o.basename(e).toLowerCase()===x&&n.unshift(x),n.some((e,t)=>e===x&&n[t+1]===`skills`)}function D(e,t){return e===`replace`||e===`append`?e:c(t)}function O(e){return e===`fork`||e===`fresh`?e:void 0}function k(e,t){if(e===void 0)return;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`Agent '${t}' has invalid timeoutMs frontmatter; expected a positive integer.`);return n}function A(e,t){if(e===void 0||!e.trim())return;let n=JSON.parse(e);if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`Agent '${t}' has invalid toolBudget frontmatter; expected a JSON object.`);return n}function j(e){return e.endsWith(`.md`)&&!e.endsWith(`.chain.md`)}function M(e,t){let o=[];for(let s of T(e,j)){if(E(e,s))continue;let c;try{c=a.readFileSync(s,`utf-8`)}catch{continue}let{frontmatter:h,body:g}=n.parseFrontmatter(c);if(!h.name||!h.description)continue;let b=h.name,x=_(h.package,`Agent '${b}' package`);if(x.error)continue;let S=n.parseFrontmatterList(h.tools),{tools:C,mcpDirectTools:w}=y(S),T=n.parseFrontmatterList(h.skill||h.skills),j=n.parseFrontmatterList(h.skillPath),M=n.parseFrontmatterList(h.fallbackModels),N=n.parseFrontmatterList(h.defaultReads),P=Number(h.maxSubagentDepth),F={};for(let[e,t]of Object.entries(h))d.has(e)||(F[e]=t);let I={name:v(b,x.packageName),localName:b,packageName:x.packageName,description:h.description,tools:S===void 0?void 0:C??[],mcpDirectTools:w&&w.length>0?w:void 0,model:h.model,fallbackModels:M&&M.length>0?M:void 0,thinking:h.thinking!==p&&h.thinking,systemPromptMode:D(h.systemPromptMode,b),inheritProjectContext:m(h.inheritProjectContext)??l(b),inheritSkills:m(h.inheritSkills)??u(),defaultContext:O(h.defaultContext),defaultTimeoutMs:k(h.timeoutMs,b),systemPrompt:g,source:t,filePath:s,skills:T&&T.length>0?T:void 0,skillPath:j&&j.length>0?j:void 0,extensions:n.parseFrontmatterList(h.extensions),subagentOnlyExtensions:n.parseFrontmatterList(h.subagentOnlyExtensions),output:h.output,defaultReads:N&&N.length>0?N:void 0,defaultProgress:h.defaultProgress===f,interactive:h.interactive===f,maxSubagentDepth:Number.isInteger(P)&&P>=0?P:void 0,completionGuard:m(h.completionGuard),toolBudget:A(h.toolBudget,b),memory:r.parseMemoryFrontmatter(h.memory),extraFields:Object.keys(F).length>0?F:void 0};i.setAgentFrontmatterFields(I,new Set(Object.keys(h))),o.push(I)}return o}function N(){return(process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS??``).split(o.delimiter).map(e=>e.trim()).filter(e=>e.length>0)}exports.EXTRA_AGENT_DIRS_ENV=`PI_SUBAGENT_EXTRA_AGENT_DIRS`,exports.LOADER_KNOWN_FIELDS=d,exports.buildRuntimeName=v,exports.defaultInheritProjectContext=l,exports.defaultInheritSkills=u,exports.defaultSystemPromptMode=c,exports.listFilesRecursive=T,exports.loadAgentsFromDir=M,exports.parsePackageName=_,exports.pluginAgentDirs=N,exports.splitToolList=y;
|
|
2
2
|
//# sourceMappingURL=loader.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.cjs","names":["fs","getProjectConfigDir","path","parseFrontmatter","parseFrontmatterList","parseMemoryFrontmatter"],"sources":["../../../../src/adapters/agents/loader.ts"],"sourcesContent":["/**\n * Reading agent definitions off disk into `AgentConfig` values.\n *\n * One markdown file is one agent: YAML frontmatter declares how the child run\n * should be shaped, and the body is its system prompt. This module owns the walk\n * that finds those files and the field-by-field interpretation of what it finds.\n * Precedence between sources, settings defaults, and builtin overrides are\n * applied by discovery afterwards, never here.\n *\n * DESIGN PATTERNS:\n * - A malformed value fails loudly, a malformed file is skipped quietly. A file\n * missing `name` or `description` is simply not an agent and must not stop the\n * sweep, but a `timeoutMs` of \"soon\" is an authoring mistake that has to\n * surface rather than be silently dropped\n * - Frontmatter keys this module does not interpret are copied into\n * `extraFields` verbatim, so a later writer can round-trip a file it did not\n * fully understand\n * - The directory walk prunes at project boundaries, so an agent directory that\n * happens to contain a checked-out sub-repository does not absorb its agents\n *\n * ASYNC-ONLY:\n * This package has no synchronous run mode, so the `async` frontmatter field is\n * not interpreted. It falls through into `extraFields` like any other key,\n * which keeps a definition written for the predecessor readable here.\n *\n * AVOID:\n * - Applying settings defaults or builtin overrides in this module\n * - Adding a field here without adding it to `LOADER_KNOWN_FIELDS`, which would\n * leak it into `extraFields` and get it written back twice\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getProjectConfigDir } from '../filesystem/configDir';\nimport type { SystemPromptMode, ToolBudgetConfig } from '../../types';\nimport { parseFrontmatter, parseFrontmatterList } from './frontmatter';\nimport { parseMemoryFrontmatter } from './memory';\nimport { setAgentFrontmatterFields } from './settings';\nimport type { AgentConfig, AgentDefaultContext, AgentSource } from './types';\n\n// ============================================================================\n// Builtin defaults\n// ============================================================================\n\n/**\n * The agents this package ships.\n *\n * Named here because a definition on disk with one of these names is an\n * override of a builtin rather than a new agent, and because their defaults\n * differ from a custom agent's.\n */\nexport const BUILTIN_AGENT_NAMES = [\n 'advisor',\n 'context-builder',\n 'delegate',\n 'oracle',\n 'planner',\n 'researcher',\n 'reviewer',\n 'scout',\n 'worker',\n] as const;\n\n/**\n * The one builtin that extends the host's context instead of replacing it.\n *\n * `delegate` exists to carry out work on the operator's behalf in the same\n * project, so it inherits the host system prompt and project context. Every\n * other agent starts clean, which is what makes its output reproducible.\n */\nconst CONTEXT_INHERITING_BUILTIN = 'delegate';\n\nexport function defaultSystemPromptMode(name: string): SystemPromptMode {\n return name === CONTEXT_INHERITING_BUILTIN ? 'append' : 'replace';\n}\n\nexport function defaultInheritProjectContext(name: string): boolean {\n return name === CONTEXT_INHERITING_BUILTIN;\n}\n\nexport function defaultInheritSkills(): boolean {\n return false;\n}\n\n// ============================================================================\n// Frontmatter vocabulary\n// ============================================================================\n\n/**\n * Every frontmatter key this module interprets.\n *\n * Anything absent from this set is preserved in `extraFields` instead. `async`\n * is deliberately absent: this package is async-only, so the key is data to\n * carry, not a setting to honour.\n */\nexport const LOADER_KNOWN_FIELDS: ReadonlySet<string> = new Set([\n 'name',\n 'package',\n 'description',\n 'tools',\n 'model',\n 'fallbackModels',\n 'thinking',\n 'systemPromptMode',\n 'inheritProjectContext',\n 'inheritSkills',\n 'defaultContext',\n 'timeoutMs',\n 'skill',\n 'skills',\n 'skillPath',\n 'extensions',\n 'subagentOnlyExtensions',\n 'output',\n 'defaultReads',\n 'defaultProgress',\n 'interactive',\n 'maxSubagentDepth',\n 'completionGuard',\n 'toolBudget',\n 'memory',\n]);\n\nconst TRUE_LITERAL = 'true';\nconst FALSE_LITERAL = 'false';\n\n/** Frontmatter carries strings, so a boolean field is a tri-state until parsed. */\nfunction parseOptionalBoolean(raw: string | undefined): boolean | undefined {\n if (raw === TRUE_LITERAL) return true;\n if (raw === FALSE_LITERAL) return false;\n return undefined;\n}\n\n// ============================================================================\n// Identity\n// ============================================================================\n\n/** A package-qualified agent name: dot-separated lowercase segments. */\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]*(?:\\.[a-z0-9][a-z0-9-]*)*$/;\nconst PACKAGE_NAME_SEPARATOR = '.';\n\n/**\n * Reduce an authored package name to the canonical form used in runtime names.\n *\n * Sanitizing rather than rejecting outright keeps a human-written `My Tools`\n * usable, while the pattern check afterwards still rejects anything that\n * sanitizes down to nothing meaningful.\n */\nfunction normalizePackageName(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n return trimmed\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9.-]/g, '')\n .replace(/-+/g, '-')\n .replace(/\\.+/g, '.')\n .replace(/(?:^[-.]+|[-.]+$)/g, '');\n}\n\n/** Validate a `package` frontmatter value. An absent or empty value is not an error. */\nexport function parsePackageName(value: unknown, label = 'package'): { packageName?: string; error?: string } {\n if (value === undefined || value === false || value === '') return { packageName: undefined };\n if (typeof value !== 'string') return { error: `${label} must be a string or false when provided.` };\n const packageName = normalizePackageName(value);\n if (!packageName || !IDENTIFIER_PATTERN.test(packageName)) {\n return { error: `${label} is invalid after sanitization.` };\n }\n return { packageName };\n}\n\n/** The name an agent is addressed by, qualified when it belongs to a package. */\nexport function buildRuntimeName(localName: string, packageName?: string): string {\n const trimmedPackage = packageName?.trim();\n return trimmedPackage ? `${trimmedPackage}${PACKAGE_NAME_SEPARATOR}${localName}` : localName;\n}\n\n// ============================================================================\n// Tool lists\n// ============================================================================\n\n/** Marks a tool that is reached through an MCP server rather than the host. */\nconst MCP_TOOL_PREFIX = 'mcp:';\n\n/**\n * Split an authored `tools` list into host tools and MCP tools.\n *\n * The two are separate fields on `AgentConfig` because they are enforced by\n * different layers, but a single flat list is what an author wants to write.\n */\nexport function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {\n const mcpDirectTools: string[] = [];\n const tools: string[] = [];\n for (const tool of rawTools ?? []) {\n if (tool.startsWith(MCP_TOOL_PREFIX)) {\n mcpDirectTools.push(tool.slice(MCP_TOOL_PREFIX.length));\n } else {\n tools.push(tool);\n }\n }\n return {\n // An empty `tools:` means \"no tools\", which is not the same as an absent key.\n ...(rawTools !== undefined ? { tools } : {}),\n ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n };\n}\n\n// ============================================================================\n// Directory walk\n// ============================================================================\n\nconst DISCOVERY_PRUNED_DIR_NAMES: ReadonlySet<string> = new Set(['.git', 'node_modules']);\nconst GIT_DIR_NAME = '.git';\nconst LEGACY_AGENTS_DIR_NAME = '.agents';\nconst LEGACY_SKILLS_DIR_NAME = 'skills';\nconst AGENT_FILE_EXTENSION = '.md';\nconst CHAIN_FILE_EXTENSION = '.chain.md';\n\nfunction isDirectory(target: string): boolean {\n try {\n return fs.statSync(target).isDirectory();\n } catch {\n // A missing or unreadable path is simply not a directory for our purposes.\n return false;\n }\n}\n\n/** A directory that owns its own agent configuration is a separate project. */\nfunction isDiscoveryNestedProjectRoot(dir: string): boolean {\n return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, LEGACY_AGENTS_DIR_NAME));\n}\n\n/**\n * Decide whether the walk should skip a subdirectory.\n *\n * A nested repository or nested project root is pruned because its agents\n * belong to that project, not to the one being scanned. The root itself is\n * exempt: scanning a project's own agent directory must not prune it.\n */\nfunction shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {\n if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;\n if (fs.existsSync(path.join(dir, GIT_DIR_NAME))) return true;\n return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);\n}\n\n/**\n * Collect matching files under `dir`, sorted so discovery order is stable.\n *\n * Symlinked entries are followed as files, because staging an agent by symlink\n * is a supported way to share one definition across projects.\n */\nexport function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {\n const files: string[] = [];\n if (!fs.existsSync(dir)) return files;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));\n } catch {\n // An unreadable directory yields nothing rather than failing the whole sweep.\n return files;\n }\n\n for (const entry of entries) {\n const filePath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {\n files.push(...listFilesRecursive(filePath, predicate, rootDir));\n }\n continue;\n }\n if (!entry.isFile() && !entry.isSymbolicLink()) continue;\n if (!predicate(entry.name)) continue;\n files.push(filePath);\n }\n return files;\n}\n\n/**\n * Recognise a file that lives under a legacy `.agents/skills/` directory.\n *\n * Those markdown files are skill documents, not agent definitions, and they\n * predate the split. They would otherwise be loaded as nameless agents.\n */\nfunction isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {\n const relative = path.relative(rootDir, filePath);\n const parts = relative.split(path.sep).map((part) => part.toLowerCase());\n if (path.basename(rootDir).toLowerCase() === LEGACY_AGENTS_DIR_NAME) {\n parts.unshift(LEGACY_AGENTS_DIR_NAME);\n }\n return parts.some((part, index) => part === LEGACY_AGENTS_DIR_NAME && parts[index + 1] === LEGACY_SKILLS_DIR_NAME);\n}\n\n// ============================================================================\n// Structured field parsing\n// ============================================================================\n\nfunction parseSystemPromptMode(raw: string | undefined, localName: string): SystemPromptMode {\n if (raw === 'replace' || raw === 'append') return raw;\n return defaultSystemPromptMode(localName);\n}\n\nfunction parseDefaultContext(raw: string | undefined): AgentDefaultContext | undefined {\n return raw === 'fork' || raw === 'fresh' ? raw : undefined;\n}\n\nfunction parseTimeoutMs(raw: string | undefined, localName: string): number | undefined {\n if (raw === undefined) return undefined;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);\n }\n return parsed;\n}\n\nfunction parseToolBudget(raw: string | undefined, localName: string): ToolBudgetConfig | undefined {\n if (raw === undefined || !raw.trim()) return undefined;\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);\n }\n // Field-level validation lives with the enforcement layer in the runs domain.\n return parsed as ToolBudgetConfig;\n}\n\n// ============================================================================\n// Loading\n// ============================================================================\n\n/** True for an agent definition file, false for a chain or anything else. */\nfunction isAgentFileName(fileName: string): boolean {\n return fileName.endsWith(AGENT_FILE_EXTENSION) && !fileName.endsWith(CHAIN_FILE_EXTENSION);\n}\n\n/**\n * Load every agent definition under `dir`.\n *\n * The returned configs carry only what the file itself declared. Settings\n * defaults, builtin overrides, and cross-source precedence are the caller's job.\n */\nexport function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {\n const agents: AgentConfig[] = [];\n\n for (const filePath of listFilesRecursive(dir, isAgentFileName)) {\n if (isLegacyAgentSkillPath(dir, filePath)) continue;\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch {\n // The file can be removed or replaced mid-sweep; skip it, do not abort.\n continue;\n }\n\n const { frontmatter, body } = parseFrontmatter(content);\n // Without both of these the file is documentation, not an agent.\n if (!frontmatter.name || !frontmatter.description) continue;\n\n const localName = frontmatter.name;\n const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);\n // An unusable package name would produce an unaddressable runtime name.\n if (parsedPackage.error) continue;\n\n const rawTools = parseFrontmatterList(frontmatter.tools);\n const { tools, mcpDirectTools } = splitToolList(rawTools);\n const skills = parseFrontmatterList(frontmatter.skill || frontmatter.skills);\n const skillPath = parseFrontmatterList(frontmatter.skillPath);\n const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);\n const defaultReads = parseFrontmatterList(frontmatter.defaultReads);\n const maxSubagentDepth = Number(frontmatter.maxSubagentDepth);\n\n const extraFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(frontmatter)) {\n if (!LOADER_KNOWN_FIELDS.has(key)) extraFields[key] = value;\n }\n\n const agent: AgentConfig = {\n name: buildRuntimeName(localName, parsedPackage.packageName),\n localName,\n packageName: parsedPackage.packageName,\n description: frontmatter.description,\n tools: rawTools !== undefined ? (tools ?? []) : undefined,\n mcpDirectTools: mcpDirectTools && mcpDirectTools.length > 0 ? mcpDirectTools : undefined,\n model: frontmatter.model,\n fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,\n thinking: frontmatter.thinking === FALSE_LITERAL ? false : frontmatter.thinking,\n systemPromptMode: parseSystemPromptMode(frontmatter.systemPromptMode, localName),\n inheritProjectContext:\n parseOptionalBoolean(frontmatter.inheritProjectContext) ?? defaultInheritProjectContext(localName),\n inheritSkills: parseOptionalBoolean(frontmatter.inheritSkills) ?? defaultInheritSkills(),\n defaultContext: parseDefaultContext(frontmatter.defaultContext),\n defaultTimeoutMs: parseTimeoutMs(frontmatter.timeoutMs, localName),\n systemPrompt: body,\n source,\n filePath,\n skills: skills && skills.length > 0 ? skills : undefined,\n skillPath: skillPath && skillPath.length > 0 ? skillPath : undefined,\n extensions: parseFrontmatterList(frontmatter.extensions),\n subagentOnlyExtensions: parseFrontmatterList(frontmatter.subagentOnlyExtensions),\n output: frontmatter.output,\n defaultReads: defaultReads && defaultReads.length > 0 ? defaultReads : undefined,\n defaultProgress: frontmatter.defaultProgress === TRUE_LITERAL,\n interactive: frontmatter.interactive === TRUE_LITERAL,\n maxSubagentDepth: Number.isInteger(maxSubagentDepth) && maxSubagentDepth >= 0 ? maxSubagentDepth : undefined,\n completionGuard: parseOptionalBoolean(frontmatter.completionGuard),\n toolBudget: parseToolBudget(frontmatter.toolBudget, localName),\n memory: parseMemoryFrontmatter(frontmatter.memory),\n extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,\n };\n // Record what the file actually declared, so a later settings pass can tell\n // an author's explicit value from one this loader defaulted in.\n setAgentFrontmatterFields(agent, new Set(Object.keys(frontmatter)));\n agents.push(agent);\n }\n\n return agents;\n}\n\n// ============================================================================\n// Plugin directories\n// ============================================================================\n\n/** Path-delimited list of read-only agent directories staged by the host. */\nexport const EXTRA_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\n\n/**\n * Read-only agent directories contributed by plugins.\n *\n * Read from the environment on every call rather than captured once, because a\n * host can stage a plugin directory after this module is first imported.\n */\nexport function pluginAgentDirs(): string[] {\n return (process.env[EXTRA_AGENT_DIRS_ENV] ?? '')\n .split(path.delimiter)\n .map((directory) => directory.trim())\n .filter((directory) => directory.length > 0);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loader.cjs","names":["fs","getProjectConfigDir","path","parseFrontmatter","parseFrontmatterList","parseMemoryFrontmatter"],"sources":["../../../../src/adapters/agents/loader.ts"],"sourcesContent":["/**\n * Reading agent definitions off disk into `AgentConfig` values.\n *\n * One markdown file is one agent: YAML frontmatter declares how the child run\n * should be shaped, and the body is its system prompt. This module owns the walk\n * that finds those files and the field-by-field interpretation of what it finds.\n * Precedence between sources, settings defaults, and builtin overrides are\n * applied by discovery afterwards, never here.\n *\n * DESIGN PATTERNS:\n * - A malformed value fails loudly, a malformed file is skipped quietly. A file\n * missing `name` or `description` is simply not an agent and must not stop the\n * sweep, but a `timeoutMs` of \"soon\" is an authoring mistake that has to\n * surface rather than be silently dropped\n * - Frontmatter keys this module does not interpret are copied into\n * `extraFields` verbatim, so a later writer can round-trip a file it did not\n * fully understand\n * - The directory walk prunes at project boundaries, so an agent directory that\n * happens to contain a checked-out sub-repository does not absorb its agents\n *\n * ASYNC-ONLY:\n * This package has no synchronous run mode, so the `async` frontmatter field is\n * not interpreted. It falls through into `extraFields` like any other key,\n * which keeps a definition written for the predecessor readable here.\n *\n * AVOID:\n * - Applying settings defaults or builtin overrides in this module\n * - Adding a field here without adding it to `LOADER_KNOWN_FIELDS`, which would\n * leak it into `extraFields` and get it written back twice\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getProjectConfigDir } from '../filesystem/configDir';\nimport type { SystemPromptMode, ToolBudgetConfig } from '../../types';\nimport { parseFrontmatter, parseFrontmatterList } from './frontmatter';\nimport { parseMemoryFrontmatter } from './memory';\nimport { setAgentFrontmatterFields } from './settings';\nimport type { AgentConfig, AgentDefaultContext, AgentSource } from './types';\n\n// ============================================================================\n// Builtin defaults\n// ============================================================================\n\n/**\n * The agents this package ships.\n *\n * Named here because a definition on disk with one of these names is an\n * override of a builtin rather than a new agent, and because their defaults\n * differ from a custom agent's.\n */\nexport const BUILTIN_AGENT_NAMES = [\n 'advisor',\n 'context-builder',\n 'delegate',\n 'oracle',\n 'planner',\n 'researcher',\n 'reviewer',\n 'scout',\n 'worker',\n] as const;\n\n/**\n * The one builtin that extends the host's context instead of replacing it.\n *\n * `delegate` exists to carry out work on the operator's behalf in the same\n * project, so it inherits the host system prompt and project context. Every\n * other agent starts clean, which is what makes its output reproducible.\n */\nconst CONTEXT_INHERITING_BUILTIN = 'delegate';\n\nexport function defaultSystemPromptMode(name: string): SystemPromptMode {\n return name === CONTEXT_INHERITING_BUILTIN ? 'append' : 'replace';\n}\n\nexport function defaultInheritProjectContext(name: string): boolean {\n return name === CONTEXT_INHERITING_BUILTIN;\n}\n\nexport function defaultInheritSkills(): boolean {\n return false;\n}\n\n// ============================================================================\n// Frontmatter vocabulary\n// ============================================================================\n\n/**\n * Every frontmatter key this module interprets.\n *\n * Anything absent from this set is preserved in `extraFields` instead. `async`\n * is deliberately absent: this package is async-only, so the key is data to\n * carry, not a setting to honour.\n */\nexport const LOADER_KNOWN_FIELDS: ReadonlySet<string> = new Set([\n 'name',\n 'package',\n 'description',\n 'tools',\n 'model',\n 'fallbackModels',\n 'thinking',\n 'systemPromptMode',\n 'inheritProjectContext',\n 'inheritSkills',\n 'defaultContext',\n 'timeoutMs',\n 'skill',\n 'skills',\n 'skillPath',\n 'extensions',\n 'subagentOnlyExtensions',\n 'output',\n 'defaultReads',\n 'defaultProgress',\n 'interactive',\n 'maxSubagentDepth',\n 'completionGuard',\n 'toolBudget',\n 'memory',\n]);\n\nconst TRUE_LITERAL = 'true';\nconst FALSE_LITERAL = 'false';\n\n/** Frontmatter carries strings, so a boolean field is a tri-state until parsed. */\nfunction parseOptionalBoolean(raw: string | undefined): boolean | undefined {\n if (raw === TRUE_LITERAL) return true;\n if (raw === FALSE_LITERAL) return false;\n return undefined;\n}\n\n// ============================================================================\n// Identity\n// ============================================================================\n\n/** A package-qualified agent name: dot-separated lowercase segments. */\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]*(?:\\.[a-z0-9][a-z0-9-]*)*$/;\nconst PACKAGE_NAME_SEPARATOR = '.';\n\n/**\n * Reduce an authored package name to the canonical form used in runtime names.\n *\n * Sanitizing rather than rejecting outright keeps a human-written `My Tools`\n * usable, while the pattern check afterwards still rejects anything that\n * sanitizes down to nothing meaningful.\n */\nfunction normalizePackageName(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n return trimmed\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9.-]/g, '')\n .replace(/-+/g, '-')\n .replace(/\\.+/g, '.')\n .replace(/(?:^[-.]+|[-.]+$)/g, '');\n}\n\n/** Validate a `package` frontmatter value. An absent or empty value is not an error. */\nexport function parsePackageName(value: unknown, label = 'package'): { packageName?: string; error?: string } {\n if (value === undefined || value === false || value === '') return { packageName: undefined };\n if (typeof value !== 'string') return { error: `${label} must be a string or false when provided.` };\n const packageName = normalizePackageName(value);\n if (!packageName || !IDENTIFIER_PATTERN.test(packageName)) {\n return { error: `${label} is invalid after sanitization.` };\n }\n return { packageName };\n}\n\n/** The name an agent is addressed by, qualified when it belongs to a package. */\nexport function buildRuntimeName(localName: string, packageName?: string): string {\n const trimmedPackage = packageName?.trim();\n return trimmedPackage ? `${trimmedPackage}${PACKAGE_NAME_SEPARATOR}${localName}` : localName;\n}\n\n// ============================================================================\n// Tool lists\n// ============================================================================\n\n/** Marks a tool that is reached through an MCP server rather than the host. */\nconst MCP_TOOL_PREFIX = 'mcp:';\n\n/**\n * Split an authored `tools` list into host tools and MCP tools.\n *\n * The two are separate fields on `AgentConfig` because they are enforced by\n * different layers, but a single flat list is what an author wants to write.\n */\nexport function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {\n const mcpDirectTools: string[] = [];\n const tools: string[] = [];\n for (const tool of rawTools ?? []) {\n if (tool.startsWith(MCP_TOOL_PREFIX)) {\n mcpDirectTools.push(tool.slice(MCP_TOOL_PREFIX.length));\n } else {\n tools.push(tool);\n }\n }\n return {\n // An empty `tools:` means \"no tools\", which is not the same as an absent key.\n ...(rawTools !== undefined ? { tools } : {}),\n ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n };\n}\n\n// ============================================================================\n// Directory walk\n// ============================================================================\n\nconst DISCOVERY_PRUNED_DIR_NAMES: ReadonlySet<string> = new Set(['.git', 'node_modules']);\nconst GIT_DIR_NAME = '.git';\nconst LEGACY_AGENTS_DIR_NAME = '.agents';\nconst LEGACY_SKILLS_DIR_NAME = 'skills';\nconst AGENT_FILE_EXTENSION = '.md';\nconst CHAIN_FILE_EXTENSION = '.chain.md';\n\nfunction isDirectory(target: string): boolean {\n try {\n return fs.statSync(target).isDirectory();\n } catch {\n // A missing or unreadable path is simply not a directory for our purposes.\n return false;\n }\n}\n\n/** A directory that owns its own agent configuration is a separate project. */\nfunction isDiscoveryNestedProjectRoot(dir: string): boolean {\n return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, LEGACY_AGENTS_DIR_NAME));\n}\n\n/**\n * Decide whether the walk should skip a subdirectory.\n *\n * A nested repository or nested project root is pruned because its agents\n * belong to that project, not to the one being scanned. The root itself is\n * exempt: scanning a project's own agent directory must not prune it.\n */\nfunction shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {\n if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;\n if (fs.existsSync(path.join(dir, GIT_DIR_NAME))) return true;\n return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);\n}\n\n/**\n * Collect matching files under `dir`, sorted so discovery order is stable.\n *\n * Symlinked entries are followed as files, because staging an agent by symlink\n * is a supported way to share one definition across projects.\n */\nexport function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {\n const files: string[] = [];\n if (!fs.existsSync(dir)) return files;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));\n } catch {\n // An unreadable directory yields nothing rather than failing the whole sweep.\n return files;\n }\n\n for (const entry of entries) {\n const filePath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {\n files.push(...listFilesRecursive(filePath, predicate, rootDir));\n }\n continue;\n }\n if (!entry.isFile() && !entry.isSymbolicLink()) continue;\n if (!predicate(entry.name)) continue;\n files.push(filePath);\n }\n return files;\n}\n\n/**\n * Recognise a file that lives under a legacy `.agents/skills/` directory.\n *\n * Those markdown files are skill documents, not agent definitions, and they\n * predate the split. They would otherwise be loaded as nameless agents.\n */\nfunction isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {\n const relative = path.relative(rootDir, filePath);\n const parts = relative.split(path.sep).map((part) => part.toLowerCase());\n if (path.basename(rootDir).toLowerCase() === LEGACY_AGENTS_DIR_NAME) {\n parts.unshift(LEGACY_AGENTS_DIR_NAME);\n }\n return parts.some((part, index) => part === LEGACY_AGENTS_DIR_NAME && parts[index + 1] === LEGACY_SKILLS_DIR_NAME);\n}\n\n// ============================================================================\n// Structured field parsing\n// ============================================================================\n\nfunction parseSystemPromptMode(raw: string | undefined, localName: string): SystemPromptMode {\n if (raw === 'replace' || raw === 'append') return raw;\n return defaultSystemPromptMode(localName);\n}\n\nfunction parseDefaultContext(raw: string | undefined): AgentDefaultContext | undefined {\n return raw === 'fork' || raw === 'fresh' ? raw : undefined;\n}\n\nfunction parseTimeoutMs(raw: string | undefined, localName: string): number | undefined {\n if (raw === undefined) return undefined;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);\n }\n return parsed;\n}\n\nfunction parseToolBudget(raw: string | undefined, localName: string): ToolBudgetConfig | undefined {\n if (raw === undefined || !raw.trim()) return undefined;\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);\n }\n // Field-level validation lives with the enforcement layer in the runs domain.\n return parsed as ToolBudgetConfig;\n}\n\n// ============================================================================\n// Loading\n// ============================================================================\n\n/** True for an agent definition file, false for a chain or anything else. */\nfunction isAgentFileName(fileName: string): boolean {\n return fileName.endsWith(AGENT_FILE_EXTENSION) && !fileName.endsWith(CHAIN_FILE_EXTENSION);\n}\n\n/**\n * Load every agent definition under `dir`.\n *\n * The returned configs carry only what the file itself declared. Settings\n * defaults, builtin overrides, and cross-source precedence are the caller's job.\n */\nexport function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {\n const agents: AgentConfig[] = [];\n\n for (const filePath of listFilesRecursive(dir, isAgentFileName)) {\n if (isLegacyAgentSkillPath(dir, filePath)) continue;\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch {\n // The file can be removed or replaced mid-sweep; skip it, do not abort.\n continue;\n }\n\n const { frontmatter, body } = parseFrontmatter(content);\n // Without both of these the file is documentation, not an agent.\n if (!frontmatter.name || !frontmatter.description) continue;\n\n const localName = frontmatter.name;\n const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);\n // An unusable package name would produce an unaddressable runtime name.\n if (parsedPackage.error) continue;\n\n const rawTools = parseFrontmatterList(frontmatter.tools);\n const { tools, mcpDirectTools } = splitToolList(rawTools);\n const skills = parseFrontmatterList(frontmatter.skill || frontmatter.skills);\n const skillPath = parseFrontmatterList(frontmatter.skillPath);\n const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);\n const defaultReads = parseFrontmatterList(frontmatter.defaultReads);\n const maxSubagentDepth = Number(frontmatter.maxSubagentDepth);\n\n const extraFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(frontmatter)) {\n if (!LOADER_KNOWN_FIELDS.has(key)) extraFields[key] = value;\n }\n\n const agent: AgentConfig = {\n name: buildRuntimeName(localName, parsedPackage.packageName),\n localName,\n packageName: parsedPackage.packageName,\n description: frontmatter.description,\n tools: rawTools !== undefined ? (tools ?? []) : undefined,\n mcpDirectTools: mcpDirectTools && mcpDirectTools.length > 0 ? mcpDirectTools : undefined,\n model: frontmatter.model,\n fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,\n thinking: frontmatter.thinking === FALSE_LITERAL ? false : frontmatter.thinking,\n systemPromptMode: parseSystemPromptMode(frontmatter.systemPromptMode, localName),\n inheritProjectContext:\n parseOptionalBoolean(frontmatter.inheritProjectContext) ?? defaultInheritProjectContext(localName),\n inheritSkills: parseOptionalBoolean(frontmatter.inheritSkills) ?? defaultInheritSkills(),\n defaultContext: parseDefaultContext(frontmatter.defaultContext),\n defaultTimeoutMs: parseTimeoutMs(frontmatter.timeoutMs, localName),\n systemPrompt: body,\n source,\n filePath,\n skills: skills && skills.length > 0 ? skills : undefined,\n skillPath: skillPath && skillPath.length > 0 ? skillPath : undefined,\n extensions: parseFrontmatterList(frontmatter.extensions),\n subagentOnlyExtensions: parseFrontmatterList(frontmatter.subagentOnlyExtensions),\n output: frontmatter.output,\n defaultReads: defaultReads && defaultReads.length > 0 ? defaultReads : undefined,\n defaultProgress: frontmatter.defaultProgress === TRUE_LITERAL,\n interactive: frontmatter.interactive === TRUE_LITERAL,\n maxSubagentDepth: Number.isInteger(maxSubagentDepth) && maxSubagentDepth >= 0 ? maxSubagentDepth : undefined,\n completionGuard: parseOptionalBoolean(frontmatter.completionGuard),\n toolBudget: parseToolBudget(frontmatter.toolBudget, localName),\n memory: parseMemoryFrontmatter(frontmatter.memory),\n extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,\n };\n // Record what the file actually declared, so a later settings pass can tell\n // an author's explicit value from one this loader defaulted in.\n setAgentFrontmatterFields(agent, new Set(Object.keys(frontmatter)));\n agents.push(agent);\n }\n\n return agents;\n}\n\n// ============================================================================\n// Plugin directories\n// ============================================================================\n\n/** Path-delimited list of read-only agent directories staged by the host. */\nexport const EXTRA_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\n\n/**\n * Read-only agent directories contributed by plugins.\n *\n * Read from the environment on every call rather than captured once, because a\n * host can stage a plugin directory after this module is first imported.\n */\nexport function pluginAgentDirs(): string[] {\n return (process.env[EXTRA_AGENT_DIRS_ENV] ?? '')\n .split(path.delimiter)\n .map((directory) => directory.trim())\n .filter((directory) => directory.length > 0);\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getProjectConfigDir as e,init_configDir as t}from"../filesystem/configDir.mjs";import{parseFrontmatter as n,parseFrontmatterList as r}from"./frontmatter.mjs";import{parseMemoryFrontmatter as i}from"./memory.mjs";import{setAgentFrontmatterFields as a}from"./settings.mjs";import*as o from"node:fs";import*as s from"node:path";t();const c=`delegate`;function l(e){return e===c?`append`:`replace`}function u(e){return e===c}function d(){return!1}const f=new Set([`name`,`package`,`description`,`tools`,`model`,`fallbackModels`,`thinking`,`systemPromptMode`,`inheritProjectContext`,`inheritSkills`,`defaultContext`,`timeoutMs`,`skill`,`skills`,`skillPath`,`extensions`,`subagentOnlyExtensions`,`output`,`defaultReads`,`defaultProgress`,`interactive`,`maxSubagentDepth`,`completionGuard`,`toolBudget`,`memory`]),p=`true`,m=`false`;function h(e){if(e===p)return!0;if(e===m)return!1}const g=/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/;function _(e){let t=e?.trim();if(t)return t.toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9.-]/g,``).replace(/-+/g,`-`).replace(/\.+/g,`.`).replace(/(?:^[-.]+|[-.]+$)/g,``)}function v(e,t=`package`){if(e===void 0||e===!1||e===``)return{packageName:void 0};if(typeof e!=`string`)return{error:`${t} must be a string or false when provided.`};let n=_(e);return!n||!g.test(n)?{error:`${t} is invalid after sanitization.`}:{packageName:n}}function y(e,t){let n=t?.trim();return n?`${n}.${e}`:e}function b(e){let t=[],n=[];for(let r of e??[])r.startsWith(`mcp:`)?t.push(r.slice(4)):n.push(r);return{...e===void 0?{}:{tools:n},...t.length>0?{mcpDirectTools:t}:{}}}const x=new Set([`.git`,`node_modules`]),S=`.agents`;function C(e){try{return o.statSync(e).isDirectory()}catch{return!1}}function w(t){return C(e(t))||C(s.join(t,S))}function T(e,t,n){return x.has(n)||o.existsSync(s.join(t,`.git`))?!0:s.resolve(t)!==s.resolve(e)&&w(t)}function E(e,t,n=e){let r=[];if(!o.existsSync(e))return r;let i;try{i=o.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))}catch{return r}for(let a of i){let i=s.join(e,a.name);if(a.isDirectory()){T(n,i,a.name)||r.push(...E(i,t,n));continue}
|
|
1
|
+
import{getProjectConfigDir as e,init_configDir as t}from"../filesystem/configDir.mjs";import{parseFrontmatter as n,parseFrontmatterList as r}from"./frontmatter.mjs";import{parseMemoryFrontmatter as i}from"./memory.mjs";import{setAgentFrontmatterFields as a}from"./settings.mjs";import*as o from"node:fs";import*as s from"node:path";t();const c=`delegate`;function l(e){return e===c?`append`:`replace`}function u(e){return e===c}function d(){return!1}const f=new Set([`name`,`package`,`description`,`tools`,`model`,`fallbackModels`,`thinking`,`systemPromptMode`,`inheritProjectContext`,`inheritSkills`,`defaultContext`,`timeoutMs`,`skill`,`skills`,`skillPath`,`extensions`,`subagentOnlyExtensions`,`output`,`defaultReads`,`defaultProgress`,`interactive`,`maxSubagentDepth`,`completionGuard`,`toolBudget`,`memory`]),p=`true`,m=`false`;function h(e){if(e===p)return!0;if(e===m)return!1}const g=/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/;function _(e){let t=e?.trim();if(t)return t.toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9.-]/g,``).replace(/-+/g,`-`).replace(/\.+/g,`.`).replace(/(?:^[-.]+|[-.]+$)/g,``)}function v(e,t=`package`){if(e===void 0||e===!1||e===``)return{packageName:void 0};if(typeof e!=`string`)return{error:`${t} must be a string or false when provided.`};let n=_(e);return!n||!g.test(n)?{error:`${t} is invalid after sanitization.`}:{packageName:n}}function y(e,t){let n=t?.trim();return n?`${n}.${e}`:e}function b(e){let t=[],n=[];for(let r of e??[])r.startsWith(`mcp:`)?t.push(r.slice(4)):n.push(r);return{...e===void 0?{}:{tools:n},...t.length>0?{mcpDirectTools:t}:{}}}const x=new Set([`.git`,`node_modules`]),S=`.agents`;function C(e){try{return o.statSync(e).isDirectory()}catch{return!1}}function w(t){return C(e(t))||C(s.join(t,S))}function T(e,t,n){return x.has(n)||o.existsSync(s.join(t,`.git`))?!0:s.resolve(t)!==s.resolve(e)&&w(t)}function E(e,t,n=e){let r=[];if(!o.existsSync(e))return r;let i;try{i=o.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))}catch{return r}for(let a of i){let i=s.join(e,a.name);if(a.isDirectory()){T(n,i,a.name)||r.push(...E(i,t,n));continue}(a.isFile()||a.isSymbolicLink())&&t(a.name)&&r.push(i)}return r}function D(e,t){let n=s.relative(e,t).split(s.sep).map(e=>e.toLowerCase());return s.basename(e).toLowerCase()===S&&n.unshift(S),n.some((e,t)=>e===S&&n[t+1]===`skills`)}function O(e,t){return e===`replace`||e===`append`?e:l(t)}function k(e){return e===`fork`||e===`fresh`?e:void 0}function A(e,t){if(e===void 0)return;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`Agent '${t}' has invalid timeoutMs frontmatter; expected a positive integer.`);return n}function j(e,t){if(e===void 0||!e.trim())return;let n=JSON.parse(e);if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`Agent '${t}' has invalid toolBudget frontmatter; expected a JSON object.`);return n}function M(e){return e.endsWith(`.md`)&&!e.endsWith(`.chain.md`)}function N(e,t){let s=[];for(let c of E(e,M)){if(D(e,c))continue;let l;try{l=o.readFileSync(c,`utf-8`)}catch{continue}let{frontmatter:g,body:_}=n(l);if(!g.name||!g.description)continue;let x=g.name,S=v(g.package,`Agent '${x}' package`);if(S.error)continue;let C=r(g.tools),{tools:w,mcpDirectTools:T}=b(C),E=r(g.skill||g.skills),M=r(g.skillPath),N=r(g.fallbackModels),P=r(g.defaultReads),F=Number(g.maxSubagentDepth),I={};for(let[e,t]of Object.entries(g))f.has(e)||(I[e]=t);let L={name:y(x,S.packageName),localName:x,packageName:S.packageName,description:g.description,tools:C===void 0?void 0:w??[],mcpDirectTools:T&&T.length>0?T:void 0,model:g.model,fallbackModels:N&&N.length>0?N:void 0,thinking:g.thinking!==m&&g.thinking,systemPromptMode:O(g.systemPromptMode,x),inheritProjectContext:h(g.inheritProjectContext)??u(x),inheritSkills:h(g.inheritSkills)??d(),defaultContext:k(g.defaultContext),defaultTimeoutMs:A(g.timeoutMs,x),systemPrompt:_,source:t,filePath:c,skills:E&&E.length>0?E:void 0,skillPath:M&&M.length>0?M:void 0,extensions:r(g.extensions),subagentOnlyExtensions:r(g.subagentOnlyExtensions),output:g.output,defaultReads:P&&P.length>0?P:void 0,defaultProgress:g.defaultProgress===p,interactive:g.interactive===p,maxSubagentDepth:Number.isInteger(F)&&F>=0?F:void 0,completionGuard:h(g.completionGuard),toolBudget:j(g.toolBudget,x),memory:i(g.memory),extraFields:Object.keys(I).length>0?I:void 0};a(L,new Set(Object.keys(g))),s.push(L)}return s}const P=`PI_SUBAGENT_EXTRA_AGENT_DIRS`;function F(){return(process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS??``).split(s.delimiter).map(e=>e.trim()).filter(e=>e.length>0)}export{P as EXTRA_AGENT_DIRS_ENV,f as LOADER_KNOWN_FIELDS,y as buildRuntimeName,u as defaultInheritProjectContext,d as defaultInheritSkills,l as defaultSystemPromptMode,E as listFilesRecursive,N as loadAgentsFromDir,v as parsePackageName,F as pluginAgentDirs,b as splitToolList};
|
|
2
2
|
//# sourceMappingURL=loader.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.mjs","names":["fs","path"],"sources":["../../../../src/adapters/agents/loader.ts"],"sourcesContent":["/**\n * Reading agent definitions off disk into `AgentConfig` values.\n *\n * One markdown file is one agent: YAML frontmatter declares how the child run\n * should be shaped, and the body is its system prompt. This module owns the walk\n * that finds those files and the field-by-field interpretation of what it finds.\n * Precedence between sources, settings defaults, and builtin overrides are\n * applied by discovery afterwards, never here.\n *\n * DESIGN PATTERNS:\n * - A malformed value fails loudly, a malformed file is skipped quietly. A file\n * missing `name` or `description` is simply not an agent and must not stop the\n * sweep, but a `timeoutMs` of \"soon\" is an authoring mistake that has to\n * surface rather than be silently dropped\n * - Frontmatter keys this module does not interpret are copied into\n * `extraFields` verbatim, so a later writer can round-trip a file it did not\n * fully understand\n * - The directory walk prunes at project boundaries, so an agent directory that\n * happens to contain a checked-out sub-repository does not absorb its agents\n *\n * ASYNC-ONLY:\n * This package has no synchronous run mode, so the `async` frontmatter field is\n * not interpreted. It falls through into `extraFields` like any other key,\n * which keeps a definition written for the predecessor readable here.\n *\n * AVOID:\n * - Applying settings defaults or builtin overrides in this module\n * - Adding a field here without adding it to `LOADER_KNOWN_FIELDS`, which would\n * leak it into `extraFields` and get it written back twice\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getProjectConfigDir } from '../filesystem/configDir';\nimport type { SystemPromptMode, ToolBudgetConfig } from '../../types';\nimport { parseFrontmatter, parseFrontmatterList } from './frontmatter';\nimport { parseMemoryFrontmatter } from './memory';\nimport { setAgentFrontmatterFields } from './settings';\nimport type { AgentConfig, AgentDefaultContext, AgentSource } from './types';\n\n// ============================================================================\n// Builtin defaults\n// ============================================================================\n\n/**\n * The agents this package ships.\n *\n * Named here because a definition on disk with one of these names is an\n * override of a builtin rather than a new agent, and because their defaults\n * differ from a custom agent's.\n */\nexport const BUILTIN_AGENT_NAMES = [\n 'advisor',\n 'context-builder',\n 'delegate',\n 'oracle',\n 'planner',\n 'researcher',\n 'reviewer',\n 'scout',\n 'worker',\n] as const;\n\n/**\n * The one builtin that extends the host's context instead of replacing it.\n *\n * `delegate` exists to carry out work on the operator's behalf in the same\n * project, so it inherits the host system prompt and project context. Every\n * other agent starts clean, which is what makes its output reproducible.\n */\nconst CONTEXT_INHERITING_BUILTIN = 'delegate';\n\nexport function defaultSystemPromptMode(name: string): SystemPromptMode {\n return name === CONTEXT_INHERITING_BUILTIN ? 'append' : 'replace';\n}\n\nexport function defaultInheritProjectContext(name: string): boolean {\n return name === CONTEXT_INHERITING_BUILTIN;\n}\n\nexport function defaultInheritSkills(): boolean {\n return false;\n}\n\n// ============================================================================\n// Frontmatter vocabulary\n// ============================================================================\n\n/**\n * Every frontmatter key this module interprets.\n *\n * Anything absent from this set is preserved in `extraFields` instead. `async`\n * is deliberately absent: this package is async-only, so the key is data to\n * carry, not a setting to honour.\n */\nexport const LOADER_KNOWN_FIELDS: ReadonlySet<string> = new Set([\n 'name',\n 'package',\n 'description',\n 'tools',\n 'model',\n 'fallbackModels',\n 'thinking',\n 'systemPromptMode',\n 'inheritProjectContext',\n 'inheritSkills',\n 'defaultContext',\n 'timeoutMs',\n 'skill',\n 'skills',\n 'skillPath',\n 'extensions',\n 'subagentOnlyExtensions',\n 'output',\n 'defaultReads',\n 'defaultProgress',\n 'interactive',\n 'maxSubagentDepth',\n 'completionGuard',\n 'toolBudget',\n 'memory',\n]);\n\nconst TRUE_LITERAL = 'true';\nconst FALSE_LITERAL = 'false';\n\n/** Frontmatter carries strings, so a boolean field is a tri-state until parsed. */\nfunction parseOptionalBoolean(raw: string | undefined): boolean | undefined {\n if (raw === TRUE_LITERAL) return true;\n if (raw === FALSE_LITERAL) return false;\n return undefined;\n}\n\n// ============================================================================\n// Identity\n// ============================================================================\n\n/** A package-qualified agent name: dot-separated lowercase segments. */\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]*(?:\\.[a-z0-9][a-z0-9-]*)*$/;\nconst PACKAGE_NAME_SEPARATOR = '.';\n\n/**\n * Reduce an authored package name to the canonical form used in runtime names.\n *\n * Sanitizing rather than rejecting outright keeps a human-written `My Tools`\n * usable, while the pattern check afterwards still rejects anything that\n * sanitizes down to nothing meaningful.\n */\nfunction normalizePackageName(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n return trimmed\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9.-]/g, '')\n .replace(/-+/g, '-')\n .replace(/\\.+/g, '.')\n .replace(/(?:^[-.]+|[-.]+$)/g, '');\n}\n\n/** Validate a `package` frontmatter value. An absent or empty value is not an error. */\nexport function parsePackageName(value: unknown, label = 'package'): { packageName?: string; error?: string } {\n if (value === undefined || value === false || value === '') return { packageName: undefined };\n if (typeof value !== 'string') return { error: `${label} must be a string or false when provided.` };\n const packageName = normalizePackageName(value);\n if (!packageName || !IDENTIFIER_PATTERN.test(packageName)) {\n return { error: `${label} is invalid after sanitization.` };\n }\n return { packageName };\n}\n\n/** The name an agent is addressed by, qualified when it belongs to a package. */\nexport function buildRuntimeName(localName: string, packageName?: string): string {\n const trimmedPackage = packageName?.trim();\n return trimmedPackage ? `${trimmedPackage}${PACKAGE_NAME_SEPARATOR}${localName}` : localName;\n}\n\n// ============================================================================\n// Tool lists\n// ============================================================================\n\n/** Marks a tool that is reached through an MCP server rather than the host. */\nconst MCP_TOOL_PREFIX = 'mcp:';\n\n/**\n * Split an authored `tools` list into host tools and MCP tools.\n *\n * The two are separate fields on `AgentConfig` because they are enforced by\n * different layers, but a single flat list is what an author wants to write.\n */\nexport function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {\n const mcpDirectTools: string[] = [];\n const tools: string[] = [];\n for (const tool of rawTools ?? []) {\n if (tool.startsWith(MCP_TOOL_PREFIX)) {\n mcpDirectTools.push(tool.slice(MCP_TOOL_PREFIX.length));\n } else {\n tools.push(tool);\n }\n }\n return {\n // An empty `tools:` means \"no tools\", which is not the same as an absent key.\n ...(rawTools !== undefined ? { tools } : {}),\n ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n };\n}\n\n// ============================================================================\n// Directory walk\n// ============================================================================\n\nconst DISCOVERY_PRUNED_DIR_NAMES: ReadonlySet<string> = new Set(['.git', 'node_modules']);\nconst GIT_DIR_NAME = '.git';\nconst LEGACY_AGENTS_DIR_NAME = '.agents';\nconst LEGACY_SKILLS_DIR_NAME = 'skills';\nconst AGENT_FILE_EXTENSION = '.md';\nconst CHAIN_FILE_EXTENSION = '.chain.md';\n\nfunction isDirectory(target: string): boolean {\n try {\n return fs.statSync(target).isDirectory();\n } catch {\n // A missing or unreadable path is simply not a directory for our purposes.\n return false;\n }\n}\n\n/** A directory that owns its own agent configuration is a separate project. */\nfunction isDiscoveryNestedProjectRoot(dir: string): boolean {\n return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, LEGACY_AGENTS_DIR_NAME));\n}\n\n/**\n * Decide whether the walk should skip a subdirectory.\n *\n * A nested repository or nested project root is pruned because its agents\n * belong to that project, not to the one being scanned. The root itself is\n * exempt: scanning a project's own agent directory must not prune it.\n */\nfunction shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {\n if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;\n if (fs.existsSync(path.join(dir, GIT_DIR_NAME))) return true;\n return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);\n}\n\n/**\n * Collect matching files under `dir`, sorted so discovery order is stable.\n *\n * Symlinked entries are followed as files, because staging an agent by symlink\n * is a supported way to share one definition across projects.\n */\nexport function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {\n const files: string[] = [];\n if (!fs.existsSync(dir)) return files;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));\n } catch {\n // An unreadable directory yields nothing rather than failing the whole sweep.\n return files;\n }\n\n for (const entry of entries) {\n const filePath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {\n files.push(...listFilesRecursive(filePath, predicate, rootDir));\n }\n continue;\n }\n if (!entry.isFile() && !entry.isSymbolicLink()) continue;\n if (!predicate(entry.name)) continue;\n files.push(filePath);\n }\n return files;\n}\n\n/**\n * Recognise a file that lives under a legacy `.agents/skills/` directory.\n *\n * Those markdown files are skill documents, not agent definitions, and they\n * predate the split. They would otherwise be loaded as nameless agents.\n */\nfunction isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {\n const relative = path.relative(rootDir, filePath);\n const parts = relative.split(path.sep).map((part) => part.toLowerCase());\n if (path.basename(rootDir).toLowerCase() === LEGACY_AGENTS_DIR_NAME) {\n parts.unshift(LEGACY_AGENTS_DIR_NAME);\n }\n return parts.some((part, index) => part === LEGACY_AGENTS_DIR_NAME && parts[index + 1] === LEGACY_SKILLS_DIR_NAME);\n}\n\n// ============================================================================\n// Structured field parsing\n// ============================================================================\n\nfunction parseSystemPromptMode(raw: string | undefined, localName: string): SystemPromptMode {\n if (raw === 'replace' || raw === 'append') return raw;\n return defaultSystemPromptMode(localName);\n}\n\nfunction parseDefaultContext(raw: string | undefined): AgentDefaultContext | undefined {\n return raw === 'fork' || raw === 'fresh' ? raw : undefined;\n}\n\nfunction parseTimeoutMs(raw: string | undefined, localName: string): number | undefined {\n if (raw === undefined) return undefined;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);\n }\n return parsed;\n}\n\nfunction parseToolBudget(raw: string | undefined, localName: string): ToolBudgetConfig | undefined {\n if (raw === undefined || !raw.trim()) return undefined;\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);\n }\n // Field-level validation lives with the enforcement layer in the runs domain.\n return parsed as ToolBudgetConfig;\n}\n\n// ============================================================================\n// Loading\n// ============================================================================\n\n/** True for an agent definition file, false for a chain or anything else. */\nfunction isAgentFileName(fileName: string): boolean {\n return fileName.endsWith(AGENT_FILE_EXTENSION) && !fileName.endsWith(CHAIN_FILE_EXTENSION);\n}\n\n/**\n * Load every agent definition under `dir`.\n *\n * The returned configs carry only what the file itself declared. Settings\n * defaults, builtin overrides, and cross-source precedence are the caller's job.\n */\nexport function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {\n const agents: AgentConfig[] = [];\n\n for (const filePath of listFilesRecursive(dir, isAgentFileName)) {\n if (isLegacyAgentSkillPath(dir, filePath)) continue;\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch {\n // The file can be removed or replaced mid-sweep; skip it, do not abort.\n continue;\n }\n\n const { frontmatter, body } = parseFrontmatter(content);\n // Without both of these the file is documentation, not an agent.\n if (!frontmatter.name || !frontmatter.description) continue;\n\n const localName = frontmatter.name;\n const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);\n // An unusable package name would produce an unaddressable runtime name.\n if (parsedPackage.error) continue;\n\n const rawTools = parseFrontmatterList(frontmatter.tools);\n const { tools, mcpDirectTools } = splitToolList(rawTools);\n const skills = parseFrontmatterList(frontmatter.skill || frontmatter.skills);\n const skillPath = parseFrontmatterList(frontmatter.skillPath);\n const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);\n const defaultReads = parseFrontmatterList(frontmatter.defaultReads);\n const maxSubagentDepth = Number(frontmatter.maxSubagentDepth);\n\n const extraFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(frontmatter)) {\n if (!LOADER_KNOWN_FIELDS.has(key)) extraFields[key] = value;\n }\n\n const agent: AgentConfig = {\n name: buildRuntimeName(localName, parsedPackage.packageName),\n localName,\n packageName: parsedPackage.packageName,\n description: frontmatter.description,\n tools: rawTools !== undefined ? (tools ?? []) : undefined,\n mcpDirectTools: mcpDirectTools && mcpDirectTools.length > 0 ? mcpDirectTools : undefined,\n model: frontmatter.model,\n fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,\n thinking: frontmatter.thinking === FALSE_LITERAL ? false : frontmatter.thinking,\n systemPromptMode: parseSystemPromptMode(frontmatter.systemPromptMode, localName),\n inheritProjectContext:\n parseOptionalBoolean(frontmatter.inheritProjectContext) ?? defaultInheritProjectContext(localName),\n inheritSkills: parseOptionalBoolean(frontmatter.inheritSkills) ?? defaultInheritSkills(),\n defaultContext: parseDefaultContext(frontmatter.defaultContext),\n defaultTimeoutMs: parseTimeoutMs(frontmatter.timeoutMs, localName),\n systemPrompt: body,\n source,\n filePath,\n skills: skills && skills.length > 0 ? skills : undefined,\n skillPath: skillPath && skillPath.length > 0 ? skillPath : undefined,\n extensions: parseFrontmatterList(frontmatter.extensions),\n subagentOnlyExtensions: parseFrontmatterList(frontmatter.subagentOnlyExtensions),\n output: frontmatter.output,\n defaultReads: defaultReads && defaultReads.length > 0 ? defaultReads : undefined,\n defaultProgress: frontmatter.defaultProgress === TRUE_LITERAL,\n interactive: frontmatter.interactive === TRUE_LITERAL,\n maxSubagentDepth: Number.isInteger(maxSubagentDepth) && maxSubagentDepth >= 0 ? maxSubagentDepth : undefined,\n completionGuard: parseOptionalBoolean(frontmatter.completionGuard),\n toolBudget: parseToolBudget(frontmatter.toolBudget, localName),\n memory: parseMemoryFrontmatter(frontmatter.memory),\n extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,\n };\n // Record what the file actually declared, so a later settings pass can tell\n // an author's explicit value from one this loader defaulted in.\n setAgentFrontmatterFields(agent, new Set(Object.keys(frontmatter)));\n agents.push(agent);\n }\n\n return agents;\n}\n\n// ============================================================================\n// Plugin directories\n// ============================================================================\n\n/** Path-delimited list of read-only agent directories staged by the host. */\nexport const EXTRA_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\n\n/**\n * Read-only agent directories contributed by plugins.\n *\n * Read from the environment on every call rather than captured once, because a\n * host can stage a plugin directory after this module is first imported.\n */\nexport function pluginAgentDirs(): string[] {\n return (process.env[EXTRA_AGENT_DIRS_ENV] ?? '')\n .split(path.delimiter)\n .map((directory) => directory.trim())\n .filter((directory) => directory.length > 0);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loader.mjs","names":["fs","path"],"sources":["../../../../src/adapters/agents/loader.ts"],"sourcesContent":["/**\n * Reading agent definitions off disk into `AgentConfig` values.\n *\n * One markdown file is one agent: YAML frontmatter declares how the child run\n * should be shaped, and the body is its system prompt. This module owns the walk\n * that finds those files and the field-by-field interpretation of what it finds.\n * Precedence between sources, settings defaults, and builtin overrides are\n * applied by discovery afterwards, never here.\n *\n * DESIGN PATTERNS:\n * - A malformed value fails loudly, a malformed file is skipped quietly. A file\n * missing `name` or `description` is simply not an agent and must not stop the\n * sweep, but a `timeoutMs` of \"soon\" is an authoring mistake that has to\n * surface rather than be silently dropped\n * - Frontmatter keys this module does not interpret are copied into\n * `extraFields` verbatim, so a later writer can round-trip a file it did not\n * fully understand\n * - The directory walk prunes at project boundaries, so an agent directory that\n * happens to contain a checked-out sub-repository does not absorb its agents\n *\n * ASYNC-ONLY:\n * This package has no synchronous run mode, so the `async` frontmatter field is\n * not interpreted. It falls through into `extraFields` like any other key,\n * which keeps a definition written for the predecessor readable here.\n *\n * AVOID:\n * - Applying settings defaults or builtin overrides in this module\n * - Adding a field here without adding it to `LOADER_KNOWN_FIELDS`, which would\n * leak it into `extraFields` and get it written back twice\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getProjectConfigDir } from '../filesystem/configDir';\nimport type { SystemPromptMode, ToolBudgetConfig } from '../../types';\nimport { parseFrontmatter, parseFrontmatterList } from './frontmatter';\nimport { parseMemoryFrontmatter } from './memory';\nimport { setAgentFrontmatterFields } from './settings';\nimport type { AgentConfig, AgentDefaultContext, AgentSource } from './types';\n\n// ============================================================================\n// Builtin defaults\n// ============================================================================\n\n/**\n * The agents this package ships.\n *\n * Named here because a definition on disk with one of these names is an\n * override of a builtin rather than a new agent, and because their defaults\n * differ from a custom agent's.\n */\nexport const BUILTIN_AGENT_NAMES = [\n 'advisor',\n 'context-builder',\n 'delegate',\n 'oracle',\n 'planner',\n 'researcher',\n 'reviewer',\n 'scout',\n 'worker',\n] as const;\n\n/**\n * The one builtin that extends the host's context instead of replacing it.\n *\n * `delegate` exists to carry out work on the operator's behalf in the same\n * project, so it inherits the host system prompt and project context. Every\n * other agent starts clean, which is what makes its output reproducible.\n */\nconst CONTEXT_INHERITING_BUILTIN = 'delegate';\n\nexport function defaultSystemPromptMode(name: string): SystemPromptMode {\n return name === CONTEXT_INHERITING_BUILTIN ? 'append' : 'replace';\n}\n\nexport function defaultInheritProjectContext(name: string): boolean {\n return name === CONTEXT_INHERITING_BUILTIN;\n}\n\nexport function defaultInheritSkills(): boolean {\n return false;\n}\n\n// ============================================================================\n// Frontmatter vocabulary\n// ============================================================================\n\n/**\n * Every frontmatter key this module interprets.\n *\n * Anything absent from this set is preserved in `extraFields` instead. `async`\n * is deliberately absent: this package is async-only, so the key is data to\n * carry, not a setting to honour.\n */\nexport const LOADER_KNOWN_FIELDS: ReadonlySet<string> = new Set([\n 'name',\n 'package',\n 'description',\n 'tools',\n 'model',\n 'fallbackModels',\n 'thinking',\n 'systemPromptMode',\n 'inheritProjectContext',\n 'inheritSkills',\n 'defaultContext',\n 'timeoutMs',\n 'skill',\n 'skills',\n 'skillPath',\n 'extensions',\n 'subagentOnlyExtensions',\n 'output',\n 'defaultReads',\n 'defaultProgress',\n 'interactive',\n 'maxSubagentDepth',\n 'completionGuard',\n 'toolBudget',\n 'memory',\n]);\n\nconst TRUE_LITERAL = 'true';\nconst FALSE_LITERAL = 'false';\n\n/** Frontmatter carries strings, so a boolean field is a tri-state until parsed. */\nfunction parseOptionalBoolean(raw: string | undefined): boolean | undefined {\n if (raw === TRUE_LITERAL) return true;\n if (raw === FALSE_LITERAL) return false;\n return undefined;\n}\n\n// ============================================================================\n// Identity\n// ============================================================================\n\n/** A package-qualified agent name: dot-separated lowercase segments. */\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]*(?:\\.[a-z0-9][a-z0-9-]*)*$/;\nconst PACKAGE_NAME_SEPARATOR = '.';\n\n/**\n * Reduce an authored package name to the canonical form used in runtime names.\n *\n * Sanitizing rather than rejecting outright keeps a human-written `My Tools`\n * usable, while the pattern check afterwards still rejects anything that\n * sanitizes down to nothing meaningful.\n */\nfunction normalizePackageName(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n return trimmed\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9.-]/g, '')\n .replace(/-+/g, '-')\n .replace(/\\.+/g, '.')\n .replace(/(?:^[-.]+|[-.]+$)/g, '');\n}\n\n/** Validate a `package` frontmatter value. An absent or empty value is not an error. */\nexport function parsePackageName(value: unknown, label = 'package'): { packageName?: string; error?: string } {\n if (value === undefined || value === false || value === '') return { packageName: undefined };\n if (typeof value !== 'string') return { error: `${label} must be a string or false when provided.` };\n const packageName = normalizePackageName(value);\n if (!packageName || !IDENTIFIER_PATTERN.test(packageName)) {\n return { error: `${label} is invalid after sanitization.` };\n }\n return { packageName };\n}\n\n/** The name an agent is addressed by, qualified when it belongs to a package. */\nexport function buildRuntimeName(localName: string, packageName?: string): string {\n const trimmedPackage = packageName?.trim();\n return trimmedPackage ? `${trimmedPackage}${PACKAGE_NAME_SEPARATOR}${localName}` : localName;\n}\n\n// ============================================================================\n// Tool lists\n// ============================================================================\n\n/** Marks a tool that is reached through an MCP server rather than the host. */\nconst MCP_TOOL_PREFIX = 'mcp:';\n\n/**\n * Split an authored `tools` list into host tools and MCP tools.\n *\n * The two are separate fields on `AgentConfig` because they are enforced by\n * different layers, but a single flat list is what an author wants to write.\n */\nexport function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {\n const mcpDirectTools: string[] = [];\n const tools: string[] = [];\n for (const tool of rawTools ?? []) {\n if (tool.startsWith(MCP_TOOL_PREFIX)) {\n mcpDirectTools.push(tool.slice(MCP_TOOL_PREFIX.length));\n } else {\n tools.push(tool);\n }\n }\n return {\n // An empty `tools:` means \"no tools\", which is not the same as an absent key.\n ...(rawTools !== undefined ? { tools } : {}),\n ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n };\n}\n\n// ============================================================================\n// Directory walk\n// ============================================================================\n\nconst DISCOVERY_PRUNED_DIR_NAMES: ReadonlySet<string> = new Set(['.git', 'node_modules']);\nconst GIT_DIR_NAME = '.git';\nconst LEGACY_AGENTS_DIR_NAME = '.agents';\nconst LEGACY_SKILLS_DIR_NAME = 'skills';\nconst AGENT_FILE_EXTENSION = '.md';\nconst CHAIN_FILE_EXTENSION = '.chain.md';\n\nfunction isDirectory(target: string): boolean {\n try {\n return fs.statSync(target).isDirectory();\n } catch {\n // A missing or unreadable path is simply not a directory for our purposes.\n return false;\n }\n}\n\n/** A directory that owns its own agent configuration is a separate project. */\nfunction isDiscoveryNestedProjectRoot(dir: string): boolean {\n return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, LEGACY_AGENTS_DIR_NAME));\n}\n\n/**\n * Decide whether the walk should skip a subdirectory.\n *\n * A nested repository or nested project root is pruned because its agents\n * belong to that project, not to the one being scanned. The root itself is\n * exempt: scanning a project's own agent directory must not prune it.\n */\nfunction shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {\n if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;\n if (fs.existsSync(path.join(dir, GIT_DIR_NAME))) return true;\n return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);\n}\n\n/**\n * Collect matching files under `dir`, sorted so discovery order is stable.\n *\n * Symlinked entries are followed as files, because staging an agent by symlink\n * is a supported way to share one definition across projects.\n */\nexport function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {\n const files: string[] = [];\n if (!fs.existsSync(dir)) return files;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));\n } catch {\n // An unreadable directory yields nothing rather than failing the whole sweep.\n return files;\n }\n\n for (const entry of entries) {\n const filePath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {\n files.push(...listFilesRecursive(filePath, predicate, rootDir));\n }\n continue;\n }\n if (!entry.isFile() && !entry.isSymbolicLink()) continue;\n if (!predicate(entry.name)) continue;\n files.push(filePath);\n }\n return files;\n}\n\n/**\n * Recognise a file that lives under a legacy `.agents/skills/` directory.\n *\n * Those markdown files are skill documents, not agent definitions, and they\n * predate the split. They would otherwise be loaded as nameless agents.\n */\nfunction isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {\n const relative = path.relative(rootDir, filePath);\n const parts = relative.split(path.sep).map((part) => part.toLowerCase());\n if (path.basename(rootDir).toLowerCase() === LEGACY_AGENTS_DIR_NAME) {\n parts.unshift(LEGACY_AGENTS_DIR_NAME);\n }\n return parts.some((part, index) => part === LEGACY_AGENTS_DIR_NAME && parts[index + 1] === LEGACY_SKILLS_DIR_NAME);\n}\n\n// ============================================================================\n// Structured field parsing\n// ============================================================================\n\nfunction parseSystemPromptMode(raw: string | undefined, localName: string): SystemPromptMode {\n if (raw === 'replace' || raw === 'append') return raw;\n return defaultSystemPromptMode(localName);\n}\n\nfunction parseDefaultContext(raw: string | undefined): AgentDefaultContext | undefined {\n return raw === 'fork' || raw === 'fresh' ? raw : undefined;\n}\n\nfunction parseTimeoutMs(raw: string | undefined, localName: string): number | undefined {\n if (raw === undefined) return undefined;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);\n }\n return parsed;\n}\n\nfunction parseToolBudget(raw: string | undefined, localName: string): ToolBudgetConfig | undefined {\n if (raw === undefined || !raw.trim()) return undefined;\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);\n }\n // Field-level validation lives with the enforcement layer in the runs domain.\n return parsed as ToolBudgetConfig;\n}\n\n// ============================================================================\n// Loading\n// ============================================================================\n\n/** True for an agent definition file, false for a chain or anything else. */\nfunction isAgentFileName(fileName: string): boolean {\n return fileName.endsWith(AGENT_FILE_EXTENSION) && !fileName.endsWith(CHAIN_FILE_EXTENSION);\n}\n\n/**\n * Load every agent definition under `dir`.\n *\n * The returned configs carry only what the file itself declared. Settings\n * defaults, builtin overrides, and cross-source precedence are the caller's job.\n */\nexport function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {\n const agents: AgentConfig[] = [];\n\n for (const filePath of listFilesRecursive(dir, isAgentFileName)) {\n if (isLegacyAgentSkillPath(dir, filePath)) continue;\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch {\n // The file can be removed or replaced mid-sweep; skip it, do not abort.\n continue;\n }\n\n const { frontmatter, body } = parseFrontmatter(content);\n // Without both of these the file is documentation, not an agent.\n if (!frontmatter.name || !frontmatter.description) continue;\n\n const localName = frontmatter.name;\n const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);\n // An unusable package name would produce an unaddressable runtime name.\n if (parsedPackage.error) continue;\n\n const rawTools = parseFrontmatterList(frontmatter.tools);\n const { tools, mcpDirectTools } = splitToolList(rawTools);\n const skills = parseFrontmatterList(frontmatter.skill || frontmatter.skills);\n const skillPath = parseFrontmatterList(frontmatter.skillPath);\n const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);\n const defaultReads = parseFrontmatterList(frontmatter.defaultReads);\n const maxSubagentDepth = Number(frontmatter.maxSubagentDepth);\n\n const extraFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(frontmatter)) {\n if (!LOADER_KNOWN_FIELDS.has(key)) extraFields[key] = value;\n }\n\n const agent: AgentConfig = {\n name: buildRuntimeName(localName, parsedPackage.packageName),\n localName,\n packageName: parsedPackage.packageName,\n description: frontmatter.description,\n tools: rawTools !== undefined ? (tools ?? []) : undefined,\n mcpDirectTools: mcpDirectTools && mcpDirectTools.length > 0 ? mcpDirectTools : undefined,\n model: frontmatter.model,\n fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,\n thinking: frontmatter.thinking === FALSE_LITERAL ? false : frontmatter.thinking,\n systemPromptMode: parseSystemPromptMode(frontmatter.systemPromptMode, localName),\n inheritProjectContext:\n parseOptionalBoolean(frontmatter.inheritProjectContext) ?? defaultInheritProjectContext(localName),\n inheritSkills: parseOptionalBoolean(frontmatter.inheritSkills) ?? defaultInheritSkills(),\n defaultContext: parseDefaultContext(frontmatter.defaultContext),\n defaultTimeoutMs: parseTimeoutMs(frontmatter.timeoutMs, localName),\n systemPrompt: body,\n source,\n filePath,\n skills: skills && skills.length > 0 ? skills : undefined,\n skillPath: skillPath && skillPath.length > 0 ? skillPath : undefined,\n extensions: parseFrontmatterList(frontmatter.extensions),\n subagentOnlyExtensions: parseFrontmatterList(frontmatter.subagentOnlyExtensions),\n output: frontmatter.output,\n defaultReads: defaultReads && defaultReads.length > 0 ? defaultReads : undefined,\n defaultProgress: frontmatter.defaultProgress === TRUE_LITERAL,\n interactive: frontmatter.interactive === TRUE_LITERAL,\n maxSubagentDepth: Number.isInteger(maxSubagentDepth) && maxSubagentDepth >= 0 ? maxSubagentDepth : undefined,\n completionGuard: parseOptionalBoolean(frontmatter.completionGuard),\n toolBudget: parseToolBudget(frontmatter.toolBudget, localName),\n memory: parseMemoryFrontmatter(frontmatter.memory),\n extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,\n };\n // Record what the file actually declared, so a later settings pass can tell\n // an author's explicit value from one this loader defaulted in.\n setAgentFrontmatterFields(agent, new Set(Object.keys(frontmatter)));\n agents.push(agent);\n }\n\n return agents;\n}\n\n// ============================================================================\n// Plugin directories\n// ============================================================================\n\n/** Path-delimited list of read-only agent directories staged by the host. */\nexport const EXTRA_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\n\n/**\n * Read-only agent directories contributed by plugins.\n *\n * Read from the environment on every call rather than captured once, because a\n * host can stage a plugin directory after this module is first imported.\n */\nexport function pluginAgentDirs(): string[] {\n return (process.env[EXTRA_AGENT_DIRS_ENV] ?? '')\n .split(path.delimiter)\n .map((directory) => directory.trim())\n .filter((directory) => directory.length > 0);\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
const e=require("../../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);const r=new Set([`edit`,`write`,`bash`]);function i(e){let t=e.trim();return t.startsWith(`"`)&&t.endsWith(`"`)||t.startsWith(`'`)&&t.endsWith(`'`)?t.slice(1,-1):t}function a(e){return e===`project`||e===`user`?e:void 0}function o(e){if(e===`true`)return!0;if(e===`false`)return!1}function s(e){if(e===void 0)return;let t=Number(e);return Number.isInteger(t)&&t>0?t:void 0}function c(e){let t=new Map,n=e.trim().match(/^\{(.*)\}$/s),r=n?.[1]===void 0?e.split(`
|
|
2
|
-
`):n[1].split(`,`);for(let e of r){let n=e.trim().match(/^([\w-]+)\s*:\s*(.*)$/)
|
|
2
|
+
`):n[1].split(`,`);for(let e of r){let n=e.trim().match(/^([\w-]+)\s*:\s*(.*)$/);n?.[1]&&n[2]!==void 0&&t.set(n[1],i(n[2]))}return t}function l(e){if(!e)return;let t=c(e),n=o(t.get(`enabled`)),r=a(t.get(`scope`)),i=s(t.get(`maxEntries`));if(n===void 0&&r===void 0&&i===void 0)return;let l={};return n!==void 0&&(l.enabled=n),r!==void 0&&(l.scope=r),i!==void 0&&(l.maxEntries=i),l}function u(e){let t=e.tools;return!t||t.some(e=>r.has(e))}exports.agentHasWriteTools=u,exports.parseMemoryFrontmatter=l;
|
|
3
3
|
//# sourceMappingURL=memory.cjs.map
|