@agimon-ai/doompi-domain 0.0.1-alpha.2
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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/adapters/applyDomains.cjs +2 -0
- package/dist/adapters/applyDomains.cjs.map +1 -0
- package/dist/adapters/applyDomains.d.cts +24 -0
- package/dist/adapters/applyDomains.d.cts.map +1 -0
- package/dist/adapters/applyDomains.d.mts +24 -0
- package/dist/adapters/applyDomains.d.mts.map +1 -0
- package/dist/adapters/applyDomains.mjs +2 -0
- package/dist/adapters/applyDomains.mjs.map +1 -0
- package/dist/adapters/domainCatalog.cjs +2 -0
- package/dist/adapters/domainCatalog.cjs.map +1 -0
- package/dist/adapters/domainCatalog.d.cts +20 -0
- package/dist/adapters/domainCatalog.d.cts.map +1 -0
- package/dist/adapters/domainCatalog.d.mts +20 -0
- package/dist/adapters/domainCatalog.d.mts.map +1 -0
- package/dist/adapters/domainCatalog.mjs +2 -0
- package/dist/adapters/domainCatalog.mjs.map +1 -0
- package/dist/adapters/domainSwitchHandoff.cjs +2 -0
- package/dist/adapters/domainSwitchHandoff.cjs.map +1 -0
- package/dist/adapters/domainSwitchHandoff.d.cts +10 -0
- package/dist/adapters/domainSwitchHandoff.d.cts.map +1 -0
- package/dist/adapters/domainSwitchHandoff.d.mts +10 -0
- package/dist/adapters/domainSwitchHandoff.d.mts.map +1 -0
- package/dist/adapters/domainSwitchHandoff.mjs +2 -0
- package/dist/adapters/domainSwitchHandoff.mjs.map +1 -0
- package/dist/adapters/mcpFilter.cjs +3 -0
- package/dist/adapters/mcpFilter.cjs.map +1 -0
- package/dist/adapters/mcpFilter.d.cts +39 -0
- package/dist/adapters/mcpFilter.d.cts.map +1 -0
- package/dist/adapters/mcpFilter.d.mts +39 -0
- package/dist/adapters/mcpFilter.d.mts.map +1 -0
- package/dist/adapters/mcpFilter.mjs +3 -0
- package/dist/adapters/mcpFilter.mjs.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.cjs +2 -0
- package/dist/adapters/mcpSessionEnvironment.cjs.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.d.cts +14 -0
- package/dist/adapters/mcpSessionEnvironment.d.cts.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.d.mts +14 -0
- package/dist/adapters/mcpSessionEnvironment.d.mts.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.mjs +2 -0
- package/dist/adapters/mcpSessionEnvironment.mjs.map +1 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/pi/extension.d.cts +13 -0
- package/dist/adapters/pi/extension.d.cts.map +1 -0
- package/dist/adapters/pi/extension.d.mts +13 -0
- package/dist/adapters/pi/extension.d.mts.map +1 -0
- package/dist/adapters/pi/extension.mjs +2 -0
- package/dist/adapters/pi/extension.mjs.map +1 -0
- package/dist/adapters/pi/voiceTool.cjs +2 -0
- package/dist/adapters/pi/voiceTool.cjs.map +1 -0
- package/dist/adapters/pi/voiceTool.d.cts +16 -0
- package/dist/adapters/pi/voiceTool.d.cts.map +1 -0
- package/dist/adapters/pi/voiceTool.d.mts +16 -0
- package/dist/adapters/pi/voiceTool.d.mts.map +1 -0
- package/dist/adapters/pi/voiceTool.mjs +2 -0
- package/dist/adapters/pi/voiceTool.mjs.map +1 -0
- package/dist/adapters/pluginMaterializer.cjs +2 -0
- package/dist/adapters/pluginMaterializer.cjs.map +1 -0
- package/dist/adapters/pluginMaterializer.d.cts +14 -0
- package/dist/adapters/pluginMaterializer.d.cts.map +1 -0
- package/dist/adapters/pluginMaterializer.d.mts +14 -0
- package/dist/adapters/pluginMaterializer.d.mts.map +1 -0
- package/dist/adapters/pluginMaterializer.mjs +2 -0
- package/dist/adapters/pluginMaterializer.mjs.map +1 -0
- package/dist/adapters/resourceCollector.cjs +3 -0
- package/dist/adapters/resourceCollector.cjs.map +1 -0
- package/dist/adapters/resourceCollector.d.cts +25 -0
- package/dist/adapters/resourceCollector.d.cts.map +1 -0
- package/dist/adapters/resourceCollector.d.mts +25 -0
- package/dist/adapters/resourceCollector.d.mts.map +1 -0
- package/dist/adapters/resourceCollector.mjs +3 -0
- package/dist/adapters/resourceCollector.mjs.map +1 -0
- package/dist/adapters/skillCacheLocation.cjs +2 -0
- package/dist/adapters/skillCacheLocation.cjs.map +1 -0
- package/dist/adapters/skillCacheLocation.d.cts +16 -0
- package/dist/adapters/skillCacheLocation.d.cts.map +1 -0
- package/dist/adapters/skillCacheLocation.d.mts +16 -0
- package/dist/adapters/skillCacheLocation.d.mts.map +1 -0
- package/dist/adapters/skillCacheLocation.mjs +2 -0
- package/dist/adapters/skillCacheLocation.mjs.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.cjs +2 -0
- package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts +14 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts +14 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.mjs +2 -0
- package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +1 -0
- package/dist/apply.cjs +1 -0
- package/dist/apply.d.cts +2 -0
- package/dist/apply.d.mts +2 -0
- package/dist/apply.mjs +1 -0
- package/dist/commands/domainsCommand.cjs +2 -0
- package/dist/commands/domainsCommand.cjs.map +1 -0
- package/dist/commands/domainsCommand.d.cts +24 -0
- package/dist/commands/domainsCommand.d.cts.map +1 -0
- package/dist/commands/domainsCommand.d.mts +24 -0
- package/dist/commands/domainsCommand.d.mts.map +1 -0
- package/dist/commands/domainsCommand.mjs +2 -0
- package/dist/commands/domainsCommand.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.mjs +1 -0
- package/dist/mcp.cjs +1 -0
- package/dist/mcp.d.cts +3 -0
- package/dist/mcp.d.mts +3 -0
- package/dist/mcp.mjs +1 -0
- package/dist/plugins.cjs +1 -0
- package/dist/plugins.d.cts +2 -0
- package/dist/plugins.d.mts +2 -0
- package/dist/plugins.mjs +1 -0
- package/dist/resources.cjs +1 -0
- package/dist/resources.d.cts +4 -0
- package/dist/resources.d.mts +4 -0
- package/dist/resources.mjs +1 -0
- package/dist/schemas/domainVoiceTools.cjs +2 -0
- package/dist/schemas/domainVoiceTools.cjs.map +1 -0
- package/dist/schemas/domainVoiceTools.d.cts +22 -0
- package/dist/schemas/domainVoiceTools.d.cts.map +1 -0
- package/dist/schemas/domainVoiceTools.d.mts +22 -0
- package/dist/schemas/domainVoiceTools.d.mts.map +1 -0
- package/dist/schemas/domainVoiceTools.mjs +2 -0
- package/dist/schemas/domainVoiceTools.mjs.map +1 -0
- package/dist/services/domainText.cjs +2 -0
- package/dist/services/domainText.cjs.map +1 -0
- package/dist/services/domainText.d.cts +30 -0
- package/dist/services/domainText.d.cts.map +1 -0
- package/dist/services/domainText.d.mts +30 -0
- package/dist/services/domainText.d.mts.map +1 -0
- package/dist/services/domainText.mjs +2 -0
- package/dist/services/domainText.mjs.map +1 -0
- package/dist/services/toolNames.cjs +2 -0
- package/dist/services/toolNames.cjs.map +1 -0
- package/dist/services/toolNames.d.cts +21 -0
- package/dist/services/toolNames.d.cts.map +1 -0
- package/dist/services/toolNames.d.mts +21 -0
- package/dist/services/toolNames.d.mts.map +1 -0
- package/dist/services/toolNames.mjs +2 -0
- package/dist/services/toolNames.mjs.map +1 -0
- package/dist/types/domains.cjs +2 -0
- package/dist/types/domains.cjs.map +1 -0
- package/dist/types/domains.d.cts +33 -0
- package/dist/types/domains.d.cts.map +1 -0
- package/dist/types/domains.d.mts +33 -0
- package/dist/types/domains.d.mts.map +1 -0
- package/dist/types/domains.mjs +2 -0
- package/dist/types/domains.mjs.map +1 -0
- package/dist/types/handoff.d.cts +35 -0
- package/dist/types/handoff.d.cts.map +1 -0
- package/dist/types/handoff.d.mts +35 -0
- package/dist/types/handoff.d.mts.map +1 -0
- package/dist/types/resources.d.cts +46 -0
- package/dist/types/resources.d.cts.map +1 -0
- package/dist/types/resources.d.mts +46 -0
- package/dist/types/resources.d.mts.map +1 -0
- package/dist/types/telemetry.cjs +2 -0
- package/dist/types/telemetry.cjs.map +1 -0
- package/dist/types/telemetry.d.cts +15 -0
- package/dist/types/telemetry.d.cts.map +1 -0
- package/dist/types/telemetry.d.mts +15 -0
- package/dist/types/telemetry.d.mts.map +1 -0
- package/dist/types/telemetry.mjs +2 -0
- package/dist/types/telemetry.mjs.map +1 -0
- package/llms.txt +7 -0
- package/package.json +117 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{sessionConfigEnvironment as e}from"@agimon-ai/doompi-mcp";function t(t){let n={repoRoot:t.repoRoot,stagingDirectory:t.stagingDirectory,...t.generatedConfigPath?{generatedConfigPath:t.generatedConfigPath}:{},...t.pluginConfigPaths?.length?{pluginConfigPaths:[...t.pluginConfigPaths]}:{},...t.allowlist?{allowlist:structuredClone(t.allowlist)}:{}};return e(n)}export{t as mcpSessionEnvironment};
|
|
2
|
+
//# sourceMappingURL=mcpSessionEnvironment.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpSessionEnvironment.mjs","names":[],"sources":["../../src/adapters/mcpSessionEnvironment.ts"],"sourcesContent":["import { type McpAllowlist, type McpSessionConfig, sessionConfigEnvironment } from '@agimon-ai/doompi-mcp';\n\nexport interface McpSessionEnvironmentInput {\n readonly repoRoot: string;\n readonly stagingDirectory: string;\n readonly generatedConfigPath?: string;\n readonly pluginConfigPaths?: readonly string[];\n readonly allowlist?: McpAllowlist;\n}\n\n/** Projects the complete domain-selected MCP picture into the Pi session environment. */\nexport function mcpSessionEnvironment(input: McpSessionEnvironmentInput): Record<string, string> {\n const configuration: McpSessionConfig = {\n repoRoot: input.repoRoot,\n stagingDirectory: input.stagingDirectory,\n ...(input.generatedConfigPath ? { generatedConfigPath: input.generatedConfigPath } : {}),\n ...(input.pluginConfigPaths?.length ? { pluginConfigPaths: [...input.pluginConfigPaths] } : {}),\n ...(input.allowlist ? { allowlist: structuredClone(input.allowlist) } : {}),\n };\n return sessionConfigEnvironment(configuration);\n}\n"],"mappings":"iEAWA,SAAgB,EAAsB,EAA2D,CAC/F,IAAM,EAAkC,CACtC,SAAU,EAAM,SAChB,iBAAkB,EAAM,iBACxB,GAAI,EAAM,oBAAsB,CAAE,oBAAqB,EAAM,mBAAoB,EAAI,CAAC,EACtF,GAAI,EAAM,mBAAmB,OAAS,CAAE,kBAAmB,CAAC,GAAG,EAAM,iBAAiB,CAAE,EAAI,CAAC,EAC7F,GAAI,EAAM,UAAY,CAAE,UAAW,gBAAgB,EAAM,SAAS,CAAE,EAAI,CAAC,CAC3E,EACA,OAAO,EAAyB,CAAa,CAC/C"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../types/domains.cjs"),t=require("../domainCatalog.cjs"),n=require("../domainSwitchHandoff.cjs"),r=require("../../commands/domainsCommand.cjs"),i=require("../telemetry/logSinkTelemetry.cjs"),a=require("./voiceTool.cjs");let o=require("@agimon-ai/doompi-config/piContext"),s=require("@deepseek-ai/cordis");function c(){let e,t,n;return{apply:()=>e??=Promise.resolve().then(()=>require("../applyDomains.cjs")),journal:()=>t??=import(`@agimon-ai/doompi-config/piContext`),picker:()=>n??=import(`@agimon-ai/doompi-ui/components/matrixPicker`)}}async function l(l,u=i.createDomainTelemetry()){let d=new s.Context,f=c(),p=t.createDomainCatalog(),m=n.createDomainSwitchHandoffStore(),h,g=()=>(h??=d.fiber.dispose(),h);try{d.effect(function*(){a.registerDomainVoiceCapabilities(l,p,m),r.registerDomainsCommand(l,u,{catalog:p,handoffs:m,applyDomains:async(e,t)=>(await f.apply()).applyDomains(e,t),loadConfigJournal:f.journal,loadPicker:f.picker}),l.on(`resources_discover`,(e,t)=>({skillPaths:[...(0,o.requireDoomConfigContext)(t).harness.skillDirectories]})),l.on(`session_shutdown`,(e,t)=>{m.clearSession(t.sessionManager.getSessionId())}),l.on(`session_start`,(e,t)=>{let n=(0,o.requireDoomConfigContext)(t).harness;t.ui.addAutocompleteProvider(e=>({triggerCharacters:[`,`],async getSuggestions(t,r,i,a){let o=n.root,s=t[r]??``;return(o?await p.completions(o,s.slice(0,i)):void 0)??e.getSuggestions(t,r,i,a)},applyCompletion(t,n,r,i,a){return e.applyCompletion(t,n,r,i,a)},shouldTriggerFileCompletion(t,n,r){return e.shouldTriggerFileCompletion?.(t,n,r)??!0}}))}),yield()=>{m.dispose()}},e.DOMAIN_SOURCE)}catch(e){throw await g(),e}l.on(`session_shutdown`,g)}exports.default=l,exports.domainsExtension=l;
|
|
2
|
+
//# sourceMappingURL=extension.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["createDomainTelemetry","Context","createDomainCatalog","createDomainSwitchHandoffStore","requireDoomConfigContext","DOMAIN_SOURCE"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerDomainsCommand } from '../../commands/domainsCommand.ts';\nimport { DOMAIN_SOURCE } from '../../types/domains.ts';\nimport type { DomainTelemetry } from '../../types/telemetry.ts';\nimport { createDomainCatalog } from '../domainCatalog.ts';\nimport { createDomainSwitchHandoffStore } from '../domainSwitchHandoff.ts';\nimport { createDomainTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { registerDomainVoiceCapabilities } from './voiceTool.ts';\n\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/**\n * Everything a switch needs beyond the session, loaded on first use.\n *\n * Every session registers /domains, but most never run it, so the plugin\n * materializer, the resource collector and the picker stay off the startup path.\n */\nfunction lazyModules() {\n let apply: Promise<typeof import('../applyDomains.ts')> | undefined;\n let journal: Promise<typeof import('@agimon-ai/doompi-config/piContext')> | undefined;\n let picker: Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')> | undefined;\n return {\n apply: () => (apply ??= import('../applyDomains.ts')),\n journal: () => (journal ??= import('@agimon-ai/doompi-config/piContext')),\n picker: () => (picker ??= import('@agimon-ai/doompi-ui/components/matrixPicker')),\n };\n}\n\n/**\n * The package's single standard Pi factory, and the owner of the cordis Context.\n *\n * Pi can reload an extension in-process, so every registration is yielded to the\n * fiber and one dispose on session shutdown unwinds them in reverse.\n */\nexport async function domainsExtension(\n pi: ExtensionAPI,\n telemetry: DomainTelemetry = createDomainTelemetry(),\n): Promise<void> {\n const cordis = new Context();\n const load = lazyModules();\n const catalog = createDomainCatalog();\n const handoffs = createDomainSwitchHandoffStore();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n cordis.effect(function* () {\n registerDomainVoiceCapabilities(pi, catalog, handoffs);\n registerDomainsCommand(pi, telemetry, {\n catalog,\n handoffs,\n applyDomains: async (domains, state) => (await load.apply()).applyDomains(domains, state),\n loadConfigJournal: load.journal,\n loadPicker: load.picker,\n });\n\n // Pi reloads base resources, then asks extensions to extend them again.\n // Read the rebound context so a domain switch discovers only the new\n // selection.\n pi.on('resources_discover', (_event, ctx) => ({\n skillPaths: [...requireDoomConfigContext(ctx).harness.skillDirectories],\n }));\n\n pi.on('session_shutdown', (_event, ctx) => {\n handoffs.clearSession(ctx.sessionManager.getSessionId());\n });\n\n pi.on('session_start', (_event, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n ctx.ui.addAutocompleteProvider((current) => ({\n triggerCharacters: [','],\n async getSuggestions(lines, cursorLine, cursorCol, options) {\n const repoRoot = state.root;\n const line = lines[cursorLine] ?? '';\n const completion = repoRoot ? await catalog.completions(repoRoot, line.slice(0, cursorCol)) : undefined;\n return completion ?? current.getSuggestions(lines, cursorLine, cursorCol, options);\n },\n applyCompletion(lines, cursorLine, cursorCol, item, prefix) {\n return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);\n },\n shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {\n return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;\n },\n }));\n });\n\n // Pi owns command and hook deregistration across a reload, so the fiber\n // only has to drop the handoffs this package parked for the session.\n yield () => {\n handoffs.dispose();\n };\n }, DOMAIN_SOURCE);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default domainsExtension;\n"],"mappings":"qUAmBA,SAAS,GAAc,CACrB,IAAI,EACA,EACA,EACJ,MAAO,CACL,UAAc,IAAA,QAAA,QAAA,CAAA,CAAA,SAAA,QAAU,qBAAA,CAAA,EACxB,YAAgB,IAAY,OAAO,sCACnC,WAAe,IAAW,OAAO,+CACnC,CACF,CAQA,eAAsB,EACpB,EACA,EAA6BA,EAAAA,sBAAsB,EACpC,CACf,IAAM,EAAS,IAAIC,EAAAA,QACb,EAAO,EAAY,EACnB,EAAUC,EAAAA,oBAAoB,EAC9B,EAAWC,EAAAA,+BAA+B,EAC5C,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAO,OAAO,WAAa,CACzB,EAAA,gCAAgC,EAAI,EAAS,CAAQ,EACrD,EAAA,uBAAuB,EAAI,EAAW,CACpC,UACA,WACA,aAAc,MAAO,EAAS,KAAW,MAAM,EAAK,MAAM,EAAA,CAAG,aAAa,EAAS,CAAK,EACxF,kBAAmB,EAAK,QACxB,WAAY,EAAK,MACnB,CAAC,EAKD,EAAG,GAAG,sBAAuB,EAAQ,KAAS,CAC5C,WAAY,CAAC,IAAA,EAAGC,EAAAA,yBAAAA,CAAyB,CAAG,CAAC,CAAC,QAAQ,gBAAgB,CACxE,EAAE,EAEF,EAAG,GAAG,oBAAqB,EAAQ,IAAQ,CACzC,EAAS,aAAa,EAAI,eAAe,aAAa,CAAC,CACzD,CAAC,EAED,EAAG,GAAG,iBAAkB,EAAQ,IAAQ,CACtC,IAAM,GAAA,EAAQA,EAAAA,yBAAAA,CAAyB,CAAG,CAAC,CAAC,QAC5C,EAAI,GAAG,wBAAyB,IAAa,CAC3C,kBAAmB,CAAC,GAAG,EACvB,MAAM,eAAe,EAAO,EAAY,EAAW,EAAS,CAC1D,IAAM,EAAW,EAAM,KACjB,EAAO,EAAM,IAAe,GAElC,OADmB,EAAW,MAAM,EAAQ,YAAY,EAAU,EAAK,MAAM,EAAG,CAAS,CAAC,EAAI,IAAA,KACzE,EAAQ,eAAe,EAAO,EAAY,EAAW,CAAO,CACnF,EACA,gBAAgB,EAAO,EAAY,EAAW,EAAM,EAAQ,CAC1D,OAAO,EAAQ,gBAAgB,EAAO,EAAY,EAAW,EAAM,CAAM,CAC3E,EACA,4BAA4B,EAAO,EAAY,EAAW,CACxD,OAAO,EAAQ,8BAA8B,EAAO,EAAY,CAAS,GAAK,EAChF,CACF,EAAE,CACJ,CAAC,EAID,SAAY,CACV,EAAS,QAAQ,CACnB,CACF,EAAGC,EAAAA,aAAa,CAClB,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAwB,CAAO,CACvC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../../types/telemetry.cjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The package's single standard Pi factory, and the owner of the cordis Context.
|
|
6
|
+
*
|
|
7
|
+
* Pi can reload an extension in-process, so every registration is yielded to the
|
|
8
|
+
* fiber and one dispose on session shutdown unwinds them in reverse.
|
|
9
|
+
*/
|
|
10
|
+
declare function domainsExtension(pi: ExtensionAPI, telemetry?: DomainTelemetry): Promise<void>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { domainsExtension as default, domainsExtension };
|
|
13
|
+
//# sourceMappingURL=extension.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;;iBAoCsB,iBACpB,IAAI,cACJ,YAAW,kBACV"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../../types/telemetry.mjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The package's single standard Pi factory, and the owner of the cordis Context.
|
|
6
|
+
*
|
|
7
|
+
* Pi can reload an extension in-process, so every registration is yielded to the
|
|
8
|
+
* fiber and one dispose on session shutdown unwinds them in reverse.
|
|
9
|
+
*/
|
|
10
|
+
declare function domainsExtension(pi: ExtensionAPI, telemetry?: DomainTelemetry): Promise<void>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { domainsExtension as default, domainsExtension };
|
|
13
|
+
//# sourceMappingURL=extension.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;;iBAoCsB,iBACpB,IAAI,cACJ,YAAW,kBACV"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{DOMAIN_SOURCE as e}from"../../types/domains.mjs";import{createDomainCatalog as t}from"../domainCatalog.mjs";import{createDomainSwitchHandoffStore as n}from"../domainSwitchHandoff.mjs";import{registerDomainsCommand as r}from"../../commands/domainsCommand.mjs";import{createDomainTelemetry as i}from"../telemetry/logSinkTelemetry.mjs";import{registerDomainVoiceCapabilities as a}from"./voiceTool.mjs";import{requireDoomConfigContext as o}from"@agimon-ai/doompi-config/piContext";import{Context as s}from"@deepseek-ai/cordis";function c(){let e,t,n;return{apply:()=>e??=import(`../applyDomains.mjs`),journal:()=>t??=import(`@agimon-ai/doompi-config/piContext`),picker:()=>n??=import(`@agimon-ai/doompi-ui/components/matrixPicker`)}}async function l(l,u=i()){let d=new s,f=c(),p=t(),m=n(),h,g=()=>(h??=d.fiber.dispose(),h);try{d.effect(function*(){a(l,p,m),r(l,u,{catalog:p,handoffs:m,applyDomains:async(e,t)=>(await f.apply()).applyDomains(e,t),loadConfigJournal:f.journal,loadPicker:f.picker}),l.on(`resources_discover`,(e,t)=>({skillPaths:[...o(t).harness.skillDirectories]})),l.on(`session_shutdown`,(e,t)=>{m.clearSession(t.sessionManager.getSessionId())}),l.on(`session_start`,(e,t)=>{let n=o(t).harness;t.ui.addAutocompleteProvider(e=>({triggerCharacters:[`,`],async getSuggestions(t,r,i,a){let o=n.root,s=t[r]??``;return(o?await p.completions(o,s.slice(0,i)):void 0)??e.getSuggestions(t,r,i,a)},applyCompletion(t,n,r,i,a){return e.applyCompletion(t,n,r,i,a)},shouldTriggerFileCompletion(t,n,r){return e.shouldTriggerFileCompletion?.(t,n,r)??!0}}))}),yield()=>{m.dispose()}},e)}catch(e){throw await g(),e}l.on(`session_shutdown`,g)}export{l as default,l as domainsExtension};
|
|
2
|
+
//# sourceMappingURL=extension.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerDomainsCommand } from '../../commands/domainsCommand.ts';\nimport { DOMAIN_SOURCE } from '../../types/domains.ts';\nimport type { DomainTelemetry } from '../../types/telemetry.ts';\nimport { createDomainCatalog } from '../domainCatalog.ts';\nimport { createDomainSwitchHandoffStore } from '../domainSwitchHandoff.ts';\nimport { createDomainTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { registerDomainVoiceCapabilities } from './voiceTool.ts';\n\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/**\n * Everything a switch needs beyond the session, loaded on first use.\n *\n * Every session registers /domains, but most never run it, so the plugin\n * materializer, the resource collector and the picker stay off the startup path.\n */\nfunction lazyModules() {\n let apply: Promise<typeof import('../applyDomains.ts')> | undefined;\n let journal: Promise<typeof import('@agimon-ai/doompi-config/piContext')> | undefined;\n let picker: Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')> | undefined;\n return {\n apply: () => (apply ??= import('../applyDomains.ts')),\n journal: () => (journal ??= import('@agimon-ai/doompi-config/piContext')),\n picker: () => (picker ??= import('@agimon-ai/doompi-ui/components/matrixPicker')),\n };\n}\n\n/**\n * The package's single standard Pi factory, and the owner of the cordis Context.\n *\n * Pi can reload an extension in-process, so every registration is yielded to the\n * fiber and one dispose on session shutdown unwinds them in reverse.\n */\nexport async function domainsExtension(\n pi: ExtensionAPI,\n telemetry: DomainTelemetry = createDomainTelemetry(),\n): Promise<void> {\n const cordis = new Context();\n const load = lazyModules();\n const catalog = createDomainCatalog();\n const handoffs = createDomainSwitchHandoffStore();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n cordis.effect(function* () {\n registerDomainVoiceCapabilities(pi, catalog, handoffs);\n registerDomainsCommand(pi, telemetry, {\n catalog,\n handoffs,\n applyDomains: async (domains, state) => (await load.apply()).applyDomains(domains, state),\n loadConfigJournal: load.journal,\n loadPicker: load.picker,\n });\n\n // Pi reloads base resources, then asks extensions to extend them again.\n // Read the rebound context so a domain switch discovers only the new\n // selection.\n pi.on('resources_discover', (_event, ctx) => ({\n skillPaths: [...requireDoomConfigContext(ctx).harness.skillDirectories],\n }));\n\n pi.on('session_shutdown', (_event, ctx) => {\n handoffs.clearSession(ctx.sessionManager.getSessionId());\n });\n\n pi.on('session_start', (_event, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n ctx.ui.addAutocompleteProvider((current) => ({\n triggerCharacters: [','],\n async getSuggestions(lines, cursorLine, cursorCol, options) {\n const repoRoot = state.root;\n const line = lines[cursorLine] ?? '';\n const completion = repoRoot ? await catalog.completions(repoRoot, line.slice(0, cursorCol)) : undefined;\n return completion ?? current.getSuggestions(lines, cursorLine, cursorCol, options);\n },\n applyCompletion(lines, cursorLine, cursorCol, item, prefix) {\n return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);\n },\n shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {\n return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;\n },\n }));\n });\n\n // Pi owns command and hook deregistration across a reload, so the fiber\n // only has to drop the handoffs this package parked for the session.\n yield () => {\n handoffs.dispose();\n };\n }, DOMAIN_SOURCE);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default domainsExtension;\n"],"mappings":"khBAmBA,SAAS,GAAc,CACrB,IAAI,EACA,EACA,EACJ,MAAO,CACL,UAAc,IAAU,OAAO,uBAC/B,YAAgB,IAAY,OAAO,sCACnC,WAAe,IAAW,OAAO,+CACnC,CACF,CAQA,eAAsB,EACpB,EACA,EAA6B,EAAsB,EACpC,CACf,IAAM,EAAS,IAAI,EACb,EAAO,EAAY,EACnB,EAAU,EAAoB,EAC9B,EAAW,EAA+B,EAC5C,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAO,OAAO,WAAa,CACzB,EAAgC,EAAI,EAAS,CAAQ,EACrD,EAAuB,EAAI,EAAW,CACpC,UACA,WACA,aAAc,MAAO,EAAS,KAAW,MAAM,EAAK,MAAM,EAAA,CAAG,aAAa,EAAS,CAAK,EACxF,kBAAmB,EAAK,QACxB,WAAY,EAAK,MACnB,CAAC,EAKD,EAAG,GAAG,sBAAuB,EAAQ,KAAS,CAC5C,WAAY,CAAC,GAAG,EAAyB,CAAG,CAAC,CAAC,QAAQ,gBAAgB,CACxE,EAAE,EAEF,EAAG,GAAG,oBAAqB,EAAQ,IAAQ,CACzC,EAAS,aAAa,EAAI,eAAe,aAAa,CAAC,CACzD,CAAC,EAED,EAAG,GAAG,iBAAkB,EAAQ,IAAQ,CACtC,IAAM,EAAQ,EAAyB,CAAG,CAAC,CAAC,QAC5C,EAAI,GAAG,wBAAyB,IAAa,CAC3C,kBAAmB,CAAC,GAAG,EACvB,MAAM,eAAe,EAAO,EAAY,EAAW,EAAS,CAC1D,IAAM,EAAW,EAAM,KACjB,EAAO,EAAM,IAAe,GAElC,OADmB,EAAW,MAAM,EAAQ,YAAY,EAAU,EAAK,MAAM,EAAG,CAAS,CAAC,EAAI,IAAA,KACzE,EAAQ,eAAe,EAAO,EAAY,EAAW,CAAO,CACnF,EACA,gBAAgB,EAAO,EAAY,EAAW,EAAM,EAAQ,CAC1D,OAAO,EAAQ,gBAAgB,EAAO,EAAY,EAAW,EAAM,CAAM,CAC3E,EACA,4BAA4B,EAAO,EAAY,EAAW,CACxD,OAAO,EAAQ,8BAA8B,EAAO,EAAY,CAAS,GAAK,EAChF,CACF,EAAE,CACJ,CAAC,EAID,SAAY,CACV,EAAS,QAAQ,CACnB,CACF,EAAG,CAAa,CAClB,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAwB,CAAO,CACvC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../types/domains.cjs"),t=require("../../services/domainText.cjs"),n=require("../../schemas/domainVoiceTools.cjs");let r=require("@agimon-ai/doompi-extension-contracts/voice-tools"),i=require("@agimon-ai/doompi-extension-contracts/transition");function a(a,o,s){let c=a;(0,r.registerVoiceToolContribution)(c,{descriptor:{source:e.DOMAIN_SOURCE,id:`domains-list`,name:`list_domains`,label:`List domains`,description:`List active, effective, and available Doom domains.`,order:100,inputSchema:n.EMPTY_DOMAIN_INPUT_SCHEMA,resultSchema:n.LIST_DOMAINS_RESULT_SCHEMA},execute:async(e,t)=>o.list(t.context)}),(0,r.registerVoiceToolContribution)(c,{descriptor:{source:e.DOMAIN_SOURCE,id:`domains-switch`,name:`switch_domains`,label:`Switch domains`,description:`Queue a validated Doom domain selection and reload the session.`,order:110,inputSchema:n.SWITCH_DOMAINS_INPUT_SCHEMA,resultSchema:n.SWITCH_DOMAINS_RESULT_SCHEMA},execute:async(e,n)=>{let c=e,l=await o.validate(n.context,c.domains),u=(0,i.requireDoomTransitionCoordinator)(n.context);u.plan({sessionId:n.sessionId,hostGeneration:u.hostGeneration,operationId:n.operationId,source:`voice`,target:{axis:`domains`,domains:l},signal:n.signal});let d=(0,r.prepareVoiceReloadHandoff)({sessionId:n.sessionId,hostGeneration:n.hostGeneration,operationId:n.operationId,domains:l}),f;try{f=s.issue({sessionId:n.sessionId,hostGeneration:n.hostGeneration,operationId:n.operationId,domains:l,reloadHandoffToken:d.token}),a.sendUserMessage.bind(a)(`/${t.DOMAIN_COMMAND} ${t.VOICE_SWITCH_TOKEN_PREFIX}${f.token}`,{deliverAs:`followUp`,expandPromptTemplates:!0})}catch(e){throw f&&s.discard(f.token,n),d.discard(),e}return{status:`queued`,stopBatch:`session-reload`}}})}exports.registerDomainVoiceCapabilities=a;
|
|
2
|
+
//# sourceMappingURL=voiceTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceTool.cjs","names":["DOMAIN_SOURCE","EMPTY_DOMAIN_INPUT_SCHEMA","LIST_DOMAINS_RESULT_SCHEMA","SWITCH_DOMAINS_INPUT_SCHEMA","SWITCH_DOMAINS_RESULT_SCHEMA","requireDoomTransitionCoordinator","prepareVoiceReloadHandoff","DOMAIN_COMMAND","VOICE_SWITCH_TOKEN_PREFIX"],"sources":["../../../src/adapters/pi/voiceTool.ts"],"sourcesContent":["import type { DoomExtensionHost } from '@agimon-ai/doompi-extension-contracts/config';\nimport { requireDoomTransitionCoordinator } from '@agimon-ai/doompi-extension-contracts/transition';\nimport {\n prepareVoiceReloadHandoff,\n registerVoiceToolContribution,\n} from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { DomainCatalogPort } from '../../commands/domainsCommand.ts';\nimport {\n EMPTY_DOMAIN_INPUT_SCHEMA,\n LIST_DOMAINS_RESULT_SCHEMA,\n SWITCH_DOMAINS_INPUT_SCHEMA,\n SWITCH_DOMAINS_RESULT_SCHEMA,\n type SwitchDomainsInput,\n} from '../../schemas/domainVoiceTools.ts';\nimport { DOMAIN_COMMAND, VOICE_SWITCH_TOKEN_PREFIX } from '../../services/domainText.ts';\nimport { DOMAIN_SOURCE } from '../../types/domains.ts';\nimport type { DomainSwitchHandoff, DomainSwitchHandoffStore } from '../../types/handoff.ts';\n\nconst LIST_DOMAINS_ID = 'domains-list';\nconst SWITCH_DOMAINS_ID = 'domains-switch';\n\ntype VoiceMessageSender = (\n content: string,\n options: { readonly deliverAs: 'followUp'; readonly expandPromptTemplates: true },\n) => void;\n\n/**\n * The model-facing half of the axis.\n *\n * A switch is never applied here. It plans the transition, parks the validated\n * selection behind an opaque token and sends `/domains --voice-switch-token=…`\n * back as a follow-up, so the reload happens inside a command handler where it\n * can be the terminal action.\n */\nexport function registerDomainVoiceCapabilities(\n pi: ExtensionAPI,\n catalog: DomainCatalogPort,\n store: DomainSwitchHandoffStore,\n): void {\n const host = pi as unknown as DoomExtensionHost<ExtensionContext>;\n registerVoiceToolContribution(host, {\n descriptor: {\n source: DOMAIN_SOURCE,\n id: LIST_DOMAINS_ID,\n name: 'list_domains',\n label: 'List domains',\n description: 'List active, effective, and available Doom domains.',\n order: 100,\n inputSchema: EMPTY_DOMAIN_INPUT_SCHEMA,\n resultSchema: LIST_DOMAINS_RESULT_SCHEMA,\n },\n execute: async (_input, execution) => catalog.list(execution.context),\n });\n registerVoiceToolContribution(host, {\n descriptor: {\n source: DOMAIN_SOURCE,\n id: SWITCH_DOMAINS_ID,\n name: 'switch_domains',\n label: 'Switch domains',\n description: 'Queue a validated Doom domain selection and reload the session.',\n order: 110,\n inputSchema: SWITCH_DOMAINS_INPUT_SCHEMA,\n resultSchema: SWITCH_DOMAINS_RESULT_SCHEMA,\n },\n execute: async (input, execution) => {\n const request = input as SwitchDomainsInput;\n const domains = await catalog.validate(execution.context, request.domains);\n const coordinator = requireDoomTransitionCoordinator(execution.context);\n coordinator.plan({\n sessionId: execution.sessionId,\n hostGeneration: coordinator.hostGeneration,\n operationId: execution.operationId,\n source: 'voice',\n target: { axis: 'domains', domains },\n signal: execution.signal,\n });\n const reloadHandoff = prepareVoiceReloadHandoff({\n sessionId: execution.sessionId,\n hostGeneration: execution.hostGeneration,\n operationId: execution.operationId,\n domains,\n });\n let queued: DomainSwitchHandoff | undefined;\n try {\n queued = store.issue({\n sessionId: execution.sessionId,\n hostGeneration: execution.hostGeneration,\n operationId: execution.operationId,\n domains,\n reloadHandoffToken: reloadHandoff.token,\n });\n // The selection travels in the store, never in the follow-up text, so a\n // transcript cannot be edited into a different switch.\n const sendUserMessage = pi.sendUserMessage.bind(pi) as unknown as VoiceMessageSender;\n sendUserMessage(`/${DOMAIN_COMMAND} ${VOICE_SWITCH_TOKEN_PREFIX}${queued.token}`, {\n deliverAs: 'followUp',\n expandPromptTemplates: true,\n });\n } catch (error) {\n if (queued) store.discard(queued.token, execution);\n reloadHandoff.discard();\n throw error;\n }\n return { status: 'queued', stopBatch: 'session-reload' };\n },\n });\n}\n"],"mappings":"uQAmCA,SAAgB,EACd,EACA,EACA,EACM,CACN,IAAM,EAAO,GACb,EAAA,EAAA,8BAAA,CAA8B,EAAM,CAClC,WAAY,CACV,OAAQA,EAAAA,cACR,GAAI,eACJ,KAAM,eACN,MAAO,eACP,YAAa,sDACb,MAAO,IACP,YAAaC,EAAAA,0BACb,aAAcC,EAAAA,0BAChB,EACA,QAAS,MAAO,EAAQ,IAAc,EAAQ,KAAK,EAAU,OAAO,CACtE,CAAC,GACD,EAAA,EAAA,8BAAA,CAA8B,EAAM,CAClC,WAAY,CACV,OAAQF,EAAAA,cACR,GAAI,iBACJ,KAAM,iBACN,MAAO,iBACP,YAAa,kEACb,MAAO,IACP,YAAaG,EAAAA,4BACb,aAAcC,EAAAA,4BAChB,EACA,QAAS,MAAO,EAAO,IAAc,CACnC,IAAM,EAAU,EACV,EAAU,MAAM,EAAQ,SAAS,EAAU,QAAS,EAAQ,OAAO,EACnE,GAAA,EAAcC,EAAAA,iCAAAA,CAAiC,EAAU,OAAO,EACtE,EAAY,KAAK,CACf,UAAW,EAAU,UACrB,eAAgB,EAAY,eAC5B,YAAa,EAAU,YACvB,OAAQ,QACR,OAAQ,CAAE,KAAM,UAAW,SAAQ,EACnC,OAAQ,EAAU,MACpB,CAAC,EACD,IAAM,GAAA,EAAgBC,EAAAA,0BAAAA,CAA0B,CAC9C,UAAW,EAAU,UACrB,eAAgB,EAAU,eAC1B,YAAa,EAAU,YACvB,SACF,CAAC,EACG,EACJ,GAAI,CACF,EAAS,EAAM,MAAM,CACnB,UAAW,EAAU,UACrB,eAAgB,EAAU,eAC1B,YAAa,EAAU,YACvB,UACA,mBAAoB,EAAc,KACpC,CAAC,EAID,EAD2B,gBAAgB,KAAK,CAClC,CAAC,CAAC,IAAIC,EAAAA,eAAe,GAAGC,EAAAA,4BAA4B,EAAO,QAAS,CAChF,UAAW,WACX,sBAAuB,EACzB,CAAC,CACH,OAAS,EAAO,CAGd,MAFI,GAAQ,EAAM,QAAQ,EAAO,MAAO,CAAS,EACjD,EAAc,QAAQ,EAChB,CACR,CACA,MAAO,CAAE,OAAQ,SAAU,UAAW,gBAAiB,CACzD,CACF,CAAC,CACH"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DomainSwitchHandoffStore } from "../../types/handoff.cjs";
|
|
2
|
+
import { DomainCatalogPort } from "../../commands/domainsCommand.cjs";
|
|
3
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
//#region src/adapters/pi/voiceTool.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The model-facing half of the axis.
|
|
7
|
+
*
|
|
8
|
+
* A switch is never applied here. It plans the transition, parks the validated
|
|
9
|
+
* selection behind an opaque token and sends `/domains --voice-switch-token=…`
|
|
10
|
+
* back as a follow-up, so the reload happens inside a command handler where it
|
|
11
|
+
* can be the terminal action.
|
|
12
|
+
*/
|
|
13
|
+
declare function registerDomainVoiceCapabilities(pi: ExtensionAPI, catalog: DomainCatalogPort, store: DomainSwitchHandoffStore): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { registerDomainVoiceCapabilities };
|
|
16
|
+
//# sourceMappingURL=voiceTool.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceTool.d.cts","names":[],"sources":["../../../src/adapters/pi/voiceTool.ts"],"mappings":";;;;;;;;;;;;iBAmCgB,gCACd,IAAI,cACJ,SAAS,mBACT,OAAO"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DomainSwitchHandoffStore } from "../../types/handoff.mjs";
|
|
2
|
+
import { DomainCatalogPort } from "../../commands/domainsCommand.mjs";
|
|
3
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
//#region src/adapters/pi/voiceTool.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The model-facing half of the axis.
|
|
7
|
+
*
|
|
8
|
+
* A switch is never applied here. It plans the transition, parks the validated
|
|
9
|
+
* selection behind an opaque token and sends `/domains --voice-switch-token=…`
|
|
10
|
+
* back as a follow-up, so the reload happens inside a command handler where it
|
|
11
|
+
* can be the terminal action.
|
|
12
|
+
*/
|
|
13
|
+
declare function registerDomainVoiceCapabilities(pi: ExtensionAPI, catalog: DomainCatalogPort, store: DomainSwitchHandoffStore): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { registerDomainVoiceCapabilities };
|
|
16
|
+
//# sourceMappingURL=voiceTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceTool.d.mts","names":[],"sources":["../../../src/adapters/pi/voiceTool.ts"],"mappings":";;;;;;;;;;;;iBAmCgB,gCACd,IAAI,cACJ,SAAS,mBACT,OAAO"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{DOMAIN_SOURCE as e}from"../../types/domains.mjs";import{DOMAIN_COMMAND as t,VOICE_SWITCH_TOKEN_PREFIX as n}from"../../services/domainText.mjs";import{EMPTY_DOMAIN_INPUT_SCHEMA as r,LIST_DOMAINS_RESULT_SCHEMA as i,SWITCH_DOMAINS_INPUT_SCHEMA as a,SWITCH_DOMAINS_RESULT_SCHEMA as o}from"../../schemas/domainVoiceTools.mjs";import{prepareVoiceReloadHandoff as s,registerVoiceToolContribution as c}from"@agimon-ai/doompi-extension-contracts/voice-tools";import{requireDoomTransitionCoordinator as l}from"@agimon-ai/doompi-extension-contracts/transition";function u(u,d,f){let p=u;c(p,{descriptor:{source:e,id:`domains-list`,name:`list_domains`,label:`List domains`,description:`List active, effective, and available Doom domains.`,order:100,inputSchema:r,resultSchema:i},execute:async(e,t)=>d.list(t.context)}),c(p,{descriptor:{source:e,id:`domains-switch`,name:`switch_domains`,label:`Switch domains`,description:`Queue a validated Doom domain selection and reload the session.`,order:110,inputSchema:a,resultSchema:o},execute:async(e,r)=>{let i=e,a=await d.validate(r.context,i.domains),o=l(r.context);o.plan({sessionId:r.sessionId,hostGeneration:o.hostGeneration,operationId:r.operationId,source:`voice`,target:{axis:`domains`,domains:a},signal:r.signal});let c=s({sessionId:r.sessionId,hostGeneration:r.hostGeneration,operationId:r.operationId,domains:a}),p;try{p=f.issue({sessionId:r.sessionId,hostGeneration:r.hostGeneration,operationId:r.operationId,domains:a,reloadHandoffToken:c.token}),u.sendUserMessage.bind(u)(`/${t} ${n}${p.token}`,{deliverAs:`followUp`,expandPromptTemplates:!0})}catch(e){throw p&&f.discard(p.token,r),c.discard(),e}return{status:`queued`,stopBatch:`session-reload`}}})}export{u as registerDomainVoiceCapabilities};
|
|
2
|
+
//# sourceMappingURL=voiceTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceTool.mjs","names":[],"sources":["../../../src/adapters/pi/voiceTool.ts"],"sourcesContent":["import type { DoomExtensionHost } from '@agimon-ai/doompi-extension-contracts/config';\nimport { requireDoomTransitionCoordinator } from '@agimon-ai/doompi-extension-contracts/transition';\nimport {\n prepareVoiceReloadHandoff,\n registerVoiceToolContribution,\n} from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { DomainCatalogPort } from '../../commands/domainsCommand.ts';\nimport {\n EMPTY_DOMAIN_INPUT_SCHEMA,\n LIST_DOMAINS_RESULT_SCHEMA,\n SWITCH_DOMAINS_INPUT_SCHEMA,\n SWITCH_DOMAINS_RESULT_SCHEMA,\n type SwitchDomainsInput,\n} from '../../schemas/domainVoiceTools.ts';\nimport { DOMAIN_COMMAND, VOICE_SWITCH_TOKEN_PREFIX } from '../../services/domainText.ts';\nimport { DOMAIN_SOURCE } from '../../types/domains.ts';\nimport type { DomainSwitchHandoff, DomainSwitchHandoffStore } from '../../types/handoff.ts';\n\nconst LIST_DOMAINS_ID = 'domains-list';\nconst SWITCH_DOMAINS_ID = 'domains-switch';\n\ntype VoiceMessageSender = (\n content: string,\n options: { readonly deliverAs: 'followUp'; readonly expandPromptTemplates: true },\n) => void;\n\n/**\n * The model-facing half of the axis.\n *\n * A switch is never applied here. It plans the transition, parks the validated\n * selection behind an opaque token and sends `/domains --voice-switch-token=…`\n * back as a follow-up, so the reload happens inside a command handler where it\n * can be the terminal action.\n */\nexport function registerDomainVoiceCapabilities(\n pi: ExtensionAPI,\n catalog: DomainCatalogPort,\n store: DomainSwitchHandoffStore,\n): void {\n const host = pi as unknown as DoomExtensionHost<ExtensionContext>;\n registerVoiceToolContribution(host, {\n descriptor: {\n source: DOMAIN_SOURCE,\n id: LIST_DOMAINS_ID,\n name: 'list_domains',\n label: 'List domains',\n description: 'List active, effective, and available Doom domains.',\n order: 100,\n inputSchema: EMPTY_DOMAIN_INPUT_SCHEMA,\n resultSchema: LIST_DOMAINS_RESULT_SCHEMA,\n },\n execute: async (_input, execution) => catalog.list(execution.context),\n });\n registerVoiceToolContribution(host, {\n descriptor: {\n source: DOMAIN_SOURCE,\n id: SWITCH_DOMAINS_ID,\n name: 'switch_domains',\n label: 'Switch domains',\n description: 'Queue a validated Doom domain selection and reload the session.',\n order: 110,\n inputSchema: SWITCH_DOMAINS_INPUT_SCHEMA,\n resultSchema: SWITCH_DOMAINS_RESULT_SCHEMA,\n },\n execute: async (input, execution) => {\n const request = input as SwitchDomainsInput;\n const domains = await catalog.validate(execution.context, request.domains);\n const coordinator = requireDoomTransitionCoordinator(execution.context);\n coordinator.plan({\n sessionId: execution.sessionId,\n hostGeneration: coordinator.hostGeneration,\n operationId: execution.operationId,\n source: 'voice',\n target: { axis: 'domains', domains },\n signal: execution.signal,\n });\n const reloadHandoff = prepareVoiceReloadHandoff({\n sessionId: execution.sessionId,\n hostGeneration: execution.hostGeneration,\n operationId: execution.operationId,\n domains,\n });\n let queued: DomainSwitchHandoff | undefined;\n try {\n queued = store.issue({\n sessionId: execution.sessionId,\n hostGeneration: execution.hostGeneration,\n operationId: execution.operationId,\n domains,\n reloadHandoffToken: reloadHandoff.token,\n });\n // The selection travels in the store, never in the follow-up text, so a\n // transcript cannot be edited into a different switch.\n const sendUserMessage = pi.sendUserMessage.bind(pi) as unknown as VoiceMessageSender;\n sendUserMessage(`/${DOMAIN_COMMAND} ${VOICE_SWITCH_TOKEN_PREFIX}${queued.token}`, {\n deliverAs: 'followUp',\n expandPromptTemplates: true,\n });\n } catch (error) {\n if (queued) store.discard(queued.token, execution);\n reloadHandoff.discard();\n throw error;\n }\n return { status: 'queued', stopBatch: 'session-reload' };\n },\n });\n}\n"],"mappings":"6iBAmCA,SAAgB,EACd,EACA,EACA,EACM,CACN,IAAM,EAAO,EACb,EAA8B,EAAM,CAClC,WAAY,CACV,OAAQ,EACR,GAAI,eACJ,KAAM,eACN,MAAO,eACP,YAAa,sDACb,MAAO,IACP,YAAa,EACb,aAAc,CAChB,EACA,QAAS,MAAO,EAAQ,IAAc,EAAQ,KAAK,EAAU,OAAO,CACtE,CAAC,EACD,EAA8B,EAAM,CAClC,WAAY,CACV,OAAQ,EACR,GAAI,iBACJ,KAAM,iBACN,MAAO,iBACP,YAAa,kEACb,MAAO,IACP,YAAa,EACb,aAAc,CAChB,EACA,QAAS,MAAO,EAAO,IAAc,CACnC,IAAM,EAAU,EACV,EAAU,MAAM,EAAQ,SAAS,EAAU,QAAS,EAAQ,OAAO,EACnE,EAAc,EAAiC,EAAU,OAAO,EACtE,EAAY,KAAK,CACf,UAAW,EAAU,UACrB,eAAgB,EAAY,eAC5B,YAAa,EAAU,YACvB,OAAQ,QACR,OAAQ,CAAE,KAAM,UAAW,SAAQ,EACnC,OAAQ,EAAU,MACpB,CAAC,EACD,IAAM,EAAgB,EAA0B,CAC9C,UAAW,EAAU,UACrB,eAAgB,EAAU,eAC1B,YAAa,EAAU,YACvB,SACF,CAAC,EACG,EACJ,GAAI,CACF,EAAS,EAAM,MAAM,CACnB,UAAW,EAAU,UACrB,eAAgB,EAAU,eAC1B,YAAa,EAAU,YACvB,UACA,mBAAoB,EAAc,KACpC,CAAC,EAID,EAD2B,gBAAgB,KAAK,CAClC,CAAC,CAAC,IAAI,EAAe,GAAG,IAA4B,EAAO,QAAS,CAChF,UAAW,WACX,sBAAuB,EACzB,CAAC,CACH,OAAS,EAAO,CAGd,MAFI,GAAQ,EAAM,QAAQ,EAAO,MAAO,CAAS,EACjD,EAAc,QAAQ,EAChB,CACR,CACA,MAAO,CAAE,OAAQ,SAAU,UAAW,gBAAiB,CACzD,CACF,CAAC,CACH"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);let n=require("@agimon-ai/doompi-config/domains"),r=require("node:fs");r=e.__toESM(r,1);let i=require("node:child_process");const a=`.doompi-plugin.json`;function o(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function s(e,t,n={}){return new Promise((r,a)=>{let s=(0,i.spawn)(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;s.stdout.on(`data`,e=>{c=o(c,e)}),s.stderr.on(`data`,e=>{l=o(l,e)}),s.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),s.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function c(e,n,r){let i=t.default.relative(e,n);if(!(i===``||!i.startsWith(`..`)&&!t.default.isAbsolute(i)))throw Error(`${r} resolves outside ${e}`)}async function l(e,n){let r=t.default.join(n,`checkout`),i=[`clone`,`--filter=blob:none`];e.path&&i.push(`--sparse`,`--no-checkout`),i.push(e.url,r);let a={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await s(`git`,i,{environment:a}),e.path&&await s(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,e.path],{cwd:r,environment:a}),e.sha){await s(`git`,[`checkout`,e.sha],{cwd:r,environment:a});let t=await s(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:a});if(t.toLowerCase()!==e.sha.toLowerCase())throw Error(`Checked out Git SHA ${t} does not match requested SHA ${e.sha}`)}else e.ref?await s(`git`,[`checkout`,e.ref],{cwd:r,environment:a}):e.path&&await s(`git`,[`checkout`],{cwd:r,environment:a});let o=e.path?t.default.resolve(r,e.path):r;return c(r,o,`Git plugin path`),o}async function u(e,n){let r=t.default.join(n,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,e.version?`${e.package}@${e.version}`:e.package];e.registry&&i.push(`--registry`,e.registry),await s(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=t.default.resolve(r,`node_modules`,...e.package.split(`/`));return c(t.default.join(r,`node_modules`),a,`npm plugin package`),a}const d={git:l,npm:u};async function f(e){try{return(await r.default.promises.lstat(e)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function p(e,n){try{let i=JSON.parse(r.default.readFileSync(n,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);return n===t.default.join(e,`plugin.json`)&&`$schema`in i&&i.$schema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?`direct-children`:`recursive`}catch(e){throw Error(`Invalid plugin manifest ${n}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function m(e){let i=await f(e.directory);if(i===`missing`)return!1;if(i!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${e.directory}`);if(!e.source||!(0,n.isRemotePluginSource)(e.source))throw Error(`Remote plugin entry is missing its source: ${e.name??e.directory}`);let o;try{o=JSON.parse(await r.default.promises.readFile(t.default.join(e.directory,a),`utf8`))}catch(t){throw Error(`Remote plugin cache is not managed by DoomPi: ${e.directory}`,{cause:t})}if(o.version!==1||JSON.stringify(o.source)!==JSON.stringify(e.source))throw Error(`Remote plugin cache metadata does not match ${e.name??e.directory}: ${e.directory}`);let s=(0,n.findPluginManifestPath)(e.directory);if(!s)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${e.directory}`);return p(e.directory,s)}async function h(e,n){if(await f(e)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${e}`);await r.default.promises.cp(e,n,{recursive:!0,filter:e=>t.default.basename(e)!==`.git`})}function g(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function _(e,i){if(!e.source||!(0,n.isRemotePluginSource)(e.source))return e;let o=await m(e);if(o)return{...e,skillDiscovery:o};let s=t.default.dirname(e.directory);if(await r.default.promises.mkdir(s,{recursive:!0,mode:448}),await f(s)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${s}`);await r.default.promises.chmod(s,448);let c=await r.default.promises.mkdtemp(t.default.join(s,`.plugin-staging-`)),l=t.default.join(c,`installation`);try{await h(e.source.type===`git`?await i.git(e.source,c):await i.npm(e.source,c),l);let o=(0,n.findPluginManifestPath)(l);if(!o)throw Error(`Remote plugin ${e.name??e.directory} does not contain a supported plugin manifest`);let s=p(l,o),u=t.default.join(l,a);if(await f(u)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${a}`);let d={version:1,source:e.source};await r.default.promises.writeFile(u,`${JSON.stringify(d,null,2)}\n`,{flag:`wx`,mode:384});try{await r.default.promises.rename(l,e.directory)}catch(t){if(!g(t))throw t;if(await r.default.promises.rm(l,{recursive:!0,force:!0}),!await m(e))throw Error(`Remote plugin installation race left no cache: ${e.directory}`)}return{...e,skillDiscovery:s}}catch(t){throw Error(`Failed to install remote plugin ${e.name??e.directory}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{await r.default.promises.rm(c,{recursive:!0,force:!0})}}async function v(e,t={}){let n={git:t.materializers?.git??d.git,npm:t.materializers?.npm??d.npm};return Promise.all(e.map(e=>_(e,n)))}exports.materializePluginEntries=v;
|
|
2
|
+
//# sourceMappingURL=pluginMaterializer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginMaterializer.cjs","names":["spawn","path","fs","isRemotePluginSource","findPluginManifestPath"],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n assertContained(checkout, pluginRoot, 'Git plugin path');\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): PluginSkillDiscovery {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n return manifestPath === path.join(pluginRoot, 'plugin.json') &&\n '$schema' in manifest &&\n manifest.$schema === AGENT_PLUGIN_SCHEMA\n ? 'direct-children'\n : 'recursive';\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<PluginSkillDiscovery | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingDiscovery = await inspectInstallation(entry);\n if (existingDiscovery) return { ...entry, skillDiscovery: existingDiscovery };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n const skillDiscovery = validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedDiscovery = await inspectInstallation(entry);\n if (!racedDiscovery) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n }\n return { ...entry, skillDiscovery };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GitPluginSource, NpmPluginSource, PluginEntry } from "@agimon-ai/doompi-config/domains";
|
|
2
|
+
//#region src/adapters/pluginMaterializer.d.ts
|
|
3
|
+
interface PluginSourceMaterializers {
|
|
4
|
+
git: (source: GitPluginSource, workspace: string) => Promise<string>;
|
|
5
|
+
npm: (source: NpmPluginSource, workspace: string) => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
interface PluginMaterializerOptions {
|
|
8
|
+
materializers?: Partial<PluginSourceMaterializers>;
|
|
9
|
+
}
|
|
10
|
+
/** Downloads selected remote plugins once into their content-addressed cache directories. */
|
|
11
|
+
declare function materializePluginEntries(entries: readonly PluginEntry[], options?: PluginMaterializerOptions): Promise<PluginEntry[]>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PluginMaterializerOptions, PluginSourceMaterializers, materializePluginEntries };
|
|
14
|
+
//# sourceMappingURL=pluginMaterializer.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginMaterializer.d.cts","names":[],"sources":["../../src/adapters/pluginMaterializer.ts"],"mappings":";;UA2BiB;EACf,MAAM,QAAQ,iBAAiB,sBAAsB;EACrD,MAAM,QAAQ,iBAAiB,sBAAsB;;UAGtC;EACf,gBAAgB,QAAQ;;;iBA0OJ,yBACpB,kBAAkB,eAClB,UAAS,4BACR,QAAQ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GitPluginSource, NpmPluginSource, PluginEntry } from "@agimon-ai/doompi-config/domains";
|
|
2
|
+
//#region src/adapters/pluginMaterializer.d.ts
|
|
3
|
+
interface PluginSourceMaterializers {
|
|
4
|
+
git: (source: GitPluginSource, workspace: string) => Promise<string>;
|
|
5
|
+
npm: (source: NpmPluginSource, workspace: string) => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
interface PluginMaterializerOptions {
|
|
8
|
+
materializers?: Partial<PluginSourceMaterializers>;
|
|
9
|
+
}
|
|
10
|
+
/** Downloads selected remote plugins once into their content-addressed cache directories. */
|
|
11
|
+
declare function materializePluginEntries(entries: readonly PluginEntry[], options?: PluginMaterializerOptions): Promise<PluginEntry[]>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PluginMaterializerOptions, PluginSourceMaterializers, materializePluginEntries };
|
|
14
|
+
//# sourceMappingURL=pluginMaterializer.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginMaterializer.d.mts","names":[],"sources":["../../src/adapters/pluginMaterializer.ts"],"mappings":";;UA2BiB;EACf,MAAM,QAAQ,iBAAiB,sBAAsB;EACrD,MAAM,QAAQ,iBAAiB,sBAAsB;;UAGtC;EACf,gBAAgB,QAAQ;;;iBA0OJ,yBACpB,kBAAkB,eAClB,UAAS,4BACR,QAAQ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"node:path";import{findPluginManifestPath as t,isRemotePluginSource as n}from"@agimon-ai/doompi-config/domains";import r from"node:fs";import{spawn as i}from"node:child_process";const a=`.doompi-plugin.json`;function o(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function s(e,t,n={}){return new Promise((r,a)=>{let s=i(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;s.stdout.on(`data`,e=>{c=o(c,e)}),s.stderr.on(`data`,e=>{l=o(l,e)}),s.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),s.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function c(t,n,r){let i=e.relative(t,n);if(!(i===``||!i.startsWith(`..`)&&!e.isAbsolute(i)))throw Error(`${r} resolves outside ${t}`)}async function l(t,n){let r=e.join(n,`checkout`),i=[`clone`,`--filter=blob:none`];t.path&&i.push(`--sparse`,`--no-checkout`),i.push(t.url,r);let a={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await s(`git`,i,{environment:a}),t.path&&await s(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,t.path],{cwd:r,environment:a}),t.sha){await s(`git`,[`checkout`,t.sha],{cwd:r,environment:a});let e=await s(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:a});if(e.toLowerCase()!==t.sha.toLowerCase())throw Error(`Checked out Git SHA ${e} does not match requested SHA ${t.sha}`)}else t.ref?await s(`git`,[`checkout`,t.ref],{cwd:r,environment:a}):t.path&&await s(`git`,[`checkout`],{cwd:r,environment:a});let o=t.path?e.resolve(r,t.path):r;return c(r,o,`Git plugin path`),o}async function u(t,n){let r=e.join(n,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,t.version?`${t.package}@${t.version}`:t.package];t.registry&&i.push(`--registry`,t.registry),await s(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=e.resolve(r,`node_modules`,...t.package.split(`/`));return c(e.join(r,`node_modules`),a,`npm plugin package`),a}const d={git:l,npm:u};async function f(e){try{return(await r.promises.lstat(e)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function p(t,n){try{let i=JSON.parse(r.readFileSync(n,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);return n===e.join(t,`plugin.json`)&&`$schema`in i&&i.$schema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?`direct-children`:`recursive`}catch(e){throw Error(`Invalid plugin manifest ${n}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function m(i){let o=await f(i.directory);if(o===`missing`)return!1;if(o!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${i.directory}`);if(!i.source||!n(i.source))throw Error(`Remote plugin entry is missing its source: ${i.name??i.directory}`);let s;try{s=JSON.parse(await r.promises.readFile(e.join(i.directory,a),`utf8`))}catch(e){throw Error(`Remote plugin cache is not managed by DoomPi: ${i.directory}`,{cause:e})}if(s.version!==1||JSON.stringify(s.source)!==JSON.stringify(i.source))throw Error(`Remote plugin cache metadata does not match ${i.name??i.directory}: ${i.directory}`);let c=t(i.directory);if(!c)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${i.directory}`);return p(i.directory,c)}async function h(t,n){if(await f(t)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${t}`);await r.promises.cp(t,n,{recursive:!0,filter:t=>e.basename(t)!==`.git`})}function g(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function _(i,o){if(!i.source||!n(i.source))return i;let s=await m(i);if(s)return{...i,skillDiscovery:s};let c=e.dirname(i.directory);if(await r.promises.mkdir(c,{recursive:!0,mode:448}),await f(c)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${c}`);await r.promises.chmod(c,448);let l=await r.promises.mkdtemp(e.join(c,`.plugin-staging-`)),u=e.join(l,`installation`);try{await h(i.source.type===`git`?await o.git(i.source,l):await o.npm(i.source,l),u);let n=t(u);if(!n)throw Error(`Remote plugin ${i.name??i.directory} does not contain a supported plugin manifest`);let s=p(u,n),c=e.join(u,a);if(await f(c)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${a}`);let d={version:1,source:i.source};await r.promises.writeFile(c,`${JSON.stringify(d,null,2)}\n`,{flag:`wx`,mode:384});try{await r.promises.rename(u,i.directory)}catch(e){if(!g(e))throw e;if(await r.promises.rm(u,{recursive:!0,force:!0}),!await m(i))throw Error(`Remote plugin installation race left no cache: ${i.directory}`)}return{...i,skillDiscovery:s}}catch(e){throw Error(`Failed to install remote plugin ${i.name??i.directory}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{await r.promises.rm(l,{recursive:!0,force:!0})}}async function v(e,t={}){let n={git:t.materializers?.git??d.git,npm:t.materializers?.npm??d.npm};return Promise.all(e.map(e=>_(e,n)))}export{v as materializePluginEntries};
|
|
2
|
+
//# sourceMappingURL=pluginMaterializer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginMaterializer.mjs","names":[],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n assertContained(checkout, pluginRoot, 'Git plugin path');\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): PluginSkillDiscovery {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n return manifestPath === path.join(pluginRoot, 'plugin.json') &&\n '$schema' in manifest &&\n manifest.$schema === AGENT_PLUGIN_SCHEMA\n ? 'direct-children'\n : 'recursive';\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<PluginSkillDiscovery | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingDiscovery = await inspectInstallation(entry);\n if (existingDiscovery) return { ...entry, skillDiscovery: existingDiscovery };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n const skillDiscovery = validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedDiscovery = await inspectInstallation(entry);\n if (!racedDiscovery) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n }\n return { ...entry, skillDiscovery };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./mcpFilter.cjs"),n=require("../services/toolNames.cjs"),r=require("./skillCacheLocation.cjs");let i=require("node:path");i=e.__toESM(i,1);let a=require("node:fs");a=e.__toESM(a,1);let o=require("yaml"),s=require("node:crypto"),c=require("node:os");c=e.__toESM(c,1);const l=`agiflow-dispatcher`,u=[`read`,`grep`,`find`,`ls`,`bash`,`launch_workflow`,`list_workflows`];function d(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);if(!t)throw Error(`Resource is missing YAML frontmatter`);return{attributes:(0,o.parse)(t[1]),body:t[2]??``}}const f={sonnet:`anthropic/claude-sonnet-4-6`,opus:`anthropic/claude-opus-4-6`,haiku:`anthropic/claude-haiku-4-5`};function p(e){let t=e.trim();if(!t||t!==e||t===`.`||t===`..`||t.includes(`\0`)||/[\\/]/.test(t))throw Error(`Unsafe agent name: ${JSON.stringify(e)}`);return t}function m(e){return typeof e==`string`?f[e.toLowerCase()]??e:Array.isArray(e)?e.map(e=>m(e)):e}function h(e){let{attributes:t,body:r}=d(e),i=typeof t.name==`string`?t.name:void 0;if(!i)throw Error(`Agent definition requires a name`);let a=p(i),s=Object.hasOwn(t,`tools`),c=Array.isArray(t.tools)?t.tools.map(String):typeof t.tools==`string`?t.tools.split(`,`).map(e=>e.trim()).filter(Boolean):[],l=[...new Set(c.map(n.toPiToolName).filter(e=>!!e))],u={...t,inheritProjectContext:!0,inheritSkills:!0,systemPromptMode:t.systemPromptMode??`replace`};if(s?u.tools=Array.isArray(t.tools)?l:l.join(`, `):delete u.tools,u.model!==void 0&&(u.model=m(u.model)),u.fallbackModels!==void 0&&(u.fallbackModels=m(u.fallbackModels)),u.memory===`project`||u.memory===`user`)u.memory={scope:u.memory,path:a};else if(u.memory!==void 0&&(typeof u.memory!=`object`||u.memory===null||Array.isArray(u.memory)))throw Error(`Unsupported memory declaration`);return delete u.permissionMode,{name:a,content:`---\n${(0,o.stringify)(u).trim()}\n---\n\n${r.trimStart()}`}}function g(e,t,n,a){let o=(0,s.createHash)(`sha256`).update(`${i.default.resolve(t)}\0${n}`).digest(`hex`).slice(0,16);return i.default.join(a??r.resolveSkillCacheDirectory(e),`${o}.json`)}function _(e){try{let t=a.default.statSync(e.path);return t.isFile()&&t.size===e.size&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function v(e){try{let t=a.default.statSync(e.path);return t.isDirectory()&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function y(e,t,n){try{let r=JSON.parse(a.default.readFileSync(e,`utf8`));return r.version!==2||r.root!==i.default.resolve(t)||r.discovery!==n||!Array.isArray(r.files)||!Array.isArray(r.directories)||!r.files.every(_)||!r.directories.every(v)?void 0:r}catch{return}}function b(e,t){a.default.mkdirSync(i.default.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;a.default.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{a.default.renameSync(n,e)}catch(t){if(a.default.rmSync(n,{force:!0}),!a.default.existsSync(e))throw t}}async function x(e){try{return await a.default.promises.access(e),!0}catch{return!1}}async function S(e,t,n){try{let r=JSON.parse(await a.default.promises.readFile(e,`utf8`));if(r.version!==2||r.root!==i.default.resolve(t)||r.discovery!==n||!Array.isArray(r.files)||!Array.isArray(r.directories))return;for(let e of r.files){let t=await a.default.promises.stat(e.path);if(!t.isFile()||t.size!==e.size||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}for(let e of r.directories){let t=await a.default.promises.stat(e.path);if(!t.isDirectory()||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}return r}catch{return}}async function C(e,t){await a.default.promises.mkdir(i.default.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;await a.default.promises.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{await a.default.promises.rename(n,e)}catch(t){if(await a.default.promises.rm(n,{force:!0}),!await x(e))throw t}}function w(e,t){let n=[],r=[],o=(e,c)=>{if(!a.default.existsSync(e))return;let l=a.default.statSync(e);n.push({path:e,mtimeMs:l.mtimeMs,ctimeMs:l.ctimeMs});for(let n of a.default.readdirSync(e,{withFileTypes:!0})){let l=i.default.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=a.default.readFileSync(l,`utf8`),{attributes:f}=d(u);if(typeof f.name!=`string`)throw Error(`Resource requires a name: ${l}`);let p=a.default.statSync(l);r.push({path:l,name:f.name,digest:(0,s.createHash)(`sha256`).update(u).digest(`hex`),size:p.size,mtimeMs:p.mtimeMs,ctimeMs:p.ctimeMs})}},c=i.default.resolve(e);return o(c,0),r.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:r,directories:n}}function T(e,t,n=`recursive`,r){if(!a.default.existsSync(t))return[];let i=g(e,t,n,r),o=y(i,t,n),s=o??w(t,n);return o||b(i,s),s.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function E(e,t){let n=[],r=[],o=async(e,c)=>{let l;try{let t=await a.default.promises.stat(e);n.push({path:e,mtimeMs:t.mtimeMs,ctimeMs:t.ctimeMs}),l=await a.default.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}for(let n of l){let l=i.default.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&await o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=await a.default.promises.readFile(l,`utf8`),{attributes:f}=d(u);if(typeof f.name!=`string`)throw Error(`Resource requires a name: ${l}`);let p=await a.default.promises.stat(l);r.push({path:l,name:f.name,digest:(0,s.createHash)(`sha256`).update(u).digest(`hex`),size:p.size,mtimeMs:p.mtimeMs,ctimeMs:p.ctimeMs})}},c=i.default.resolve(e);return await o(c,0),r.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:r,directories:n}}async function D(e,t,n=`recursive`,r){if(!await x(t))return[];let i=g(e,t,n,r),a=await S(i,t,n),o=a??await E(t,n);return a||await C(i,o),o.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function O(e){let t;try{t=await a.default.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let n=[];for(let r of t){let t=i.default.join(e,r.name);r.isDirectory()&&n.push(...await O(t)),r.isFile()&&r.name.endsWith(`.md`)&&n.push(t)}return n}async function k(e){let{attributes:t}=d(await a.default.promises.readFile(e,`utf8`));if(typeof t.name!=`string`)throw Error(`Resource requires a name: ${e}`);return t.name}async function A(e,t){let n=new Map,r=new Map;for(let i of e){let e=n.get(i.name),o=i.digest??(0,s.createHash)(`sha256`).update(await a.default.promises.readFile(i.path)).digest(`hex`);if(e&&r.get(i.name)!==o)throw Error(`Conflicting ${t} "${i.name}": ${e} and ${i.path}`);n.set(i.name,i.path),r.set(i.name,o)}}function j(){let e={name:l,description:`Selects and launches Agiflow workflows for one loop pass without implementing the work.`,thinking:`high`,systemPromptMode:`replace`,inheritProjectContext:!0,inheritSkills:!0,tools:u.join(`, `),defaultContext:`fresh`,defaultProgress:!1},t=[`You are the Agiflow workflow dispatcher.`,`Reason about the supplied dispatch context and launch eligible workflows.`,`Launch workflows without monitoring them. After dispatching, report and exit.`,`Follow the task restrictions exactly. Do not implement jobs or edit repository files.`].join(`
|
|
2
|
+
`);return`---\n${(0,o.stringify)(e).trim()}\n---\n\n${t}\n`}function M(e){let t={mcpServers:{}},n=t.mcpServers,r=new Map;for(let t of e){if(!a.default.existsSync(t))continue;let e=JSON.parse(a.default.readFileSync(t,`utf8`)).mcpServers??{};for(let[i,a]of Object.entries(e)){let e=n[i];if(e&&JSON.stringify(e)!==JSON.stringify(a))throw Error(`Conflicting MCP server "${i}": ${r.get(i)} and ${t}`);n[i]=a,r.set(i,t)}}return t}async function N(e){let t={mcpServers:{}},n=t.mcpServers,r=new Map;for(let t of e){let e;try{e=await a.default.promises.readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)continue;throw e}let i=JSON.parse(e).mcpServers??{};for(let[e,a]of Object.entries(i)){let i=n[e];if(i&&JSON.stringify(i)!==JSON.stringify(a))throw Error(`Conflicting MCP server "${e}": ${r.get(e)} and ${t}`);n[e]=a,r.set(e,t)}}return t}function P(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function F(e,t){return!e||e.some(e=>e.includes(`*`)?RegExp(`^${e.split(`*`).map(P).join(`.*`)}$`).test(t):e===t)}async function I(e,n,r){let o=n.map(e=>typeof e==`string`?{directory:e}:e),s=r.temporaryDirectory===void 0,u=r.temporaryDirectory??await a.default.promises.mkdtemp(i.default.join(c.default.tmpdir(),`doom-pi-`));await a.default.promises.mkdir(u,{mode:448,recursive:!0}),await a.default.promises.chmod(u,448);let d=i.default.join(e,`.claude`,`skills`),f=r.sharedSkills===!1?[]:await D(e,d,`recursive`,r.skillCacheDirectory),m=[],g=[],_=[],v=[],y=[],b=[i.default.join(e,`.mcp.json`)];for(let t of o){let n=t.directory,a=i.default.join(n,`skills`);if(await x(a)){let n=(await D(e,a,t.skillDiscovery??`recursive`,r.skillCacheDirectory)).filter(e=>F(t.skills,e.name));m.push(...n.map(e=>e.path)),g.push(...n)}let o=await O(i.default.join(n,`agents`)),s=await Promise.all(o.map(e=>k(e)));_.push(...o.map((e,t)=>({name:s[t]??``,path:e})).filter(e=>F(t.agents,e.name)));let c=i.default.join(n,`hooks`,`hooks.json`);t.hooks!==!1&&await x(c)&&v.push({pluginRoot:n,configPath:c});let l=i.default.join(n,`.mcp.json`);t.mcp!==!1&&await x(l)&&(b.push(l),y.push(l))}await A(g,`skill`),await A(f,`skill`);let S=new Set(g.map(e=>e.name)),C=f.filter(e=>!S.has(e.name));if(m.push(...C.map(e=>e.path)),g.push(...C),await A(_,`agent`),_.some(e=>e.name===`agiflow-dispatcher`))throw Error(`Conflicting agent "${l}": reserved by the agent harness`);let w=[],T=i.default.join(u,`agents`);if(await a.default.promises.rm(T,{recursive:!0,force:!0}),r.agents){await a.default.promises.mkdir(T,{mode:448});for(let e of _){let t=h(await a.default.promises.readFile(e.path,`utf8`));await a.default.promises.writeFile(i.default.join(T,`${p(t.name)}.md`),t.content,{mode:384})}await a.default.promises.writeFile(i.default.join(T,`${l}.md`),j(),{mode:384}),w.push(T)}let E;if(r.mcp){E=i.default.join(u,`mcp.json`);let n=await t.applyMcpAllowlist(await N(b),r.mcpAllowlist,e,u);await a.default.promises.writeFile(E,`${JSON.stringify(n,null,2)}\n`,{mode:384})}return{temporaryDirectory:u,skillDirectories:m,skillCount:g.length,agentCount:_.length,agentDirectories:w,pluginHooks:v,mcpConfigPath:E,pluginMcpConfigPaths:y,cleanup:()=>s?a.default.promises.rm(u,{recursive:!0,force:!0}):Promise.resolve()}}exports.DISPATCHER_AGENT_NAME=l,exports.adaptAgentDefinition=h,exports.collectResources=I,exports.discoverSkills=T,exports.discoverSkillsAsync=D,exports.mergeMcpConfigs=M,exports.mergeMcpConfigsAsync=N;
|
|
3
|
+
//# sourceMappingURL=resourceCollector.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.cjs","names":["parse","toPiToolName","stringify","createHash","path","resolveSkillCacheDirectory","fs","os","applyMcpAllowlist"],"sources":["../../src/adapters/resourceCollector.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { PluginEntry, PluginSkillDiscovery } from '@agimon-ai/doompi-config/domains';\nimport { parse, stringify } from 'yaml';\nimport { toPiToolName } from '../services/toolNames.ts';\nimport type { HarnessResourceOptions, HarnessResources, JsonObject, NamedResource } from '../types/resources.ts';\nimport type { PluginHookSource } from '@agimon-ai/doompi-config/types';\nimport { applyMcpAllowlist } from './mcpFilter.ts';\nimport { resolveSkillCacheDirectory } from './skillCacheLocation.ts';\n\nexport const DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst DISPATCHER_TOOLS = ['read', 'grep', 'find', 'ls', 'bash', 'launch_workflow', 'list_workflows'];\nconst SKILL_MANIFEST_VERSION = 2;\nconst SKILL_MANIFEST_HASH_LENGTH = 16;\n\ninterface SkillManifestFile {\n path: string;\n name: string;\n digest: string;\n size: number;\n mtimeMs: number;\n ctimeMs: number;\n}\n\ninterface SkillManifestDirectory {\n path: string;\n mtimeMs: number;\n ctimeMs: number;\n}\n\ninterface SkillManifest {\n version: number;\n root: string;\n discovery: PluginSkillDiscovery;\n files: SkillManifestFile[];\n directories: SkillManifestDirectory[];\n}\n\nfunction splitFrontmatter(content: string): { attributes: JsonObject; body: string } {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) throw new Error('Resource is missing YAML frontmatter');\n return { attributes: parse(match[1]!) as JsonObject, body: match[2] ?? '' };\n}\n\nconst CLAUDE_MODEL_ALIASES: Record<string, string> = {\n sonnet: 'anthropic/claude-sonnet-4-6',\n opus: 'anthropic/claude-opus-4-6',\n haiku: 'anthropic/claude-haiku-4-5',\n};\n\nfunction assertSafeAgentName(name: string): string {\n const trimmed = name.trim();\n if (\n !trimmed ||\n trimmed !== name ||\n trimmed === '.' ||\n trimmed === '..' ||\n trimmed.includes('\\0') ||\n /[\\\\/]/.test(trimmed)\n ) {\n throw new Error(`Unsafe agent name: ${JSON.stringify(name)}`);\n }\n return trimmed;\n}\n\nfunction normalizeClaudeModel(value: unknown): unknown {\n if (typeof value === 'string') return CLAUDE_MODEL_ALIASES[value.toLowerCase()] ?? value;\n if (Array.isArray(value)) return value.map((entry) => normalizeClaudeModel(entry));\n return value;\n}\n\n/** Rewrites a Claude-authored agent definition into the form Pi loads. */\nexport function adaptAgentDefinition(content: string): { name: string; content: string } {\n const { attributes, body } = splitFrontmatter(content);\n const rawName = typeof attributes.name === 'string' ? attributes.name : undefined;\n if (!rawName) throw new Error('Agent definition requires a name');\n const name = assertSafeAgentName(rawName);\n const hasTools = Object.hasOwn(attributes, 'tools');\n const rawTools = Array.isArray(attributes.tools)\n ? attributes.tools.map(String)\n : typeof attributes.tools === 'string'\n ? attributes.tools\n .split(',')\n .map((tool) => tool.trim())\n .filter(Boolean)\n : [];\n const mappedTools = [...new Set(rawTools.map(toPiToolName).filter((tool): tool is string => Boolean(tool)))];\n const converted: JsonObject = {\n ...attributes,\n inheritProjectContext: true,\n inheritSkills: true,\n systemPromptMode: attributes.systemPromptMode ?? 'replace',\n };\n if (hasTools) converted.tools = Array.isArray(attributes.tools) ? mappedTools : mappedTools.join(', ');\n else delete converted.tools;\n if (converted.model !== undefined) converted.model = normalizeClaudeModel(converted.model);\n if (converted.fallbackModels !== undefined) converted.fallbackModels = normalizeClaudeModel(converted.fallbackModels);\n if (converted.memory === 'project' || converted.memory === 'user')\n converted.memory = { scope: converted.memory, path: name };\n else if (\n converted.memory !== undefined &&\n (typeof converted.memory !== 'object' || converted.memory === null || Array.isArray(converted.memory))\n )\n throw new Error('Unsupported memory declaration');\n delete converted.permissionMode;\n return { name, content: `---\\n${stringify(converted).trim()}\\n---\\n\\n${body.trimStart()}` };\n}\n\nfunction skillManifestPath(\n repoRoot: string,\n skillRoot: string,\n discovery: PluginSkillDiscovery,\n cacheDirectory?: string,\n): string {\n const key = createHash('sha256')\n .update(`${path.resolve(skillRoot)}\\0${discovery}`)\n .digest('hex')\n .slice(0, SKILL_MANIFEST_HASH_LENGTH);\n return path.join(cacheDirectory ?? resolveSkillCacheDirectory(repoRoot), `${key}.json`);\n}\n\nfunction fileMatches(previous: SkillManifestFile): boolean {\n try {\n const stat = fs.statSync(previous.path);\n return (\n stat.isFile() &&\n stat.size === previous.size &&\n stat.mtimeMs === previous.mtimeMs &&\n stat.ctimeMs === previous.ctimeMs\n );\n } catch {\n return false;\n }\n}\n\nfunction directoryMatches(previous: SkillManifestDirectory): boolean {\n try {\n const stat = fs.statSync(previous.path);\n return stat.isDirectory() && stat.mtimeMs === previous.mtimeMs && stat.ctimeMs === previous.ctimeMs;\n } catch {\n return false;\n }\n}\n\nfunction readSkillManifest(\n manifestPath: string,\n root: string,\n discovery: PluginSkillDiscovery,\n): SkillManifest | undefined {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as SkillManifest;\n if (\n manifest.version !== SKILL_MANIFEST_VERSION ||\n manifest.root !== path.resolve(root) ||\n manifest.discovery !== discovery ||\n !Array.isArray(manifest.files) ||\n !Array.isArray(manifest.directories) ||\n !manifest.files.every(fileMatches) ||\n !manifest.directories.every(directoryMatches)\n ) {\n return undefined;\n }\n return manifest;\n } catch {\n return undefined;\n }\n}\n\nfunction writeSkillManifest(manifestPath: string, manifest: SkillManifest): void {\n fs.mkdirSync(path.dirname(manifestPath), { recursive: true, mode: 0o700 });\n const temporary = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n try {\n fs.renameSync(temporary, manifestPath);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(manifestPath)) throw error;\n }\n}\n\nasync function pathExists(target: string): Promise<boolean> {\n try {\n await fs.promises.access(target);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readSkillManifestAsync(\n manifestPath: string,\n root: string,\n discovery: PluginSkillDiscovery,\n): Promise<SkillManifest | undefined> {\n try {\n const manifest = JSON.parse(await fs.promises.readFile(manifestPath, 'utf8')) as SkillManifest;\n if (\n manifest.version !== SKILL_MANIFEST_VERSION ||\n manifest.root !== path.resolve(root) ||\n manifest.discovery !== discovery ||\n !Array.isArray(manifest.files) ||\n !Array.isArray(manifest.directories)\n ) {\n return undefined;\n }\n for (const previous of manifest.files) {\n const stat = await fs.promises.stat(previous.path);\n if (\n !stat.isFile() ||\n stat.size !== previous.size ||\n stat.mtimeMs !== previous.mtimeMs ||\n stat.ctimeMs !== previous.ctimeMs\n ) {\n return undefined;\n }\n }\n for (const previous of manifest.directories) {\n const stat = await fs.promises.stat(previous.path);\n if (!stat.isDirectory() || stat.mtimeMs !== previous.mtimeMs || stat.ctimeMs !== previous.ctimeMs) {\n return undefined;\n }\n }\n return manifest;\n } catch {\n return undefined;\n }\n}\n\nasync function writeSkillManifestAsync(manifestPath: string, manifest: SkillManifest): Promise<void> {\n await fs.promises.mkdir(path.dirname(manifestPath), { recursive: true, mode: 0o700 });\n const temporary = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;\n await fs.promises.writeFile(temporary, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n try {\n await fs.promises.rename(temporary, manifestPath);\n } catch (error) {\n await fs.promises.rm(temporary, { force: true });\n if (!(await pathExists(manifestPath))) throw error;\n }\n}\n\nfunction scanSkillManifest(root: string, discovery: PluginSkillDiscovery): SkillManifest {\n const directories: SkillManifestDirectory[] = [];\n const files: SkillManifestFile[] = [];\n const walk = (directory: string, depth: number): void => {\n if (!fs.existsSync(directory)) return;\n const directoryStat = fs.statSync(directory);\n directories.push({ path: directory, mtimeMs: directoryStat.mtimeMs, ctimeMs: directoryStat.ctimeMs });\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (discovery === 'recursive' || depth === 0) walk(candidate, depth + 1);\n continue;\n }\n if (!entry.isFile() || entry.name !== 'SKILL.md' || (discovery === 'direct-children' && depth !== 1)) {\n continue;\n }\n const content = fs.readFileSync(candidate, 'utf8');\n const { attributes } = splitFrontmatter(content);\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${candidate}`);\n const stat = fs.statSync(candidate);\n files.push({\n path: candidate,\n name: attributes.name,\n digest: createHash('sha256').update(content).digest('hex'),\n size: stat.size,\n mtimeMs: stat.mtimeMs,\n ctimeMs: stat.ctimeMs,\n });\n }\n };\n const resolvedRoot = path.resolve(root);\n walk(resolvedRoot, 0);\n files.sort((left, right) => left.path.localeCompare(right.path));\n directories.sort((left, right) => left.path.localeCompare(right.path));\n return { version: SKILL_MANIFEST_VERSION, root: resolvedRoot, discovery, files, directories };\n}\n\n/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */\nexport function discoverSkills(\n repoRoot: string,\n root: string,\n discovery: PluginSkillDiscovery = 'recursive',\n cacheDirectory?: string,\n): NamedResource[] {\n if (!fs.existsSync(root)) return [];\n const manifestPath = skillManifestPath(repoRoot, root, discovery, cacheDirectory);\n const cached = readSkillManifest(manifestPath, root, discovery);\n const manifest = cached ?? scanSkillManifest(root, discovery);\n if (!cached) writeSkillManifest(manifestPath, manifest);\n return manifest.files.map(({ name, path: filePath, digest }) => ({ name, path: filePath, digest }));\n}\n\nasync function scanSkillManifestAsync(root: string, discovery: PluginSkillDiscovery): Promise<SkillManifest> {\n const directories: SkillManifestDirectory[] = [];\n const files: SkillManifestFile[] = [];\n const walk = async (directory: string, depth: number): Promise<void> => {\n let entries: fs.Dirent[];\n try {\n const directoryStat = await fs.promises.stat(directory);\n directories.push({ path: directory, mtimeMs: directoryStat.mtimeMs, ctimeMs: directoryStat.ctimeMs });\n entries = await fs.promises.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n for (const entry of entries) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (discovery === 'recursive' || depth === 0) await walk(candidate, depth + 1);\n continue;\n }\n if (!entry.isFile() || entry.name !== 'SKILL.md' || (discovery === 'direct-children' && depth !== 1)) {\n continue;\n }\n const content = await fs.promises.readFile(candidate, 'utf8');\n const { attributes } = splitFrontmatter(content);\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${candidate}`);\n const stat = await fs.promises.stat(candidate);\n files.push({\n path: candidate,\n name: attributes.name,\n digest: createHash('sha256').update(content).digest('hex'),\n size: stat.size,\n mtimeMs: stat.mtimeMs,\n ctimeMs: stat.ctimeMs,\n });\n }\n };\n const resolvedRoot = path.resolve(root);\n await walk(resolvedRoot, 0);\n files.sort((left, right) => left.path.localeCompare(right.path));\n directories.sort((left, right) => left.path.localeCompare(right.path));\n return { version: SKILL_MANIFEST_VERSION, root: resolvedRoot, discovery, files, directories };\n}\n\nexport async function discoverSkillsAsync(\n repoRoot: string,\n root: string,\n discovery: PluginSkillDiscovery = 'recursive',\n cacheDirectory?: string,\n): Promise<NamedResource[]> {\n if (!(await pathExists(root))) return [];\n const manifestPath = skillManifestPath(repoRoot, root, discovery, cacheDirectory);\n const cached = await readSkillManifestAsync(manifestPath, root, discovery);\n const manifest = cached ?? (await scanSkillManifestAsync(root, discovery));\n if (!cached) await writeSkillManifestAsync(manifestPath, manifest);\n return manifest.files.map(({ name, path: filePath, digest }) => ({ name, path: filePath, digest }));\n}\n\nasync function markdownFilesAsync(directory: string): Promise<string[]> {\n let entries: fs.Dirent[];\n try {\n entries = await fs.promises.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n const results: string[] = [];\n for (const entry of entries) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...(await markdownFilesAsync(candidate)));\n if (entry.isFile() && entry.name.endsWith('.md')) results.push(candidate);\n }\n return results;\n}\n\nasync function frontmatterNameAsync(filePath: string): Promise<string> {\n const { attributes } = splitFrontmatter(await fs.promises.readFile(filePath, 'utf8'));\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${filePath}`);\n return attributes.name;\n}\n\nasync function assertUniqueAsync(resources: NamedResource[], kind: string): Promise<void> {\n const seen = new Map<string, string>();\n const digestByName = new Map<string, string>();\n for (const resource of resources) {\n const previous = seen.get(resource.name);\n const digest =\n resource.digest ??\n createHash('sha256')\n .update(await fs.promises.readFile(resource.path))\n .digest('hex');\n if (previous && digestByName.get(resource.name) !== digest) {\n throw new Error(`Conflicting ${kind} \"${resource.name}\": ${previous} and ${resource.path}`);\n }\n seen.set(resource.name, resource.path);\n digestByName.set(resource.name, digest);\n }\n}\n\nfunction dispatcherAgentSource(): string {\n const attributes: JsonObject = {\n name: DISPATCHER_AGENT_NAME,\n description: 'Selects and launches Agiflow workflows for one loop pass without implementing the work.',\n thinking: 'high',\n systemPromptMode: 'replace',\n inheritProjectContext: true,\n inheritSkills: true,\n tools: DISPATCHER_TOOLS.join(', '),\n // No feature extension is named here. Team inherits the ordered child\n // composition projected from the selected layers for every helper process.\n defaultContext: 'fresh',\n defaultProgress: false,\n };\n const body = [\n 'You are the Agiflow workflow dispatcher.',\n 'Reason about the supplied dispatch context and launch eligible workflows.',\n 'Launch workflows without monitoring them. After dispatching, report and exit.',\n 'Follow the task restrictions exactly. Do not implement jobs or edit repository files.',\n ].join('\\n');\n return `---\\n${stringify(attributes).trim()}\\n---\\n\\n${body}\\n`;\n}\n\nexport function mergeMcpConfigs(configPaths: string[]): JsonObject {\n const merged: JsonObject = { mcpServers: {} };\n const servers = merged.mcpServers as Record<string, unknown>;\n const sources = new Map<string, string>();\n for (const configPath of configPaths) {\n if (!fs.existsSync(configPath)) continue;\n const config = JSON.parse(fs.readFileSync(configPath, 'utf8')) as JsonObject;\n const incoming = (config.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, definition] of Object.entries(incoming)) {\n const previous = servers[name];\n if (previous && JSON.stringify(previous) !== JSON.stringify(definition)) {\n throw new Error(`Conflicting MCP server \"${name}\": ${sources.get(name)} and ${configPath}`);\n }\n servers[name] = definition;\n sources.set(name, configPath);\n }\n }\n return merged;\n}\n\nexport async function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject> {\n const merged: JsonObject = { mcpServers: {} };\n const servers = merged.mcpServers as Record<string, unknown>;\n const sources = new Map<string, string>();\n for (const configPath of configPaths) {\n let content: string;\n try {\n content = await fs.promises.readFile(configPath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;\n throw error;\n }\n const config = JSON.parse(content) as JsonObject;\n const incoming = (config.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, definition] of Object.entries(incoming)) {\n const previous = servers[name];\n if (previous && JSON.stringify(previous) !== JSON.stringify(definition)) {\n throw new Error(`Conflicting MCP server \"${name}\": ${sources.get(name)} and ${configPath}`);\n }\n servers[name] = definition;\n sources.set(name, configPath);\n }\n }\n return merged;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Matches a resource name against a subset filter. Undefined keeps everything. */\nfunction keepsName(allowed: string[] | undefined, name: string): boolean {\n if (!allowed) return true;\n return allowed.some((pattern) =>\n pattern.includes('*')\n ? new RegExp(`^${pattern.split('*').map(escapeRegExp).join('.*')}$`).test(name)\n : pattern === name,\n );\n}\n\n/**\n * Stages every resource the selected domains contribute, ready for one Pi session.\n *\n * The caller owns the returned cleanup(): the temporary directory holding agents\n * and the generated MCP config has to outlive this function and be removed once\n * the session that reads it is done.\n */\nexport async function collectResources(\n repoRoot: string,\n plugins: Array<string | PluginEntry>,\n options: HarnessResourceOptions,\n): Promise<HarnessResources> {\n const pluginEntries: PluginEntry[] = plugins.map((plugin) =>\n typeof plugin === 'string' ? { directory: plugin } : plugin,\n );\n // A caller-supplied directory is owned by the caller: it is either a live\n // session's directory or the synced one, and removing it here would delete\n // resources that outlive this collection.\n const ownsDirectory = options.temporaryDirectory === undefined;\n const temporaryDirectory =\n options.temporaryDirectory ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'doom-pi-')));\n await fs.promises.mkdir(temporaryDirectory, { mode: 0o700, recursive: true });\n await fs.promises.chmod(temporaryDirectory, 0o700);\n const sharedSkills = path.join(repoRoot, '.claude', 'skills');\n // A domain can opt out of the always-on shared skills to keep its context small.\n const sharedSkillSources =\n options.sharedSkills === false\n ? []\n : await discoverSkillsAsync(repoRoot, sharedSkills, 'recursive', options.skillCacheDirectory);\n const skillDirectories: string[] = [];\n const skillSources: NamedResource[] = [];\n const agentSources: Array<{ name: string; path: string }> = [];\n const pluginHooks: PluginHookSource[] = [];\n const pluginMcpConfigPaths: string[] = [];\n const mcpPaths = [path.join(repoRoot, '.mcp.json')];\n\n for (const entry of pluginEntries) {\n const pluginDirectory = entry.directory;\n const skills = path.join(pluginDirectory, 'skills');\n if (await pathExists(skills)) {\n const found = (\n await discoverSkillsAsync(repoRoot, skills, entry.skillDiscovery ?? 'recursive', options.skillCacheDirectory)\n ).filter((skill) => keepsName(entry.skills, skill.name));\n // Exact files let Pi skip another recursive traversal and make a plugin\n // subset unambiguous without staging copies of the skill bodies.\n skillDirectories.push(...found.map((skill) => skill.path));\n skillSources.push(...found);\n }\n const agents = path.join(pluginDirectory, 'agents');\n const agentFiles = await markdownFilesAsync(agents);\n const agentNames = await Promise.all(agentFiles.map((filePath) => frontmatterNameAsync(filePath)));\n agentSources.push(\n ...agentFiles\n .map((filePath, index) => ({ name: agentNames[index] ?? '', path: filePath }))\n .filter((agent) => keepsName(entry.agents, agent.name)),\n );\n const hookConfig = path.join(pluginDirectory, 'hooks', 'hooks.json');\n if (entry.hooks !== false && (await pathExists(hookConfig))) {\n pluginHooks.push({ pluginRoot: pluginDirectory, configPath: hookConfig });\n }\n const mcpConfig = path.join(pluginDirectory, '.mcp.json');\n if (entry.mcp !== false && (await pathExists(mcpConfig))) {\n mcpPaths.push(mcpConfig);\n pluginMcpConfigPaths.push(mcpConfig);\n }\n }\n\n await assertUniqueAsync(skillSources, 'skill');\n await assertUniqueAsync(sharedSkillSources, 'skill');\n // Pi keeps the first skill for a duplicated name. Selected domain plugins are\n // authoritative; shared Claude skills remain fallbacks for names no plugin owns.\n const pluginSkillNames = new Set(skillSources.map((skill) => skill.name));\n const fallbackSharedSkills = sharedSkillSources.filter((skill) => !pluginSkillNames.has(skill.name));\n skillDirectories.push(...fallbackSharedSkills.map((skill) => skill.path));\n skillSources.push(...fallbackSharedSkills);\n\n await assertUniqueAsync(agentSources, 'agent');\n if (agentSources.some((source) => source.name === DISPATCHER_AGENT_NAME)) {\n throw new Error(`Conflicting agent \"${DISPATCHER_AGENT_NAME}\": reserved by the agent harness`);\n }\n\n const agentDirectories: string[] = [];\n const outputDirectory = path.join(temporaryDirectory, 'agents');\n await fs.promises.rm(outputDirectory, { recursive: true, force: true });\n if (options.agents) {\n await fs.promises.mkdir(outputDirectory, { mode: 0o700 });\n for (const source of agentSources) {\n const adapted = adaptAgentDefinition(await fs.promises.readFile(source.path, 'utf8'));\n await fs.promises.writeFile(\n path.join(outputDirectory, `${assertSafeAgentName(adapted.name)}.md`),\n adapted.content,\n { mode: 0o600 },\n );\n }\n await fs.promises.writeFile(path.join(outputDirectory, `${DISPATCHER_AGENT_NAME}.md`), dispatcherAgentSource(), {\n mode: 0o600,\n });\n agentDirectories.push(outputDirectory);\n }\n\n let mcpConfigPath: string | undefined;\n if (options.mcp) {\n mcpConfigPath = path.join(temporaryDirectory, 'mcp.json');\n // Domains without an mcp allowlist resolve to undefined here, which leaves\n // the merged config untouched.\n const merged = await applyMcpAllowlist(\n await mergeMcpConfigsAsync(mcpPaths),\n options.mcpAllowlist,\n repoRoot,\n temporaryDirectory,\n );\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(merged, null, 2)}\\n`, {\n mode: 0o600,\n });\n }\n\n return {\n temporaryDirectory,\n skillDirectories,\n skillCount: skillSources.length,\n agentCount: agentSources.length,\n agentDirectories,\n pluginHooks,\n mcpConfigPath,\n pluginMcpConfigPaths,\n cleanup: () =>\n ownsDirectory ? fs.promises.rm(temporaryDirectory, { recursive: true, force: true }) : Promise.resolve(),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources, JsonObject, NamedResource } from "../types/resources.cjs";
|
|
2
|
+
import { PluginEntry, PluginSkillDiscovery } from "@agimon-ai/doompi-config/domains";
|
|
3
|
+
//#region src/adapters/resourceCollector.d.ts
|
|
4
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
/** Rewrites a Claude-authored agent definition into the form Pi loads. */
|
|
6
|
+
declare function adaptAgentDefinition(content: string): {
|
|
7
|
+
name: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */
|
|
11
|
+
declare function discoverSkills(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): NamedResource[];
|
|
12
|
+
declare function discoverSkillsAsync(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): Promise<NamedResource[]>;
|
|
13
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
14
|
+
declare function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject>;
|
|
15
|
+
/**
|
|
16
|
+
* Stages every resource the selected domains contribute, ready for one Pi session.
|
|
17
|
+
*
|
|
18
|
+
* The caller owns the returned cleanup(): the temporary directory holding agents
|
|
19
|
+
* and the generated MCP config has to outlive this function and be removed once
|
|
20
|
+
* the session that reads it is done.
|
|
21
|
+
*/
|
|
22
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, discoverSkills, discoverSkillsAsync, mergeMcpConfigs, mergeMcpConfigsAsync };
|
|
25
|
+
//# sourceMappingURL=resourceCollector.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.cts","names":[],"sources":["../../src/adapters/resourceCollector.ts"],"mappings":";;;cAYa;;iBA8DG,qBAAqB;EAAoB;EAAc;;;iBA8MvD,eACd,kBACA,cACA,YAAW,sBACX,0BACC;iBAoDmB,oBACpB,kBACA,cACA,YAAW,sBACX,0BACC,QAAQ;iBAyEK,gBAAgB,wBAAwB;iBAoBlC,qBAAqB,wBAAwB,QAAQ;;;;;;;;iBA+CrD,iBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,yBACR,QAAQ"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources, JsonObject, NamedResource } from "../types/resources.mjs";
|
|
2
|
+
import { PluginEntry, PluginSkillDiscovery } from "@agimon-ai/doompi-config/domains";
|
|
3
|
+
//#region src/adapters/resourceCollector.d.ts
|
|
4
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
/** Rewrites a Claude-authored agent definition into the form Pi loads. */
|
|
6
|
+
declare function adaptAgentDefinition(content: string): {
|
|
7
|
+
name: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */
|
|
11
|
+
declare function discoverSkills(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): NamedResource[];
|
|
12
|
+
declare function discoverSkillsAsync(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): Promise<NamedResource[]>;
|
|
13
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
14
|
+
declare function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject>;
|
|
15
|
+
/**
|
|
16
|
+
* Stages every resource the selected domains contribute, ready for one Pi session.
|
|
17
|
+
*
|
|
18
|
+
* The caller owns the returned cleanup(): the temporary directory holding agents
|
|
19
|
+
* and the generated MCP config has to outlive this function and be removed once
|
|
20
|
+
* the session that reads it is done.
|
|
21
|
+
*/
|
|
22
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, discoverSkills, discoverSkillsAsync, mergeMcpConfigs, mergeMcpConfigsAsync };
|
|
25
|
+
//# sourceMappingURL=resourceCollector.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.mts","names":[],"sources":["../../src/adapters/resourceCollector.ts"],"mappings":";;;cAYa;;iBA8DG,qBAAqB;EAAoB;EAAc;;;iBA8MvD,eACd,kBACA,cACA,YAAW,sBACX,0BACC;iBAoDmB,oBACpB,kBACA,cACA,YAAW,sBACX,0BACC,QAAQ;iBAyEK,gBAAgB,wBAAwB;iBAoBlC,qBAAqB,wBAAwB,QAAQ;;;;;;;;iBA+CrD,iBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,yBACR,QAAQ"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{applyMcpAllowlist as e}from"./mcpFilter.mjs";import{toPiToolName as t}from"../services/toolNames.mjs";import{resolveSkillCacheDirectory as n}from"./skillCacheLocation.mjs";import r from"node:path";import i from"node:fs";import{parse as a,stringify as o}from"yaml";import{createHash as s}from"node:crypto";import c from"node:os";const l=`agiflow-dispatcher`,u=[`read`,`grep`,`find`,`ls`,`bash`,`launch_workflow`,`list_workflows`];function d(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);if(!t)throw Error(`Resource is missing YAML frontmatter`);return{attributes:a(t[1]),body:t[2]??``}}const f={sonnet:`anthropic/claude-sonnet-4-6`,opus:`anthropic/claude-opus-4-6`,haiku:`anthropic/claude-haiku-4-5`};function p(e){let t=e.trim();if(!t||t!==e||t===`.`||t===`..`||t.includes(`\0`)||/[\\/]/.test(t))throw Error(`Unsafe agent name: ${JSON.stringify(e)}`);return t}function m(e){return typeof e==`string`?f[e.toLowerCase()]??e:Array.isArray(e)?e.map(e=>m(e)):e}function h(e){let{attributes:n,body:r}=d(e),i=typeof n.name==`string`?n.name:void 0;if(!i)throw Error(`Agent definition requires a name`);let a=p(i),s=Object.hasOwn(n,`tools`),c=Array.isArray(n.tools)?n.tools.map(String):typeof n.tools==`string`?n.tools.split(`,`).map(e=>e.trim()).filter(Boolean):[],l=[...new Set(c.map(t).filter(e=>!!e))],u={...n,inheritProjectContext:!0,inheritSkills:!0,systemPromptMode:n.systemPromptMode??`replace`};if(s?u.tools=Array.isArray(n.tools)?l:l.join(`, `):delete u.tools,u.model!==void 0&&(u.model=m(u.model)),u.fallbackModels!==void 0&&(u.fallbackModels=m(u.fallbackModels)),u.memory===`project`||u.memory===`user`)u.memory={scope:u.memory,path:a};else if(u.memory!==void 0&&(typeof u.memory!=`object`||u.memory===null||Array.isArray(u.memory)))throw Error(`Unsupported memory declaration`);return delete u.permissionMode,{name:a,content:`---\n${o(u).trim()}\n---\n\n${r.trimStart()}`}}function g(e,t,i,a){let o=s(`sha256`).update(`${r.resolve(t)}\0${i}`).digest(`hex`).slice(0,16);return r.join(a??n(e),`${o}.json`)}function _(e){try{let t=i.statSync(e.path);return t.isFile()&&t.size===e.size&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function v(e){try{let t=i.statSync(e.path);return t.isDirectory()&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function y(e,t,n){try{let a=JSON.parse(i.readFileSync(e,`utf8`));return a.version!==2||a.root!==r.resolve(t)||a.discovery!==n||!Array.isArray(a.files)||!Array.isArray(a.directories)||!a.files.every(_)||!a.directories.every(v)?void 0:a}catch{return}}function b(e,t){i.mkdirSync(r.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;i.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{i.renameSync(n,e)}catch(t){if(i.rmSync(n,{force:!0}),!i.existsSync(e))throw t}}async function x(e){try{return await i.promises.access(e),!0}catch{return!1}}async function S(e,t,n){try{let a=JSON.parse(await i.promises.readFile(e,`utf8`));if(a.version!==2||a.root!==r.resolve(t)||a.discovery!==n||!Array.isArray(a.files)||!Array.isArray(a.directories))return;for(let e of a.files){let t=await i.promises.stat(e.path);if(!t.isFile()||t.size!==e.size||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}for(let e of a.directories){let t=await i.promises.stat(e.path);if(!t.isDirectory()||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}return a}catch{return}}async function C(e,t){await i.promises.mkdir(r.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;await i.promises.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{await i.promises.rename(n,e)}catch(t){if(await i.promises.rm(n,{force:!0}),!await x(e))throw t}}function w(e,t){let n=[],a=[],o=(e,c)=>{if(!i.existsSync(e))return;let l=i.statSync(e);n.push({path:e,mtimeMs:l.mtimeMs,ctimeMs:l.ctimeMs});for(let n of i.readdirSync(e,{withFileTypes:!0})){let l=r.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=i.readFileSync(l,`utf8`),{attributes:f}=d(u);if(typeof f.name!=`string`)throw Error(`Resource requires a name: ${l}`);let p=i.statSync(l);a.push({path:l,name:f.name,digest:s(`sha256`).update(u).digest(`hex`),size:p.size,mtimeMs:p.mtimeMs,ctimeMs:p.ctimeMs})}},c=r.resolve(e);return o(c,0),a.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:a,directories:n}}function T(e,t,n=`recursive`,r){if(!i.existsSync(t))return[];let a=g(e,t,n,r),o=y(a,t,n),s=o??w(t,n);return o||b(a,s),s.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function E(e,t){let n=[],a=[],o=async(e,c)=>{let l;try{let t=await i.promises.stat(e);n.push({path:e,mtimeMs:t.mtimeMs,ctimeMs:t.ctimeMs}),l=await i.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}for(let n of l){let l=r.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&await o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=await i.promises.readFile(l,`utf8`),{attributes:f}=d(u);if(typeof f.name!=`string`)throw Error(`Resource requires a name: ${l}`);let p=await i.promises.stat(l);a.push({path:l,name:f.name,digest:s(`sha256`).update(u).digest(`hex`),size:p.size,mtimeMs:p.mtimeMs,ctimeMs:p.ctimeMs})}},c=r.resolve(e);return await o(c,0),a.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:a,directories:n}}async function D(e,t,n=`recursive`,r){if(!await x(t))return[];let i=g(e,t,n,r),a=await S(i,t,n),o=a??await E(t,n);return a||await C(i,o),o.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function O(e){let t;try{t=await i.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let n=[];for(let i of t){let t=r.join(e,i.name);i.isDirectory()&&n.push(...await O(t)),i.isFile()&&i.name.endsWith(`.md`)&&n.push(t)}return n}async function k(e){let{attributes:t}=d(await i.promises.readFile(e,`utf8`));if(typeof t.name!=`string`)throw Error(`Resource requires a name: ${e}`);return t.name}async function A(e,t){let n=new Map,r=new Map;for(let a of e){let e=n.get(a.name),o=a.digest??s(`sha256`).update(await i.promises.readFile(a.path)).digest(`hex`);if(e&&r.get(a.name)!==o)throw Error(`Conflicting ${t} "${a.name}": ${e} and ${a.path}`);n.set(a.name,a.path),r.set(a.name,o)}}function j(){let e={name:l,description:`Selects and launches Agiflow workflows for one loop pass without implementing the work.`,thinking:`high`,systemPromptMode:`replace`,inheritProjectContext:!0,inheritSkills:!0,tools:u.join(`, `),defaultContext:`fresh`,defaultProgress:!1},t=[`You are the Agiflow workflow dispatcher.`,`Reason about the supplied dispatch context and launch eligible workflows.`,`Launch workflows without monitoring them. After dispatching, report and exit.`,`Follow the task restrictions exactly. Do not implement jobs or edit repository files.`].join(`
|
|
2
|
+
`);return`---\n${o(e).trim()}\n---\n\n${t}\n`}function M(e){let t={mcpServers:{}},n=t.mcpServers,r=new Map;for(let t of e){if(!i.existsSync(t))continue;let e=JSON.parse(i.readFileSync(t,`utf8`)).mcpServers??{};for(let[i,a]of Object.entries(e)){let e=n[i];if(e&&JSON.stringify(e)!==JSON.stringify(a))throw Error(`Conflicting MCP server "${i}": ${r.get(i)} and ${t}`);n[i]=a,r.set(i,t)}}return t}async function N(e){let t={mcpServers:{}},n=t.mcpServers,r=new Map;for(let t of e){let e;try{e=await i.promises.readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)continue;throw e}let a=JSON.parse(e).mcpServers??{};for(let[e,i]of Object.entries(a)){let a=n[e];if(a&&JSON.stringify(a)!==JSON.stringify(i))throw Error(`Conflicting MCP server "${e}": ${r.get(e)} and ${t}`);n[e]=i,r.set(e,t)}}return t}function P(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function F(e,t){return!e||e.some(e=>e.includes(`*`)?RegExp(`^${e.split(`*`).map(P).join(`.*`)}$`).test(t):e===t)}async function I(t,n,a){let o=n.map(e=>typeof e==`string`?{directory:e}:e),s=a.temporaryDirectory===void 0,u=a.temporaryDirectory??await i.promises.mkdtemp(r.join(c.tmpdir(),`doom-pi-`));await i.promises.mkdir(u,{mode:448,recursive:!0}),await i.promises.chmod(u,448);let d=r.join(t,`.claude`,`skills`),f=a.sharedSkills===!1?[]:await D(t,d,`recursive`,a.skillCacheDirectory),m=[],g=[],_=[],v=[],y=[],b=[r.join(t,`.mcp.json`)];for(let e of o){let n=e.directory,i=r.join(n,`skills`);if(await x(i)){let n=(await D(t,i,e.skillDiscovery??`recursive`,a.skillCacheDirectory)).filter(t=>F(e.skills,t.name));m.push(...n.map(e=>e.path)),g.push(...n)}let o=await O(r.join(n,`agents`)),s=await Promise.all(o.map(e=>k(e)));_.push(...o.map((e,t)=>({name:s[t]??``,path:e})).filter(t=>F(e.agents,t.name)));let c=r.join(n,`hooks`,`hooks.json`);e.hooks!==!1&&await x(c)&&v.push({pluginRoot:n,configPath:c});let l=r.join(n,`.mcp.json`);e.mcp!==!1&&await x(l)&&(b.push(l),y.push(l))}await A(g,`skill`),await A(f,`skill`);let S=new Set(g.map(e=>e.name)),C=f.filter(e=>!S.has(e.name));if(m.push(...C.map(e=>e.path)),g.push(...C),await A(_,`agent`),_.some(e=>e.name===`agiflow-dispatcher`))throw Error(`Conflicting agent "${l}": reserved by the agent harness`);let w=[],T=r.join(u,`agents`);if(await i.promises.rm(T,{recursive:!0,force:!0}),a.agents){await i.promises.mkdir(T,{mode:448});for(let e of _){let t=h(await i.promises.readFile(e.path,`utf8`));await i.promises.writeFile(r.join(T,`${p(t.name)}.md`),t.content,{mode:384})}await i.promises.writeFile(r.join(T,`${l}.md`),j(),{mode:384}),w.push(T)}let E;if(a.mcp){E=r.join(u,`mcp.json`);let n=await e(await N(b),a.mcpAllowlist,t,u);await i.promises.writeFile(E,`${JSON.stringify(n,null,2)}\n`,{mode:384})}return{temporaryDirectory:u,skillDirectories:m,skillCount:g.length,agentCount:_.length,agentDirectories:w,pluginHooks:v,mcpConfigPath:E,pluginMcpConfigPaths:y,cleanup:()=>s?i.promises.rm(u,{recursive:!0,force:!0}):Promise.resolve()}}export{l as DISPATCHER_AGENT_NAME,h as adaptAgentDefinition,I as collectResources,T as discoverSkills,D as discoverSkillsAsync,M as mergeMcpConfigs,N as mergeMcpConfigsAsync};
|
|
3
|
+
//# sourceMappingURL=resourceCollector.mjs.map
|