@agimon-ai/doompi 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +546 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/bin/cli.cjs +3 -0
- package/dist/bin/cli.cjs.map +1 -0
- package/dist/bin/cli.d.cts +1 -0
- package/dist/bin/cli.d.mts +1 -0
- package/dist/bin/cli.mjs +3 -0
- package/dist/bin/cli.mjs.map +1 -0
- package/dist/bin/doomRunner.cjs +3 -0
- package/dist/bin/doomRunner.cjs.map +1 -0
- package/dist/bin/doomRunner.d.cts +1 -0
- package/dist/bin/doomRunner.d.mts +1 -0
- package/dist/bin/doomRunner.mjs +3 -0
- package/dist/bin/doomRunner.mjs.map +1 -0
- package/dist/cli/cliApp.cjs +2 -0
- package/dist/cli/cliApp.cjs.map +1 -0
- package/dist/cli/cliApp.d.cts +50 -0
- package/dist/cli/cliApp.d.cts.map +1 -0
- package/dist/cli/cliApp.d.mts +50 -0
- package/dist/cli/cliApp.d.mts.map +1 -0
- package/dist/cli/cliApp.mjs +2 -0
- package/dist/cli/cliApp.mjs.map +1 -0
- package/dist/cli/compatibilityOptions.cjs +2 -0
- package/dist/cli/compatibilityOptions.cjs.map +1 -0
- package/dist/cli/compatibilityOptions.d.cts +15 -0
- package/dist/cli/compatibilityOptions.d.cts.map +1 -0
- package/dist/cli/compatibilityOptions.d.mts +15 -0
- package/dist/cli/compatibilityOptions.d.mts.map +1 -0
- package/dist/cli/compatibilityOptions.mjs +2 -0
- package/dist/cli/compatibilityOptions.mjs.map +1 -0
- package/dist/cli/help.cjs +61 -0
- package/dist/cli/help.cjs.map +1 -0
- package/dist/cli/help.d.cts +6 -0
- package/dist/cli/help.d.cts.map +1 -0
- package/dist/cli/help.d.mts +6 -0
- package/dist/cli/help.d.mts.map +1 -0
- package/dist/cli/help.mjs +61 -0
- package/dist/cli/help.mjs.map +1 -0
- package/dist/cli/index.cjs +1 -0
- package/dist/cli/index.d.cts +5 -0
- package/dist/cli/index.d.mts +5 -0
- package/dist/cli/index.mjs +1 -0
- package/dist/cli/matrixOptions.cjs +2 -0
- package/dist/cli/matrixOptions.cjs.map +1 -0
- package/dist/cli/matrixOptions.d.cts +99 -0
- package/dist/cli/matrixOptions.d.cts.map +1 -0
- package/dist/cli/matrixOptions.d.mts +99 -0
- package/dist/cli/matrixOptions.d.mts.map +1 -0
- package/dist/cli/matrixOptions.mjs +2 -0
- package/dist/cli/matrixOptions.mjs.map +1 -0
- package/dist/cli/options.cjs +2 -0
- package/dist/cli/options.cjs.map +1 -0
- package/dist/cli/options.d.cts +7 -0
- package/dist/cli/options.d.cts.map +1 -0
- package/dist/cli/options.d.mts +7 -0
- package/dist/cli/options.d.mts.map +1 -0
- package/dist/cli/options.mjs +2 -0
- package/dist/cli/options.mjs.map +1 -0
- package/dist/commands/baseCommand.cjs +2 -0
- package/dist/commands/baseCommand.cjs.map +1 -0
- package/dist/commands/baseCommand.d.cts +36 -0
- package/dist/commands/baseCommand.d.cts.map +1 -0
- package/dist/commands/baseCommand.d.mts +36 -0
- package/dist/commands/baseCommand.d.mts.map +1 -0
- package/dist/commands/baseCommand.mjs +2 -0
- package/dist/commands/baseCommand.mjs.map +1 -0
- package/dist/commands/compatibilityCommand.cjs +2 -0
- package/dist/commands/compatibilityCommand.cjs.map +1 -0
- package/dist/commands/compatibilityCommand.d.cts +14 -0
- package/dist/commands/compatibilityCommand.d.cts.map +1 -0
- package/dist/commands/compatibilityCommand.d.mts +14 -0
- package/dist/commands/compatibilityCommand.d.mts.map +1 -0
- package/dist/commands/compatibilityCommand.mjs +2 -0
- package/dist/commands/compatibilityCommand.mjs.map +1 -0
- package/dist/commands/emitMcpCommand.cjs +2 -0
- package/dist/commands/emitMcpCommand.cjs.map +1 -0
- package/dist/commands/emitMcpCommand.d.cts +19 -0
- package/dist/commands/emitMcpCommand.d.cts.map +1 -0
- package/dist/commands/emitMcpCommand.d.mts +19 -0
- package/dist/commands/emitMcpCommand.d.mts.map +1 -0
- package/dist/commands/emitMcpCommand.mjs +2 -0
- package/dist/commands/emitMcpCommand.mjs.map +1 -0
- package/dist/commands/explainCommand.cjs +21 -0
- package/dist/commands/explainCommand.cjs.map +1 -0
- package/dist/commands/explainCommand.d.cts +63 -0
- package/dist/commands/explainCommand.d.cts.map +1 -0
- package/dist/commands/explainCommand.d.mts +63 -0
- package/dist/commands/explainCommand.d.mts.map +1 -0
- package/dist/commands/explainCommand.mjs +21 -0
- package/dist/commands/explainCommand.mjs.map +1 -0
- package/dist/commands/index.cjs +1 -0
- package/dist/commands/index.d.cts +8 -0
- package/dist/commands/index.d.mts +8 -0
- package/dist/commands/index.mjs +1 -0
- package/dist/commands/initCommand.cjs +3 -0
- package/dist/commands/initCommand.cjs.map +1 -0
- package/dist/commands/initCommand.d.cts +11 -0
- package/dist/commands/initCommand.d.cts.map +1 -0
- package/dist/commands/initCommand.d.mts +11 -0
- package/dist/commands/initCommand.d.mts.map +1 -0
- package/dist/commands/initCommand.mjs +3 -0
- package/dist/commands/initCommand.mjs.map +1 -0
- package/dist/commands/launchCommand.cjs +2 -0
- package/dist/commands/launchCommand.cjs.map +1 -0
- package/dist/commands/launchCommand.d.cts +31 -0
- package/dist/commands/launchCommand.d.cts.map +1 -0
- package/dist/commands/launchCommand.d.mts +31 -0
- package/dist/commands/launchCommand.d.mts.map +1 -0
- package/dist/commands/launchCommand.mjs +2 -0
- package/dist/commands/launchCommand.mjs.map +1 -0
- package/dist/commands/syncCommand.cjs +6 -0
- package/dist/commands/syncCommand.cjs.map +1 -0
- package/dist/commands/syncCommand.d.cts +37 -0
- package/dist/commands/syncCommand.d.cts.map +1 -0
- package/dist/commands/syncCommand.d.mts +37 -0
- package/dist/commands/syncCommand.d.mts.map +1 -0
- package/dist/commands/syncCommand.mjs +6 -0
- package/dist/commands/syncCommand.mjs.map +1 -0
- package/dist/config/harnessState.cjs +2 -0
- package/dist/config/harnessState.cjs.map +1 -0
- package/dist/config/harnessState.d.cts +24 -0
- package/dist/config/harnessState.d.cts.map +1 -0
- package/dist/config/harnessState.d.mts +24 -0
- package/dist/config/harnessState.d.mts.map +1 -0
- package/dist/config/harnessState.mjs +2 -0
- package/dist/config/harnessState.mjs.map +1 -0
- package/dist/config/index.cjs +1 -0
- package/dist/config/index.d.cts +7 -0
- package/dist/config/index.d.mts +7 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/projectTrust.cjs +2 -0
- package/dist/config/projectTrust.cjs.map +1 -0
- package/dist/config/projectTrust.d.cts +14 -0
- package/dist/config/projectTrust.d.cts.map +1 -0
- package/dist/config/projectTrust.d.mts +14 -0
- package/dist/config/projectTrust.d.mts.map +1 -0
- package/dist/config/projectTrust.mjs +2 -0
- package/dist/config/projectTrust.mjs.map +1 -0
- package/dist/entries/autoStop.cjs +2 -0
- package/dist/entries/autoStop.cjs.map +1 -0
- package/dist/entries/autoStop.d.cts +6 -0
- package/dist/entries/autoStop.d.cts.map +1 -0
- package/dist/entries/autoStop.d.mts +7 -0
- package/dist/entries/autoStop.d.mts.map +1 -0
- package/dist/entries/autoStop.mjs +2 -0
- package/dist/entries/autoStop.mjs.map +1 -0
- package/dist/entries/components/matrixPicker.cjs +2 -0
- package/dist/entries/components/matrixPicker.cjs.map +1 -0
- package/dist/entries/components/matrixPicker.d.cts +55 -0
- package/dist/entries/components/matrixPicker.d.cts.map +1 -0
- package/dist/entries/components/matrixPicker.d.mts +55 -0
- package/dist/entries/components/matrixPicker.d.mts.map +1 -0
- package/dist/entries/components/matrixPicker.mjs +2 -0
- package/dist/entries/components/matrixPicker.mjs.map +1 -0
- package/dist/entries/components/skillsOverlay.cjs +4 -0
- package/dist/entries/components/skillsOverlay.cjs.map +1 -0
- package/dist/entries/components/skillsOverlay.d.cts +58 -0
- package/dist/entries/components/skillsOverlay.d.cts.map +1 -0
- package/dist/entries/components/skillsOverlay.d.mts +58 -0
- package/dist/entries/components/skillsOverlay.d.mts.map +1 -0
- package/dist/entries/components/skillsOverlay.mjs +4 -0
- package/dist/entries/components/skillsOverlay.mjs.map +1 -0
- package/dist/entries/domains.cjs +2 -0
- package/dist/entries/domains.cjs.map +1 -0
- package/dist/entries/domains.d.cts +10 -0
- package/dist/entries/domains.d.cts.map +1 -0
- package/dist/entries/domains.d.mts +10 -0
- package/dist/entries/domains.d.mts.map +1 -0
- package/dist/entries/domains.mjs +2 -0
- package/dist/entries/domains.mjs.map +1 -0
- package/dist/entries/doom.cjs +2 -0
- package/dist/entries/doom.cjs.map +1 -0
- package/dist/entries/doom.d.cts +13 -0
- package/dist/entries/doom.d.cts.map +1 -0
- package/dist/entries/doom.d.mts +14 -0
- package/dist/entries/doom.d.mts.map +1 -0
- package/dist/entries/doom.mjs +2 -0
- package/dist/entries/doom.mjs.map +1 -0
- package/dist/entries/effort.cjs +2 -0
- package/dist/entries/effort.cjs.map +1 -0
- package/dist/entries/effort.d.cts +10 -0
- package/dist/entries/effort.d.cts.map +1 -0
- package/dist/entries/effort.d.mts +10 -0
- package/dist/entries/effort.d.mts.map +1 -0
- package/dist/entries/effort.mjs +2 -0
- package/dist/entries/effort.mjs.map +1 -0
- package/dist/entries/majorMode.cjs +6 -0
- package/dist/entries/majorMode.cjs.map +1 -0
- package/dist/entries/majorMode.d.cts +29 -0
- package/dist/entries/majorMode.d.cts.map +1 -0
- package/dist/entries/majorMode.d.mts +29 -0
- package/dist/entries/majorMode.d.mts.map +1 -0
- package/dist/entries/majorMode.mjs +6 -0
- package/dist/entries/majorMode.mjs.map +1 -0
- package/dist/entries/notifications.cjs +2 -0
- package/dist/entries/notifications.cjs.map +1 -0
- package/dist/entries/notifications.d.cts +13 -0
- package/dist/entries/notifications.d.cts.map +1 -0
- package/dist/entries/notifications.d.mts +13 -0
- package/dist/entries/notifications.d.mts.map +1 -0
- package/dist/entries/notifications.mjs +2 -0
- package/dist/entries/notifications.mjs.map +1 -0
- package/dist/entries/ollamaProvider.cjs +2 -0
- package/dist/entries/ollamaProvider.cjs.map +1 -0
- package/dist/entries/ollamaProvider.d.cts +6 -0
- package/dist/entries/ollamaProvider.d.cts.map +1 -0
- package/dist/entries/ollamaProvider.d.mts +7 -0
- package/dist/entries/ollamaProvider.d.mts.map +1 -0
- package/dist/entries/ollamaProvider.mjs +2 -0
- package/dist/entries/ollamaProvider.mjs.map +1 -0
- package/dist/entries/persona.cjs +2 -0
- package/dist/entries/persona.cjs.map +1 -0
- package/dist/entries/persona.d.cts +14 -0
- package/dist/entries/persona.d.cts.map +1 -0
- package/dist/entries/persona.d.mts +15 -0
- package/dist/entries/persona.d.mts.map +1 -0
- package/dist/entries/persona.mjs +2 -0
- package/dist/entries/persona.mjs.map +1 -0
- package/dist/entries/profile.cjs +3 -0
- package/dist/entries/profile.cjs.map +1 -0
- package/dist/entries/profile.d.cts +16 -0
- package/dist/entries/profile.d.cts.map +1 -0
- package/dist/entries/profile.d.mts +16 -0
- package/dist/entries/profile.d.mts.map +1 -0
- package/dist/entries/profile.mjs +3 -0
- package/dist/entries/profile.mjs.map +1 -0
- package/dist/entries/repositoryHooks.cjs +9 -0
- package/dist/entries/repositoryHooks.cjs.map +1 -0
- package/dist/entries/repositoryHooks.d.cts +7 -0
- package/dist/entries/repositoryHooks.d.cts.map +1 -0
- package/dist/entries/repositoryHooks.d.mts +8 -0
- package/dist/entries/repositoryHooks.d.mts.map +1 -0
- package/dist/entries/repositoryHooks.mjs +9 -0
- package/dist/entries/repositoryHooks.mjs.map +1 -0
- package/dist/entries/skills.cjs +2 -0
- package/dist/entries/skills.cjs.map +1 -0
- package/dist/entries/skills.d.cts +34 -0
- package/dist/entries/skills.d.cts.map +1 -0
- package/dist/entries/skills.d.mts +34 -0
- package/dist/entries/skills.d.mts.map +1 -0
- package/dist/entries/skills.mjs +2 -0
- package/dist/entries/skills.mjs.map +1 -0
- package/dist/entries/styleSystem.cjs +4 -0
- package/dist/entries/styleSystem.cjs.map +1 -0
- package/dist/entries/styleSystem.d.cts +32 -0
- package/dist/entries/styleSystem.d.cts.map +1 -0
- package/dist/entries/styleSystem.d.mts +32 -0
- package/dist/entries/styleSystem.d.mts.map +1 -0
- package/dist/entries/styleSystem.mjs +4 -0
- package/dist/entries/styleSystem.mjs.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +34 -0
- package/dist/index.d.mts +34 -0
- package/dist/index.mjs +1 -0
- package/dist/interfaces/compatibility.d.cts +23 -0
- package/dist/interfaces/compatibility.d.cts.map +1 -0
- package/dist/interfaces/compatibility.d.mts +23 -0
- package/dist/interfaces/compatibility.d.mts.map +1 -0
- package/dist/interfaces/harness.d.cts +83 -0
- package/dist/interfaces/harness.d.cts.map +1 -0
- package/dist/interfaces/harness.d.mts +83 -0
- package/dist/interfaces/harness.d.mts.map +1 -0
- package/dist/logSinkTelemetry.cjs +2 -0
- package/dist/logSinkTelemetry.cjs.map +1 -0
- package/dist/logSinkTelemetry.d.cts +49 -0
- package/dist/logSinkTelemetry.d.cts.map +1 -0
- package/dist/logSinkTelemetry.d.mts +49 -0
- package/dist/logSinkTelemetry.d.mts.map +1 -0
- package/dist/logSinkTelemetry.mjs +2 -0
- package/dist/logSinkTelemetry.mjs.map +1 -0
- package/dist/node_modules/.pnpm/@juicesharp_rpiv-ask-user-question@2.2.0_@earendil-works_pi-coding-agent@0.84.1_support_6ba1249e24a50b62791c1c91c9f324c6/node_modules/@juicesharp/rpiv-ask-user-question/events.cjs +2 -0
- package/dist/node_modules/.pnpm/@juicesharp_rpiv-ask-user-question@2.2.0_@earendil-works_pi-coding-agent@0.84.1_support_6ba1249e24a50b62791c1c91c9f324c6/node_modules/@juicesharp/rpiv-ask-user-question/events.cjs.map +1 -0
- package/dist/node_modules/.pnpm/@juicesharp_rpiv-ask-user-question@2.2.0_@earendil-works_pi-coding-agent@0.84.1_support_6ba1249e24a50b62791c1c91c9f324c6/node_modules/@juicesharp/rpiv-ask-user-question/events.mjs +2 -0
- package/dist/node_modules/.pnpm/@juicesharp_rpiv-ask-user-question@2.2.0_@earendil-works_pi-coding-agent@0.84.1_support_6ba1249e24a50b62791c1c91c9f324c6/node_modules/@juicesharp/rpiv-ask-user-question/events.mjs.map +1 -0
- package/dist/services/compatibility/antigravity.cjs +2 -0
- package/dist/services/compatibility/antigravity.cjs.map +1 -0
- package/dist/services/compatibility/antigravity.d.cts +11 -0
- package/dist/services/compatibility/antigravity.d.cts.map +1 -0
- package/dist/services/compatibility/antigravity.d.mts +11 -0
- package/dist/services/compatibility/antigravity.d.mts.map +1 -0
- package/dist/services/compatibility/antigravity.mjs +2 -0
- package/dist/services/compatibility/antigravity.mjs.map +1 -0
- package/dist/services/compatibility/codex.cjs +2 -0
- package/dist/services/compatibility/codex.cjs.map +1 -0
- package/dist/services/compatibility/codex.d.cts +19 -0
- package/dist/services/compatibility/codex.d.cts.map +1 -0
- package/dist/services/compatibility/codex.d.mts +19 -0
- package/dist/services/compatibility/codex.d.mts.map +1 -0
- package/dist/services/compatibility/codex.mjs +2 -0
- package/dist/services/compatibility/codex.mjs.map +1 -0
- package/dist/services/compatibility/index.cjs +2 -0
- package/dist/services/compatibility/index.cjs.map +1 -0
- package/dist/services/compatibility/index.d.cts +16 -0
- package/dist/services/compatibility/index.d.cts.map +1 -0
- package/dist/services/compatibility/index.d.mts +16 -0
- package/dist/services/compatibility/index.d.mts.map +1 -0
- package/dist/services/compatibility/index.mjs +2 -0
- package/dist/services/compatibility/index.mjs.map +1 -0
- package/dist/services/compatibility/process.cjs +2 -0
- package/dist/services/compatibility/process.cjs.map +1 -0
- package/dist/services/compatibility/process.d.cts +35 -0
- package/dist/services/compatibility/process.d.cts.map +1 -0
- package/dist/services/compatibility/process.d.mts +35 -0
- package/dist/services/compatibility/process.d.mts.map +1 -0
- package/dist/services/compatibility/process.mjs +2 -0
- package/dist/services/compatibility/process.mjs.map +1 -0
- package/dist/services/compatibility/shared.cjs +2 -0
- package/dist/services/compatibility/shared.cjs.map +1 -0
- package/dist/services/compatibility/shared.d.cts +33 -0
- package/dist/services/compatibility/shared.d.cts.map +1 -0
- package/dist/services/compatibility/shared.d.mts +33 -0
- package/dist/services/compatibility/shared.d.mts.map +1 -0
- package/dist/services/compatibility/shared.mjs +2 -0
- package/dist/services/compatibility/shared.mjs.map +1 -0
- package/dist/services/compatibilityContext.cjs +2 -0
- package/dist/services/compatibilityContext.cjs.map +1 -0
- package/dist/services/compatibilityContext.d.cts +23 -0
- package/dist/services/compatibilityContext.d.cts.map +1 -0
- package/dist/services/compatibilityContext.d.mts +23 -0
- package/dist/services/compatibilityContext.d.mts.map +1 -0
- package/dist/services/compatibilityContext.mjs +2 -0
- package/dist/services/compatibilityContext.mjs.map +1 -0
- package/dist/services/composer.cjs +2 -0
- package/dist/services/composer.cjs.map +1 -0
- package/dist/services/composer.d.cts +133 -0
- package/dist/services/composer.d.cts.map +1 -0
- package/dist/services/composer.d.mts +133 -0
- package/dist/services/composer.d.mts.map +1 -0
- package/dist/services/composer.mjs +2 -0
- package/dist/services/composer.mjs.map +1 -0
- package/dist/services/extensionAssembler.cjs +2 -0
- package/dist/services/extensionAssembler.cjs.map +1 -0
- package/dist/services/extensionAssembler.d.cts +72 -0
- package/dist/services/extensionAssembler.d.cts.map +1 -0
- package/dist/services/extensionAssembler.d.mts +72 -0
- package/dist/services/extensionAssembler.d.mts.map +1 -0
- package/dist/services/extensionAssembler.mjs +2 -0
- package/dist/services/extensionAssembler.mjs.map +1 -0
- package/dist/services/extensionCompiler.cjs +2 -0
- package/dist/services/extensionCompiler.cjs.map +1 -0
- package/dist/services/extensionCompiler.mjs +2 -0
- package/dist/services/extensionCompiler.mjs.map +1 -0
- package/dist/services/harnessContext.cjs +2 -0
- package/dist/services/harnessContext.cjs.map +1 -0
- package/dist/services/harnessContext.d.cts +61 -0
- package/dist/services/harnessContext.d.cts.map +1 -0
- package/dist/services/harnessContext.d.mts +61 -0
- package/dist/services/harnessContext.d.mts.map +1 -0
- package/dist/services/harnessContext.mjs +2 -0
- package/dist/services/harnessContext.mjs.map +1 -0
- package/dist/services/index.cjs +1 -0
- package/dist/services/index.d.cts +14 -0
- package/dist/services/index.d.mts +14 -0
- package/dist/services/index.mjs +1 -0
- package/dist/services/matrixSwitcher.cjs +2 -0
- package/dist/services/matrixSwitcher.cjs.map +1 -0
- package/dist/services/matrixSwitcher.d.cts +46 -0
- package/dist/services/matrixSwitcher.d.cts.map +1 -0
- package/dist/services/matrixSwitcher.d.mts +46 -0
- package/dist/services/matrixSwitcher.d.mts.map +1 -0
- package/dist/services/matrixSwitcher.mjs +2 -0
- package/dist/services/matrixSwitcher.mjs.map +1 -0
- package/dist/services/mcpFilter.cjs +3 -0
- package/dist/services/mcpFilter.cjs.map +1 -0
- package/dist/services/mcpFilter.d.cts +40 -0
- package/dist/services/mcpFilter.d.cts.map +1 -0
- package/dist/services/mcpFilter.d.mts +40 -0
- package/dist/services/mcpFilter.d.mts.map +1 -0
- package/dist/services/mcpFilter.mjs +3 -0
- package/dist/services/mcpFilter.mjs.map +1 -0
- package/dist/services/piSettings.cjs +2 -0
- package/dist/services/piSettings.cjs.map +1 -0
- package/dist/services/piSettings.d.cts +24 -0
- package/dist/services/piSettings.d.cts.map +1 -0
- package/dist/services/piSettings.d.mts +24 -0
- package/dist/services/piSettings.d.mts.map +1 -0
- package/dist/services/piSettings.mjs +2 -0
- package/dist/services/piSettings.mjs.map +1 -0
- package/dist/services/resourceCollector.cjs +3 -0
- package/dist/services/resourceCollector.cjs.map +1 -0
- package/dist/services/resourceCollector.d.cts +16 -0
- package/dist/services/resourceCollector.d.cts.map +1 -0
- package/dist/services/resourceCollector.d.mts +16 -0
- package/dist/services/resourceCollector.d.mts.map +1 -0
- package/dist/services/resourceCollector.mjs +3 -0
- package/dist/services/resourceCollector.mjs.map +1 -0
- package/dist/services/skillCatalog.cjs +2 -0
- package/dist/services/skillCatalog.cjs.map +1 -0
- package/dist/services/skillCatalog.d.cts +56 -0
- package/dist/services/skillCatalog.d.cts.map +1 -0
- package/dist/services/skillCatalog.d.mts +56 -0
- package/dist/services/skillCatalog.d.mts.map +1 -0
- package/dist/services/skillCatalog.mjs +2 -0
- package/dist/services/skillCatalog.mjs.map +1 -0
- package/dist/services/skillSources.cjs +2 -0
- package/dist/services/skillSources.cjs.map +1 -0
- package/dist/services/skillSources.d.cts +24 -0
- package/dist/services/skillSources.d.cts.map +1 -0
- package/dist/services/skillSources.d.mts +24 -0
- package/dist/services/skillSources.d.mts.map +1 -0
- package/dist/services/skillSources.mjs +2 -0
- package/dist/services/skillSources.mjs.map +1 -0
- package/dist/services/syncState.cjs +2 -0
- package/dist/services/syncState.cjs.map +1 -0
- package/dist/services/syncState.d.cts +130 -0
- package/dist/services/syncState.d.cts.map +1 -0
- package/dist/services/syncState.d.mts +130 -0
- package/dist/services/syncState.d.mts.map +1 -0
- package/dist/services/syncState.mjs +2 -0
- package/dist/services/syncState.mjs.map +1 -0
- package/dist/utils/index.cjs +1 -0
- package/dist/utils/index.d.cts +5 -0
- package/dist/utils/index.d.mts +5 -0
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/json.cjs +2 -0
- package/dist/utils/json.cjs.map +1 -0
- package/dist/utils/json.d.cts +23 -0
- package/dist/utils/json.d.cts.map +1 -0
- package/dist/utils/json.d.mts +23 -0
- package/dist/utils/json.d.mts.map +1 -0
- package/dist/utils/json.mjs +2 -0
- package/dist/utils/json.mjs.map +1 -0
- package/dist/utils/moduleResolution.cjs +2 -0
- package/dist/utils/moduleResolution.cjs.map +1 -0
- package/dist/utils/moduleResolution.d.cts +56 -0
- package/dist/utils/moduleResolution.d.cts.map +1 -0
- package/dist/utils/moduleResolution.d.mts +56 -0
- package/dist/utils/moduleResolution.d.mts.map +1 -0
- package/dist/utils/moduleResolution.mjs +2 -0
- package/dist/utils/moduleResolution.mjs.map +1 -0
- package/dist/utils/repository.cjs +2 -0
- package/dist/utils/repository.cjs.map +1 -0
- package/dist/utils/repository.d.cts +21 -0
- package/dist/utils/repository.d.cts.map +1 -0
- package/dist/utils/repository.d.mts +21 -0
- package/dist/utils/repository.d.mts.map +1 -0
- package/dist/utils/repository.mjs +2 -0
- package/dist/utils/repository.mjs.map +1 -0
- package/dist/utils/toolNames.cjs +2 -0
- package/dist/utils/toolNames.cjs.map +1 -0
- package/dist/utils/toolNames.d.cts +25 -0
- package/dist/utils/toolNames.d.cts.map +1 -0
- package/dist/utils/toolNames.d.mts +25 -0
- package/dist/utils/toolNames.d.mts.map +1 -0
- package/dist/utils/toolNames.mjs +2 -0
- package/dist/utils/toolNames.mjs.map +1 -0
- package/package.json +369 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DomainMcpAllowlist } from "@agimon-ai/doompi-config/domains";
|
|
2
|
+
|
|
3
|
+
//#region src/services/mcpFilter.d.ts
|
|
4
|
+
/** Server name in .mcp.json whose upstreams are declared in mcp-config.yaml. */
|
|
5
|
+
declare const PROXY_SERVER_NAME = "agiflow-proxy";
|
|
6
|
+
type JsonObject = Record<string, unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Unions the mcp allowlists of the selected domains.
|
|
9
|
+
*
|
|
10
|
+
* Returns undefined when any selected domain omits `mcp`, which means "give me
|
|
11
|
+
* everything". Filtering only kicks in once every selected domain has opted in,
|
|
12
|
+
* so a domain that has not been migrated yet cannot silently lose its tools.
|
|
13
|
+
*/
|
|
14
|
+
declare function resolveMcpAllowlist(repoRoot: string, domainNames: string[]): DomainMcpAllowlist | undefined;
|
|
15
|
+
/** Drops servers that are not on the allowlist. An empty list means keep all. */
|
|
16
|
+
declare function filterMcpServers(config: JsonObject, allowed?: string[]): JsonObject;
|
|
17
|
+
/**
|
|
18
|
+
* Rewrites the proxy's upstream list, keeping only allowed servers.
|
|
19
|
+
*
|
|
20
|
+
* Entries are removed rather than marked disabled so a filtered upstream cannot
|
|
21
|
+
* be reached even if the proxy ignores the disabled flag. Comments in the
|
|
22
|
+
* source file are not preserved; the result is a per-run temporary file.
|
|
23
|
+
*/
|
|
24
|
+
declare function filterProxyConfig(yamlText: string, allowed?: string[]): string;
|
|
25
|
+
/**
|
|
26
|
+
* Copies a generated MCP config out of the run directory so another frontend
|
|
27
|
+
* can use it, keeping the proxy's --config pointing at the copy.
|
|
28
|
+
*
|
|
29
|
+
* The run directory is deleted when the harness exits, so emitting for
|
|
30
|
+
* claude.sh or codex.sh has to relocate both files together.
|
|
31
|
+
*/
|
|
32
|
+
declare function persistMcpConfig(sourceConfigPath: string, temporaryDirectory: string, targetDirectory: string): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Applies the allowlist to a merged MCP config, writing a filtered proxy config
|
|
35
|
+
* into the run directory and repointing the proxy at it when needed.
|
|
36
|
+
*/
|
|
37
|
+
declare function applyMcpAllowlist(config: JsonObject, allowlist: DomainMcpAllowlist | undefined, repoRoot: string, temporaryDirectory: string): Promise<JsonObject>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { PROXY_SERVER_NAME, applyMcpAllowlist, filterMcpServers, filterProxyConfig, persistMcpConfig, resolveMcpAllowlist };
|
|
40
|
+
//# sourceMappingURL=mcpFilter.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpFilter.d.mts","names":[],"sources":["../../src/services/mcpFilter.ts"],"mappings":";;;;cAMa,iBAAA;AAAA,KAER,UAAA,GAAa,MAAA;;;;;AAF+B;;;iBAWjC,mBAAA,CAAoB,QAAA,UAAkB,WAAA,aAAwB,kBAAA;;iBAiB9D,gBAAA,CAAiB,MAAA,EAAQ,UAAA,EAAY,OAAA,cAAqB,UAAA;;;;;;;;iBAiB1D,iBAAA,CAAkB,QAAA,UAAkB,OAAA;AAjBpD;;;;;;;AAAA,iBA2CsB,gBAAA,CACpB,gBAAA,UACA,kBAAA,UACA,eAAA,WACC,OAAA;;;AA9BH;;iBA2DsB,iBAAA,CACpB,MAAA,EAAQ,UAAA,EACR,SAAA,EAAW,kBAAA,cACX,QAAA,UACA,kBAAA,WACC,OAAA,CAAQ,UAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import e from"node:path";import t from"node:fs";import{expandDomainNames as n,loadDomains as r}from"@agimon-ai/doompi-config/domains";import{parse as i,stringify as a}from"yaml";const o=`agiflow-proxy`;function s(e,t){let i=r(e),a=n(i,t);if(a.length===0)return;let o=new Set,s=new Set;for(let e of a){let t=i.domains[e]?.mcp;if(!t)return;for(let e of t.servers??[])o.add(e);for(let e of t.proxy??[])s.add(e)}return{servers:[...o],proxy:[...s]}}function c(e,t){if(!t||t.length===0)return e;let n=e.mcpServers??{},r={};for(let[e,i]of Object.entries(n))t.includes(e)&&(r[e]=i);return{...e,mcpServers:r}}function l(e,t){if(!t||t.length===0)return e;let n=i(e)??{},r=n.mcpServers??{},o={},s=[];for(let[e,n]of Object.entries(r))t.includes(e)?o[e]=n:s.push(e);return`${[`# Generated by doompi for this run. Do not edit.`,`# Upstreams kept: ${Object.keys(o).join(`, `)||`(none)`}`,`# Upstreams removed by the domain allowlist: ${s.join(`, `)||`(none)`}`,``].join(`
|
|
2
|
+
`)}${a({...n,mcpServers:o})}`}async function u(n,r,i){await t.promises.mkdir(i,{recursive:!0});let a=JSON.parse(t.readFileSync(n,`utf8`)),s=a.mcpServers??{},c=s[o],l=e.join(r,`mcp-config.yaml`);if(c&&t.existsSync(l)){let n=[...c.args??[]],r=n.indexOf(`--config`);if(r!==-1){let a=e.join(i,`mcp-config.yaml`);await t.promises.copyFile(l,a),n[r+1]=a,s[o]={...c,args:n}}}let u=e.join(i,`mcp.json`);return await t.promises.writeFile(u,`${JSON.stringify({...a,mcpServers:s},null,2)}\n`,{mode:384}),u}async function d(n,r,i,a){if(!r)return n;let s=c(n,r.servers),u=s.mcpServers??{},d=u[o];if(!d||!r.proxy||r.proxy.length===0)return s;let f=[...d.args??[]],p=f.indexOf(`--config`);if(p===-1||!f[p+1])return s;let m=e.resolve(i,f[p+1]);if(!t.existsSync(m))return s;let h=e.join(a,`mcp-config.yaml`);return await t.promises.writeFile(h,l(t.readFileSync(m,`utf8`),r.proxy),{mode:384}),f[p+1]=h,{...s,mcpServers:{...u,[o]:{...d,args:f}}}}export{o as PROXY_SERVER_NAME,d as applyMcpAllowlist,c as filterMcpServers,l as filterProxyConfig,u as persistMcpConfig,s as resolveMcpAllowlist};
|
|
3
|
+
//# sourceMappingURL=mcpFilter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpFilter.mjs","names":["parseYaml","stringifyYaml"],"sources":["../../src/services/mcpFilter.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport { type DomainMcpAllowlist, expandDomainNames, loadDomains } from '@agimon-ai/doompi-config/domains';\n\n/** Server name in .mcp.json whose upstreams are declared in mcp-config.yaml. */\nexport const PROXY_SERVER_NAME = 'agiflow-proxy';\n\ntype JsonObject = Record<string, unknown>;\n\n/**\n * Unions the mcp allowlists of the selected domains.\n *\n * Returns undefined when any selected domain omits `mcp`, which means \"give me\n * everything\". Filtering only kicks in once every selected domain has opted in,\n * so a domain that has not been migrated yet cannot silently lose its tools.\n */\nexport function resolveMcpAllowlist(repoRoot: string, domainNames: string[]): DomainMcpAllowlist | undefined {\n const manifest = loadDomains(repoRoot);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return undefined;\n\n const servers = new Set<string>();\n const proxy = new Set<string>();\n for (const name of expanded) {\n const allowlist = manifest.domains[name]?.mcp;\n if (!allowlist) return undefined;\n for (const server of allowlist.servers ?? []) servers.add(server);\n for (const upstream of allowlist.proxy ?? []) proxy.add(upstream);\n }\n return { servers: [...servers], proxy: [...proxy] };\n}\n\n/** Drops servers that are not on the allowlist. An empty list means keep all. */\nexport function filterMcpServers(config: JsonObject, allowed?: string[]): JsonObject {\n if (!allowed || allowed.length === 0) return config;\n const servers = (config.mcpServers ?? {}) as Record<string, unknown>;\n const kept: Record<string, unknown> = {};\n for (const [name, definition] of Object.entries(servers)) {\n if (allowed.includes(name)) kept[name] = definition;\n }\n return { ...config, mcpServers: kept };\n}\n\n/**\n * Rewrites the proxy's upstream list, keeping only allowed servers.\n *\n * Entries are removed rather than marked disabled so a filtered upstream cannot\n * be reached even if the proxy ignores the disabled flag. Comments in the\n * source file are not preserved; the result is a per-run temporary file.\n */\nexport function filterProxyConfig(yamlText: string, allowed?: string[]): string {\n if (!allowed || allowed.length === 0) return yamlText;\n const config = (parseYaml(yamlText) ?? {}) as JsonObject;\n const servers = (config.mcpServers ?? {}) as Record<string, unknown>;\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n for (const [name, definition] of Object.entries(servers)) {\n if (allowed.includes(name)) kept[name] = definition;\n else dropped.push(name);\n }\n const header = [\n '# Generated by doompi for this run. Do not edit.',\n `# Upstreams kept: ${Object.keys(kept).join(', ') || '(none)'}`,\n `# Upstreams removed by the domain allowlist: ${dropped.join(', ') || '(none)'}`,\n '',\n ].join('\\n');\n return `${header}${stringifyYaml({ ...config, mcpServers: kept })}`;\n}\n\n/**\n * Copies a generated MCP config out of the run directory so another frontend\n * can use it, keeping the proxy's --config pointing at the copy.\n *\n * The run directory is deleted when the harness exits, so emitting for\n * claude.sh or codex.sh has to relocate both files together.\n */\nexport async function persistMcpConfig(\n sourceConfigPath: string,\n temporaryDirectory: string,\n targetDirectory: string,\n): Promise<string> {\n await fs.promises.mkdir(targetDirectory, { recursive: true });\n const config = JSON.parse(fs.readFileSync(sourceConfigPath, 'utf8')) as JsonObject;\n const servers = (config.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n const generatedProxyConfig = path.join(temporaryDirectory, 'mcp-config.yaml');\n\n if (proxy && fs.existsSync(generatedProxyConfig)) {\n const args = [...((proxy.args ?? []) as string[])];\n const configIndex = args.indexOf('--config');\n if (configIndex !== -1) {\n const targetProxyConfig = path.join(targetDirectory, 'mcp-config.yaml');\n await fs.promises.copyFile(generatedProxyConfig, targetProxyConfig);\n args[configIndex + 1] = targetProxyConfig;\n servers[PROXY_SERVER_NAME] = { ...proxy, args };\n }\n }\n\n const targetPath = path.join(targetDirectory, 'mcp.json');\n await fs.promises.writeFile(targetPath, `${JSON.stringify({ ...config, mcpServers: servers }, null, 2)}\\n`, {\n mode: 0o600,\n });\n return targetPath;\n}\n\n/**\n * Applies the allowlist to a merged MCP config, writing a filtered proxy config\n * into the run directory and repointing the proxy at it when needed.\n */\nexport async function applyMcpAllowlist(\n config: JsonObject,\n allowlist: DomainMcpAllowlist | undefined,\n repoRoot: string,\n temporaryDirectory: string,\n): Promise<JsonObject> {\n if (!allowlist) return config;\n const filtered = filterMcpServers(config, allowlist.servers);\n const servers = (filtered.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n if (!proxy || !allowlist.proxy || allowlist.proxy.length === 0) return filtered;\n\n const args = [...((proxy.args ?? []) as string[])];\n const configIndex = args.indexOf('--config');\n if (configIndex === -1 || !args[configIndex + 1]) return filtered;\n\n const sourcePath = path.resolve(repoRoot, args[configIndex + 1]);\n if (!fs.existsSync(sourcePath)) return filtered;\n const targetPath = path.join(temporaryDirectory, 'mcp-config.yaml');\n await fs.promises.writeFile(targetPath, filterProxyConfig(fs.readFileSync(sourcePath, 'utf8'), allowlist.proxy), {\n mode: 0o600,\n });\n args[configIndex + 1] = targetPath;\n return { ...filtered, mcpServers: { ...servers, [PROXY_SERVER_NAME]: { ...proxy, args } } };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../utils/json.cjs`);require(`../utils/index.cjs`);const n=require(`./syncState.cjs`);let r=require(`node:path`);r=e.__toESM(r,1);const i=`extensions`,a=`themes`,o=`theme`,s=/(^|\/)entries\/doom\.(ts|mjs|js)$/;function c(e){return r.default.join(e,`.pi`,`settings.json`)}function l(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function u(e,t,r){let c=n.settingsRelativePath(t,r.extensionEntry),u=n.settingsRelativePath(t,r.themePath),d=[c,...l(e[i]).filter(e=>!s.test(e))],f=[u,...l(e[a]).filter(e=>e!==u)];return{...e,[i]:d,[a]:f,[o]:typeof e[o]==`string`?e[o]:r.themeName}}function d(e){let n=t.readJson(c(e));return t.isRecord(n)?n:{}}function f(e){return`${JSON.stringify(e,null,2)}\n`}function p(e,n){let r=c(e);return t.writeFileAtomic(r,f(u(d(e),e,n))),r}exports.mergePiSettings=u,exports.piSettingsPath=c,exports.readPiSettings=d,exports.serializePiSettings=f,exports.writePiSettings=p;
|
|
2
|
+
//# sourceMappingURL=piSettings.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"piSettings.cjs","names":["path","settingsRelativePath","readJson","isRecord"],"sources":["../../src/services/piSettings.ts"],"sourcesContent":["import path from 'node:path';\nimport { isRecord, readJson, writeFileAtomic, type JsonObject } from '../utils/index.ts';\nimport { settingsRelativePath } from './syncState.ts';\n\n/**\n * The Pi project settings file, as `doom-pi sync` maintains it.\n *\n * Sync owns three keys and leaves the rest of the file alone, because\n * `.pi/settings.json` is committed and hand-edited: `quietStartup` and the\n * subagent overrides Doom Team reads live there too. The extension entry is\n * written relative to `.pi`, which Pi resolves and which is identical on every\n * machine, so the file stays reviewable in a diff.\n */\n\nconst PI_DIRECTORY = '.pi';\nconst SETTINGS_FILE = 'settings.json';\nconst EXTENSIONS_KEY = 'extensions';\nconst THEMES_KEY = 'themes';\nconst THEME_KEY = 'theme';\n/** Any entry pointing at the doom-pi runtime, whatever path a past sync used. */\nconst DOOM_ENTRY_PATTERN = /(^|\\/)entries\\/doom\\.(ts|mjs|js)$/;\n\nexport interface PiSettingsUpdate {\n /** Absolute path to the doom-pi Pi extension. */\n extensionEntry: string;\n /** Absolute path to the generated theme file. */\n themePath: string;\n themeName: string;\n}\n\nexport function piSettingsPath(repoRoot: string): string {\n return path.join(repoRoot, PI_DIRECTORY, SETTINGS_FILE);\n}\n\nfunction stringList(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n}\n\n/**\n * Produces the settings content for an update, without writing it.\n *\n * Split out so `--check` can compare against what a sync would write.\n */\nexport function mergePiSettings(current: JsonObject, repoRoot: string, update: PiSettingsUpdate): JsonObject {\n const entry = settingsRelativePath(repoRoot, update.extensionEntry);\n const theme = settingsRelativePath(repoRoot, update.themePath);\n // First in the list, so the harness environment is hydrated before any\n // extension a user added themselves runs.\n const extensions = [entry, ...stringList(current[EXTENSIONS_KEY]).filter((value) => !DOOM_ENTRY_PATTERN.test(value))];\n const themes = [theme, ...stringList(current[THEMES_KEY]).filter((value) => value !== theme)];\n return {\n ...current,\n [EXTENSIONS_KEY]: extensions,\n [THEMES_KEY]: themes,\n // Only filled in when unset: a theme the user picked later is their choice,\n // and re-imposing the doom theme on every sync would silently undo it.\n [THEME_KEY]: typeof current[THEME_KEY] === 'string' ? current[THEME_KEY] : update.themeName,\n };\n}\n\nexport function readPiSettings(repoRoot: string): JsonObject {\n const settings = readJson(piSettingsPath(repoRoot));\n return isRecord(settings) ? settings : {};\n}\n\nexport function serializePiSettings(settings: JsonObject): string {\n return `${JSON.stringify(settings, null, 2)}\\n`;\n}\n\n/** Merges the doom-owned keys into the committed settings file. */\nexport function writePiSettings(repoRoot: string, update: PiSettingsUpdate): string {\n const settingsPath = piSettingsPath(repoRoot);\n writeFileAtomic(settingsPath, serializePiSettings(mergePiSettings(readPiSettings(repoRoot), repoRoot, update)));\n return settingsPath;\n}\n"],"mappings":"oQAcA,MAEM,EAAiB,aACjB,EAAa,SACb,EAAY,QAEZ,EAAqB,oCAU3B,SAAgB,EAAe,EAA0B,CACvD,OAAOA,EAAAA,QAAK,KAAK,EAAU,MAAc,gBAAc,CAGzD,SAAS,EAAW,EAA0B,CAC5C,OAAO,MAAM,QAAQ,EAAM,CAAG,EAAM,OAAQ,GAA2B,OAAO,GAAU,SAAS,CAAG,EAAE,CAQxG,SAAgB,EAAgB,EAAqB,EAAkB,EAAsC,CAC3G,IAAM,EAAQC,EAAAA,qBAAqB,EAAU,EAAO,eAAe,CAC7D,EAAQA,EAAAA,qBAAqB,EAAU,EAAO,UAAU,CAGxD,EAAa,CAAC,EAAO,GAAG,EAAW,EAAQ,GAAgB,CAAC,OAAQ,GAAU,CAAC,EAAmB,KAAK,EAAM,CAAC,CAAC,CAC/G,EAAS,CAAC,EAAO,GAAG,EAAW,EAAQ,GAAY,CAAC,OAAQ,GAAU,IAAU,EAAM,CAAC,CAC7F,MAAO,CACL,GAAG,GACF,GAAiB,GACjB,GAAa,GAGb,GAAY,OAAO,EAAQ,IAAe,SAAW,EAAQ,GAAa,EAAO,UACnF,CAGH,SAAgB,EAAe,EAA8B,CAC3D,IAAM,EAAWC,EAAAA,SAAS,EAAe,EAAS,CAAC,CACnD,OAAOC,EAAAA,SAAS,EAAS,CAAG,EAAW,EAAE,CAG3C,SAAgB,EAAoB,EAA8B,CAChE,MAAO,GAAG,KAAK,UAAU,EAAU,KAAM,EAAE,CAAC,IAI9C,SAAgB,EAAgB,EAAkB,EAAkC,CAClF,IAAM,EAAe,EAAe,EAAS,CAE7C,OADA,EAAA,gBAAgB,EAAc,EAAoB,EAAgB,EAAe,EAAS,CAAE,EAAU,EAAO,CAAC,CAAC,CACxG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { JsonObject } from "../utils/json.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/services/piSettings.d.ts
|
|
4
|
+
interface PiSettingsUpdate {
|
|
5
|
+
/** Absolute path to the doom-pi Pi extension. */
|
|
6
|
+
extensionEntry: string;
|
|
7
|
+
/** Absolute path to the generated theme file. */
|
|
8
|
+
themePath: string;
|
|
9
|
+
themeName: string;
|
|
10
|
+
}
|
|
11
|
+
declare function piSettingsPath(repoRoot: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Produces the settings content for an update, without writing it.
|
|
14
|
+
*
|
|
15
|
+
* Split out so `--check` can compare against what a sync would write.
|
|
16
|
+
*/
|
|
17
|
+
declare function mergePiSettings(current: JsonObject, repoRoot: string, update: PiSettingsUpdate): JsonObject;
|
|
18
|
+
declare function readPiSettings(repoRoot: string): JsonObject;
|
|
19
|
+
declare function serializePiSettings(settings: JsonObject): string;
|
|
20
|
+
/** Merges the doom-owned keys into the committed settings file. */
|
|
21
|
+
declare function writePiSettings(repoRoot: string, update: PiSettingsUpdate): string;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { PiSettingsUpdate, mergePiSettings, piSettingsPath, readPiSettings, serializePiSettings, writePiSettings };
|
|
24
|
+
//# sourceMappingURL=piSettings.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"piSettings.d.cts","names":[],"sources":["../../src/services/piSettings.ts"],"mappings":";;;UAsBiB,gBAAA;;EAEf,cAAA;EAF+B;EAI/B,SAAA;EACA,SAAA;AAAA;AAAA,iBAGc,cAAA,CAAe,QAAA;;;;AAA/B;;iBAagB,eAAA,CAAgB,OAAA,EAAS,UAAA,EAAY,QAAA,UAAkB,MAAA,EAAQ,gBAAA,GAAmB,UAAA;AAAA,iBAiBlF,cAAA,CAAe,QAAA,WAAmB,UAAA;AAAA,iBAKlC,mBAAA,CAAoB,QAAA,EAAU,UAAA;AAtB9C;AAAA,iBA2BgB,eAAA,CAAgB,QAAA,UAAkB,MAAA,EAAQ,gBAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { JsonObject } from "../utils/json.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/services/piSettings.d.ts
|
|
4
|
+
interface PiSettingsUpdate {
|
|
5
|
+
/** Absolute path to the doom-pi Pi extension. */
|
|
6
|
+
extensionEntry: string;
|
|
7
|
+
/** Absolute path to the generated theme file. */
|
|
8
|
+
themePath: string;
|
|
9
|
+
themeName: string;
|
|
10
|
+
}
|
|
11
|
+
declare function piSettingsPath(repoRoot: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Produces the settings content for an update, without writing it.
|
|
14
|
+
*
|
|
15
|
+
* Split out so `--check` can compare against what a sync would write.
|
|
16
|
+
*/
|
|
17
|
+
declare function mergePiSettings(current: JsonObject, repoRoot: string, update: PiSettingsUpdate): JsonObject;
|
|
18
|
+
declare function readPiSettings(repoRoot: string): JsonObject;
|
|
19
|
+
declare function serializePiSettings(settings: JsonObject): string;
|
|
20
|
+
/** Merges the doom-owned keys into the committed settings file. */
|
|
21
|
+
declare function writePiSettings(repoRoot: string, update: PiSettingsUpdate): string;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { PiSettingsUpdate, mergePiSettings, piSettingsPath, readPiSettings, serializePiSettings, writePiSettings };
|
|
24
|
+
//# sourceMappingURL=piSettings.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"piSettings.d.mts","names":[],"sources":["../../src/services/piSettings.ts"],"mappings":";;;UAsBiB,gBAAA;;EAEf,cAAA;EAF+B;EAI/B,SAAA;EACA,SAAA;AAAA;AAAA,iBAGc,cAAA,CAAe,QAAA;;;;AAA/B;;iBAagB,eAAA,CAAgB,OAAA,EAAS,UAAA,EAAY,QAAA,UAAkB,MAAA,EAAQ,gBAAA,GAAmB,UAAA;AAAA,iBAiBlF,cAAA,CAAe,QAAA,WAAmB,UAAA;AAAA,iBAKlC,mBAAA,CAAoB,QAAA,EAAU,UAAA;AAtB9C;AAAA,iBA2BgB,eAAA,CAAgB,QAAA,UAAkB,MAAA,EAAQ,gBAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{isRecord as e,readJson as t,writeFileAtomic as n}from"../utils/json.mjs";import"../utils/index.mjs";import{settingsRelativePath as r}from"./syncState.mjs";import i from"node:path";const a=`extensions`,o=`themes`,s=`theme`,c=/(^|\/)entries\/doom\.(ts|mjs|js)$/;function l(e){return i.join(e,`.pi`,`settings.json`)}function u(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function d(e,t,n){let i=r(t,n.extensionEntry),l=r(t,n.themePath),d=[i,...u(e[a]).filter(e=>!c.test(e))],f=[l,...u(e[o]).filter(e=>e!==l)];return{...e,[a]:d,[o]:f,[s]:typeof e[s]==`string`?e[s]:n.themeName}}function f(n){let r=t(l(n));return e(r)?r:{}}function p(e){return`${JSON.stringify(e,null,2)}\n`}function m(e,t){let r=l(e);return n(r,p(d(f(e),e,t))),r}export{d as mergePiSettings,l as piSettingsPath,f as readPiSettings,p as serializePiSettings,m as writePiSettings};
|
|
2
|
+
//# sourceMappingURL=piSettings.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"piSettings.mjs","names":[],"sources":["../../src/services/piSettings.ts"],"sourcesContent":["import path from 'node:path';\nimport { isRecord, readJson, writeFileAtomic, type JsonObject } from '../utils/index.ts';\nimport { settingsRelativePath } from './syncState.ts';\n\n/**\n * The Pi project settings file, as `doom-pi sync` maintains it.\n *\n * Sync owns three keys and leaves the rest of the file alone, because\n * `.pi/settings.json` is committed and hand-edited: `quietStartup` and the\n * subagent overrides Doom Team reads live there too. The extension entry is\n * written relative to `.pi`, which Pi resolves and which is identical on every\n * machine, so the file stays reviewable in a diff.\n */\n\nconst PI_DIRECTORY = '.pi';\nconst SETTINGS_FILE = 'settings.json';\nconst EXTENSIONS_KEY = 'extensions';\nconst THEMES_KEY = 'themes';\nconst THEME_KEY = 'theme';\n/** Any entry pointing at the doom-pi runtime, whatever path a past sync used. */\nconst DOOM_ENTRY_PATTERN = /(^|\\/)entries\\/doom\\.(ts|mjs|js)$/;\n\nexport interface PiSettingsUpdate {\n /** Absolute path to the doom-pi Pi extension. */\n extensionEntry: string;\n /** Absolute path to the generated theme file. */\n themePath: string;\n themeName: string;\n}\n\nexport function piSettingsPath(repoRoot: string): string {\n return path.join(repoRoot, PI_DIRECTORY, SETTINGS_FILE);\n}\n\nfunction stringList(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n}\n\n/**\n * Produces the settings content for an update, without writing it.\n *\n * Split out so `--check` can compare against what a sync would write.\n */\nexport function mergePiSettings(current: JsonObject, repoRoot: string, update: PiSettingsUpdate): JsonObject {\n const entry = settingsRelativePath(repoRoot, update.extensionEntry);\n const theme = settingsRelativePath(repoRoot, update.themePath);\n // First in the list, so the harness environment is hydrated before any\n // extension a user added themselves runs.\n const extensions = [entry, ...stringList(current[EXTENSIONS_KEY]).filter((value) => !DOOM_ENTRY_PATTERN.test(value))];\n const themes = [theme, ...stringList(current[THEMES_KEY]).filter((value) => value !== theme)];\n return {\n ...current,\n [EXTENSIONS_KEY]: extensions,\n [THEMES_KEY]: themes,\n // Only filled in when unset: a theme the user picked later is their choice,\n // and re-imposing the doom theme on every sync would silently undo it.\n [THEME_KEY]: typeof current[THEME_KEY] === 'string' ? current[THEME_KEY] : update.themeName,\n };\n}\n\nexport function readPiSettings(repoRoot: string): JsonObject {\n const settings = readJson(piSettingsPath(repoRoot));\n return isRecord(settings) ? settings : {};\n}\n\nexport function serializePiSettings(settings: JsonObject): string {\n return `${JSON.stringify(settings, null, 2)}\\n`;\n}\n\n/** Merges the doom-owned keys into the committed settings file. */\nexport function writePiSettings(repoRoot: string, update: PiSettingsUpdate): string {\n const settingsPath = piSettingsPath(repoRoot);\n writeFileAtomic(settingsPath, serializePiSettings(mergePiSettings(readPiSettings(repoRoot), repoRoot, update)));\n return settingsPath;\n}\n"],"mappings":"2LAcA,MAEM,EAAiB,aACjB,EAAa,SACb,EAAY,QAEZ,EAAqB,oCAU3B,SAAgB,EAAe,EAA0B,CACvD,OAAO,EAAK,KAAK,EAAU,MAAc,gBAAc,CAGzD,SAAS,EAAW,EAA0B,CAC5C,OAAO,MAAM,QAAQ,EAAM,CAAG,EAAM,OAAQ,GAA2B,OAAO,GAAU,SAAS,CAAG,EAAE,CAQxG,SAAgB,EAAgB,EAAqB,EAAkB,EAAsC,CAC3G,IAAM,EAAQ,EAAqB,EAAU,EAAO,eAAe,CAC7D,EAAQ,EAAqB,EAAU,EAAO,UAAU,CAGxD,EAAa,CAAC,EAAO,GAAG,EAAW,EAAQ,GAAgB,CAAC,OAAQ,GAAU,CAAC,EAAmB,KAAK,EAAM,CAAC,CAAC,CAC/G,EAAS,CAAC,EAAO,GAAG,EAAW,EAAQ,GAAY,CAAC,OAAQ,GAAU,IAAU,EAAM,CAAC,CAC7F,MAAO,CACL,GAAG,GACF,GAAiB,GACjB,GAAa,GAGb,GAAY,OAAO,EAAQ,IAAe,SAAW,EAAQ,GAAa,EAAO,UACnF,CAGH,SAAgB,EAAe,EAA8B,CAC3D,IAAM,EAAW,EAAS,EAAe,EAAS,CAAC,CACnD,OAAO,EAAS,EAAS,CAAG,EAAW,EAAE,CAG3C,SAAgB,EAAoB,EAA8B,CAChE,MAAO,GAAG,KAAK,UAAU,EAAU,KAAM,EAAE,CAAC,IAI9C,SAAgB,EAAgB,EAAkB,EAAkC,CAClF,IAAM,EAAe,EAAe,EAAS,CAE7C,OADA,EAAgB,EAAc,EAAoB,EAAgB,EAAe,EAAS,CAAE,EAAU,EAAO,CAAC,CAAC,CACxG"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./mcpFilter.cjs`),n=require(`../utils/toolNames.cjs`);require(`../utils/index.cjs`);let r=require(`node:path`);r=e.__toESM(r,1);let i=require(`node:fs`);i=e.__toESM(i,1);let a=require(`node:os`);a=e.__toESM(a,1);let o=require(`yaml`);const s=`agiflow-dispatcher`,c=[`read`,`grep`,`find`,`ls`,`bash`,`launch_workflow`,`list_workflows`];function l(e,t,n=process.env){return n.PI_SUBAGENT_CHILD_AGENT===`agiflow-dispatcher`&&n.PI_SUBAGENT_PARENT_SESSION&&t?t:e}function u(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 d={sonnet:`anthropic/claude-sonnet-4-6`,opus:`anthropic/claude-opus-4-6`,haiku:`anthropic/claude-haiku-4-5`};function f(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 p(e){return typeof e==`string`?d[e.toLowerCase()]??e:Array.isArray(e)?e.map(e=>p(e)):e}function m(e){let{attributes:t,body:r}=u(e),i=typeof t.name==`string`?t.name:void 0;if(!i)throw Error(`Agent definition requires a name`);let a=f(i),s=Object.prototype.hasOwnProperty.call(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))],d={...t,inheritProjectContext:!0,inheritSkills:!0,systemPromptMode:t.systemPromptMode??`replace`};if(s?d.tools=Array.isArray(t.tools)?l:l.join(`, `):delete d.tools,d.model!==void 0&&(d.model=p(d.model)),d.fallbackModels!==void 0&&(d.fallbackModels=p(d.fallbackModels)),d.memory===`project`||d.memory===`user`)d.memory={scope:d.memory,path:a};else if(d.memory!==void 0&&(typeof d.memory!=`object`||d.memory===null||Array.isArray(d.memory)))throw Error(`Unsupported memory declaration`);return delete d.permissionMode,{name:a,content:`---\n${(0,o.stringify)(d).trim()}\n---\n\n${r.trimStart()}`}}function h(e,t){if(!i.default.existsSync(e))return[];let n=[];for(let a of i.default.readdirSync(e,{withFileTypes:!0})){let i=r.default.join(e,a.name);a.isDirectory()&&n.push(...h(i,t)),a.isFile()&&a.name===t&&n.push(i)}return n}function g(e){if(!i.default.existsSync(e))return[];let t=[];for(let n of i.default.readdirSync(e,{withFileTypes:!0})){let i=r.default.join(e,n.name);n.isDirectory()&&t.push(...g(i)),n.isFile()&&n.name.endsWith(`.md`)&&t.push(i)}return t}function _(e){let{attributes:t}=u(i.default.readFileSync(e,`utf8`));if(typeof t.name!=`string`)throw Error(`Resource requires a name: ${e}`);return t.name}function v(e,t){let n=new Map;for(let r of e){let e=n.get(r.name);if(e&&i.default.readFileSync(e,`utf8`)!==i.default.readFileSync(r.path,`utf8`))throw Error(`Conflicting ${t} "${r.name}": ${e} and ${r.path}`);n.set(r.name,r.path)}}function y(e){let t={name:s,description:`Selects and launches Agiflow workflows for one loop pass without implementing the work.`,thinking:`high`,systemPromptMode:`replace`,inheritProjectContext:!0,inheritSkills:!0,tools:c.join(`, `),extensions:[e],defaultContext:`fresh`,defaultProgress:!1},n=[`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)(t).trim()}\n---\n\n${n}\n`}function b(e){let t={mcpServers:{}},n=t.mcpServers,r=new Map;for(let t of e){if(!i.default.existsSync(t))continue;let e=JSON.parse(i.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}function x(e,t){return e?e.some(e=>e.includes(`*`)?RegExp(`^${e.split(`*`).map(S).join(`.*`)}$`).test(t):e===t):!0}function S(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async function C(e,n,o){let c=n.map(e=>typeof e==`string`?{directory:e}:e),l=o.temporaryDirectory===void 0,u=o.temporaryDirectory??await i.default.promises.mkdtemp(r.default.join(a.default.tmpdir(),`doom-pi-`));await i.default.promises.mkdir(u,{mode:448,recursive:!0}),await i.default.promises.chmod(u,448);let d=r.default.join(e,`.claude`,`skills`),p=o.sharedSkills===!1?[]:[d],S=o.sharedSkills===!1?[]:h(d,`SKILL.md`).map(e=>({name:_(e),path:e})),C=[],w=[],T=[],E=[r.default.join(e,`.mcp.json`)];for(let e of c){let t=e.directory,n=r.default.join(t,`skills`);if(i.default.existsSync(n)){let t=h(n,`SKILL.md`).map(e=>({name:_(e),path:e})).filter(t=>x(e.skills,t.name));e.skills?p.push(...t.map(e=>r.default.dirname(e.path))):p.push(n),S.push(...t)}let a=r.default.join(t,`agents`);C.push(...g(a).map(e=>({name:_(e),path:e})).filter(t=>x(e.agents,t.name)));let o=r.default.join(t,`hooks`,`hooks.json`);e.hooks!==!1&&i.default.existsSync(o)&&w.push({pluginRoot:t,configPath:o});let s=r.default.join(t,`.mcp.json`);e.mcp!==!1&&i.default.existsSync(s)&&(E.push(s),T.push(s))}if(v(S,`skill`),v(C,`agent`),C.some(e=>e.name===`agiflow-dispatcher`))throw Error(`Conflicting agent "${s}": reserved by the agent harness`);let D=[],O,k=r.default.join(u,`agents`);if(await i.default.promises.rm(k,{recursive:!0,force:!0}),o.agents&&(C.length>0||o.dispatcherWorkflowExtension)){await i.default.promises.mkdir(k,{mode:448});for(let e of C){let t=m(i.default.readFileSync(e.path,`utf8`));await i.default.promises.writeFile(r.default.join(k,`${f(t.name)}.md`),t.content,{mode:384})}o.dispatcherWorkflowExtension&&(O=o.dispatcherWorkflowExtension,await i.default.promises.writeFile(r.default.join(k,`${s}.md`),y(o.dispatcherWorkflowExtension),{mode:384})),D.push(k)}let A;if(o.mcp){A=r.default.join(u,`mcp.json`);let n=await t.applyMcpAllowlist(b(E),o.mcpAllowlist,e,u);await i.default.promises.writeFile(A,`${JSON.stringify(n,null,2)}\n`,{mode:384})}return{temporaryDirectory:u,skillDirectories:p,skillCount:S.length,agentCount:C.length,agentDirectories:D,pluginHooks:w,dispatcherWorkflowExtensionPath:O,mcpConfigPath:A,pluginMcpConfigPaths:T,cleanup:()=>l?i.default.promises.rm(u,{recursive:!0,force:!0}):Promise.resolve()}}exports.DISPATCHER_AGENT_NAME=s,exports.adaptAgentDefinition=m,exports.collectResources=C,exports.mergeMcpConfigs=b,exports.selectWorkflowExtensionForProcess=l;
|
|
3
|
+
//# sourceMappingURL=resourceCollector.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.cjs","names":["toPiToolName","fs","path","os","applyMcpAllowlist"],"sources":["../../src/services/resourceCollector.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { parse, stringify } from 'yaml';\nimport { applyMcpAllowlist } from './mcpFilter.ts';\nimport type { PluginEntry } from '@agimon-ai/doompi-config/domains';\nimport type { HarnessResourceOptions, HarnessResources, PluginHookSource } from '../interfaces/index.ts';\nimport { type JsonObject, toPiToolName } from '../utils/index.ts';\n\nexport const DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst DISPATCHER_TOOLS = ['read', 'grep', 'find', 'ls', 'bash', 'launch_workflow', 'list_workflows'];\n\nexport function selectWorkflowExtensionForProcess(\n workflowExtension: string | undefined,\n dispatcherWorkflowExtension: string | undefined,\n environment: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const isDispatcherChild =\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME && Boolean(environment.PI_SUBAGENT_PARENT_SESSION);\n return isDispatcherChild && dispatcherWorkflowExtension ? dispatcherWorkflowExtension : workflowExtension;\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\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.prototype.hasOwnProperty.call(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 filesNamed(directory: string, filename: string): string[] {\n if (!fs.existsSync(directory)) return [];\n const results: string[] = [];\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...filesNamed(candidate, filename));\n if (entry.isFile() && entry.name === filename) results.push(candidate);\n }\n return results;\n}\n\nfunction markdownFiles(directory: string): string[] {\n if (!fs.existsSync(directory)) return [];\n const results: string[] = [];\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...markdownFiles(candidate));\n if (entry.isFile() && entry.name.endsWith('.md')) results.push(candidate);\n }\n return results;\n}\n\nfunction frontmatterName(filePath: string): string {\n const { attributes } = splitFrontmatter(fs.readFileSync(filePath, 'utf8'));\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${filePath}`);\n return attributes.name;\n}\n\nfunction assertUnique(resources: Array<{ name: string; path: string }>, kind: string): void {\n const seen = new Map<string, string>();\n for (const resource of resources) {\n const previous = seen.get(resource.name);\n if (previous && fs.readFileSync(previous, 'utf8') !== fs.readFileSync(resource.path, 'utf8')) {\n throw new Error(`Conflicting ${kind} \"${resource.name}\": ${previous} and ${resource.path}`);\n }\n seen.set(resource.name, resource.path);\n }\n}\n\nfunction dispatcherAgentSource(dispatcherWorkflowExtension: string): 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 extensions: [dispatcherWorkflowExtension],\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\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\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\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 skillDirectories = options.sharedSkills === false ? [] : [sharedSkills];\n const skillSources =\n options.sharedSkills === false\n ? []\n : filesNamed(sharedSkills, 'SKILL.md').map((filePath) => ({\n name: frontmatterName(filePath),\n path: filePath,\n }));\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 (fs.existsSync(skills)) {\n const found = filesNamed(skills, 'SKILL.md')\n .map((filePath) => ({ name: frontmatterName(filePath), path: filePath }))\n .filter((skill) => keepsName(entry.skills, skill.name));\n // A subset lists individual skill directories, since Pi discovers skills\n // by directory and would otherwise pick up the whole plugin again.\n if (entry.skills) skillDirectories.push(...found.map((skill) => path.dirname(skill.path)));\n else skillDirectories.push(skills);\n skillSources.push(...found);\n }\n const agents = path.join(pluginDirectory, 'agents');\n agentSources.push(\n ...markdownFiles(agents)\n .map((filePath) => ({ name: frontmatterName(filePath), 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 && fs.existsSync(hookConfig)) {\n pluginHooks.push({ pluginRoot: pluginDirectory, configPath: hookConfig });\n }\n const mcpConfig = path.join(pluginDirectory, '.mcp.json');\n if (entry.mcp !== false && fs.existsSync(mcpConfig)) {\n mcpPaths.push(mcpConfig);\n pluginMcpConfigPaths.push(mcpConfig);\n }\n }\n\n assertUnique(skillSources, 'skill');\n assertUnique(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 let dispatcherWorkflowExtensionPath: string | undefined;\n const outputDirectory = path.join(temporaryDirectory, 'agents');\n await fs.promises.rm(outputDirectory, { recursive: true, force: true });\n if (options.agents && (agentSources.length > 0 || options.dispatcherWorkflowExtension)) {\n await fs.promises.mkdir(outputDirectory, { mode: 0o700 });\n for (const source of agentSources) {\n const adapted = adaptAgentDefinition(fs.readFileSync(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 if (options.dispatcherWorkflowExtension) {\n dispatcherWorkflowExtensionPath = options.dispatcherWorkflowExtension;\n await fs.promises.writeFile(\n path.join(outputDirectory, `${DISPATCHER_AGENT_NAME}.md`),\n dispatcherAgentSource(options.dispatcherWorkflowExtension),\n { mode: 0o600 },\n );\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 mergeMcpConfigs(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 dispatcherWorkflowExtensionPath,\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,16 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources } from "../interfaces/harness.cjs";
|
|
2
|
+
import { JsonObject } from "../utils/json.cjs";
|
|
3
|
+
import { PluginEntry } from "@agimon-ai/doompi-config/domains";
|
|
4
|
+
|
|
5
|
+
//#region src/services/resourceCollector.d.ts
|
|
6
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
7
|
+
declare function selectWorkflowExtensionForProcess(workflowExtension: string | undefined, dispatcherWorkflowExtension: string | undefined, environment?: NodeJS.ProcessEnv): string | undefined;
|
|
8
|
+
declare function adaptAgentDefinition(content: string): {
|
|
9
|
+
name: string;
|
|
10
|
+
content: string;
|
|
11
|
+
};
|
|
12
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
13
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, mergeMcpConfigs, selectWorkflowExtensionForProcess };
|
|
16
|
+
//# sourceMappingURL=resourceCollector.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.cts","names":[],"sources":["../../src/services/resourceCollector.ts"],"mappings":";;;;;cASa,qBAAA;AAAA,iBAGG,iCAAA,CACd,iBAAA,sBACA,2BAAA,sBACA,WAAA,GAAa,MAAA,CAAO,UAAA;AAAA,iBAwCN,oBAAA,CAAqB,OAAA;EAAoB,IAAA;EAAc,OAAA;AAAA;AAAA,iBAiGvD,eAAA,CAAgB,WAAA,aAAwB,UAAA;AAAA,iBAkClC,gBAAA,CACpB,QAAA,UACA,OAAA,EAAS,KAAA,UAAe,WAAA,GACxB,OAAA,EAAS,sBAAA,GACR,OAAA,CAAQ,gBAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources } from "../interfaces/harness.mjs";
|
|
2
|
+
import { JsonObject } from "../utils/json.mjs";
|
|
3
|
+
import { PluginEntry } from "@agimon-ai/doompi-config/domains";
|
|
4
|
+
|
|
5
|
+
//#region src/services/resourceCollector.d.ts
|
|
6
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
7
|
+
declare function selectWorkflowExtensionForProcess(workflowExtension: string | undefined, dispatcherWorkflowExtension: string | undefined, environment?: NodeJS.ProcessEnv): string | undefined;
|
|
8
|
+
declare function adaptAgentDefinition(content: string): {
|
|
9
|
+
name: string;
|
|
10
|
+
content: string;
|
|
11
|
+
};
|
|
12
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
13
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, mergeMcpConfigs, selectWorkflowExtensionForProcess };
|
|
16
|
+
//# sourceMappingURL=resourceCollector.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.mts","names":[],"sources":["../../src/services/resourceCollector.ts"],"mappings":";;;;;cASa,qBAAA;AAAA,iBAGG,iCAAA,CACd,iBAAA,sBACA,2BAAA,sBACA,WAAA,GAAa,MAAA,CAAO,UAAA;AAAA,iBAwCN,oBAAA,CAAqB,OAAA;EAAoB,IAAA;EAAc,OAAA;AAAA;AAAA,iBAiGvD,eAAA,CAAgB,WAAA,aAAwB,UAAA;AAAA,iBAkClC,gBAAA,CACpB,QAAA,UACA,OAAA,EAAS,KAAA,UAAe,WAAA,GACxB,OAAA,EAAS,sBAAA,GACR,OAAA,CAAQ,gBAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{applyMcpAllowlist as e}from"./mcpFilter.mjs";import{toPiToolName as t}from"../utils/toolNames.mjs";import"../utils/index.mjs";import n from"node:path";import r from"node:fs";import i from"node:os";import{parse as a,stringify as o}from"yaml";const s=`agiflow-dispatcher`,c=[`read`,`grep`,`find`,`ls`,`bash`,`launch_workflow`,`list_workflows`];function l(e,t,n=process.env){return n.PI_SUBAGENT_CHILD_AGENT===`agiflow-dispatcher`&&n.PI_SUBAGENT_PARENT_SESSION&&t?t:e}function u(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 d={sonnet:`anthropic/claude-sonnet-4-6`,opus:`anthropic/claude-opus-4-6`,haiku:`anthropic/claude-haiku-4-5`};function f(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 p(e){return typeof e==`string`?d[e.toLowerCase()]??e:Array.isArray(e)?e.map(e=>p(e)):e}function m(e){let{attributes:n,body:r}=u(e),i=typeof n.name==`string`?n.name:void 0;if(!i)throw Error(`Agent definition requires a name`);let a=f(i),s=Object.prototype.hasOwnProperty.call(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))],d={...n,inheritProjectContext:!0,inheritSkills:!0,systemPromptMode:n.systemPromptMode??`replace`};if(s?d.tools=Array.isArray(n.tools)?l:l.join(`, `):delete d.tools,d.model!==void 0&&(d.model=p(d.model)),d.fallbackModels!==void 0&&(d.fallbackModels=p(d.fallbackModels)),d.memory===`project`||d.memory===`user`)d.memory={scope:d.memory,path:a};else if(d.memory!==void 0&&(typeof d.memory!=`object`||d.memory===null||Array.isArray(d.memory)))throw Error(`Unsupported memory declaration`);return delete d.permissionMode,{name:a,content:`---\n${o(d).trim()}\n---\n\n${r.trimStart()}`}}function h(e,t){if(!r.existsSync(e))return[];let i=[];for(let a of r.readdirSync(e,{withFileTypes:!0})){let r=n.join(e,a.name);a.isDirectory()&&i.push(...h(r,t)),a.isFile()&&a.name===t&&i.push(r)}return i}function g(e){if(!r.existsSync(e))return[];let t=[];for(let i of r.readdirSync(e,{withFileTypes:!0})){let r=n.join(e,i.name);i.isDirectory()&&t.push(...g(r)),i.isFile()&&i.name.endsWith(`.md`)&&t.push(r)}return t}function _(e){let{attributes:t}=u(r.readFileSync(e,`utf8`));if(typeof t.name!=`string`)throw Error(`Resource requires a name: ${e}`);return t.name}function v(e,t){let n=new Map;for(let i of e){let e=n.get(i.name);if(e&&r.readFileSync(e,`utf8`)!==r.readFileSync(i.path,`utf8`))throw Error(`Conflicting ${t} "${i.name}": ${e} and ${i.path}`);n.set(i.name,i.path)}}function y(e){let t={name:s,description:`Selects and launches Agiflow workflows for one loop pass without implementing the work.`,thinking:`high`,systemPromptMode:`replace`,inheritProjectContext:!0,inheritSkills:!0,tools:c.join(`, `),extensions:[e],defaultContext:`fresh`,defaultProgress:!1},n=[`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(t).trim()}\n---\n\n${n}\n`}function b(e){let t={mcpServers:{}},n=t.mcpServers,i=new Map;for(let t of e){if(!r.existsSync(t))continue;let e=JSON.parse(r.readFileSync(t,`utf8`)).mcpServers??{};for(let[r,a]of Object.entries(e)){let e=n[r];if(e&&JSON.stringify(e)!==JSON.stringify(a))throw Error(`Conflicting MCP server "${r}": ${i.get(r)} and ${t}`);n[r]=a,i.set(r,t)}}return t}function x(e,t){return e?e.some(e=>e.includes(`*`)?RegExp(`^${e.split(`*`).map(S).join(`.*`)}$`).test(t):e===t):!0}function S(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async function C(t,a,o){let c=a.map(e=>typeof e==`string`?{directory:e}:e),l=o.temporaryDirectory===void 0,u=o.temporaryDirectory??await r.promises.mkdtemp(n.join(i.tmpdir(),`doom-pi-`));await r.promises.mkdir(u,{mode:448,recursive:!0}),await r.promises.chmod(u,448);let d=n.join(t,`.claude`,`skills`),p=o.sharedSkills===!1?[]:[d],S=o.sharedSkills===!1?[]:h(d,`SKILL.md`).map(e=>({name:_(e),path:e})),C=[],w=[],T=[],E=[n.join(t,`.mcp.json`)];for(let e of c){let t=e.directory,i=n.join(t,`skills`);if(r.existsSync(i)){let t=h(i,`SKILL.md`).map(e=>({name:_(e),path:e})).filter(t=>x(e.skills,t.name));e.skills?p.push(...t.map(e=>n.dirname(e.path))):p.push(i),S.push(...t)}let a=n.join(t,`agents`);C.push(...g(a).map(e=>({name:_(e),path:e})).filter(t=>x(e.agents,t.name)));let o=n.join(t,`hooks`,`hooks.json`);e.hooks!==!1&&r.existsSync(o)&&w.push({pluginRoot:t,configPath:o});let s=n.join(t,`.mcp.json`);e.mcp!==!1&&r.existsSync(s)&&(E.push(s),T.push(s))}if(v(S,`skill`),v(C,`agent`),C.some(e=>e.name===`agiflow-dispatcher`))throw Error(`Conflicting agent "${s}": reserved by the agent harness`);let D=[],O,k=n.join(u,`agents`);if(await r.promises.rm(k,{recursive:!0,force:!0}),o.agents&&(C.length>0||o.dispatcherWorkflowExtension)){await r.promises.mkdir(k,{mode:448});for(let e of C){let t=m(r.readFileSync(e.path,`utf8`));await r.promises.writeFile(n.join(k,`${f(t.name)}.md`),t.content,{mode:384})}o.dispatcherWorkflowExtension&&(O=o.dispatcherWorkflowExtension,await r.promises.writeFile(n.join(k,`${s}.md`),y(o.dispatcherWorkflowExtension),{mode:384})),D.push(k)}let A;if(o.mcp){A=n.join(u,`mcp.json`);let i=await e(b(E),o.mcpAllowlist,t,u);await r.promises.writeFile(A,`${JSON.stringify(i,null,2)}\n`,{mode:384})}return{temporaryDirectory:u,skillDirectories:p,skillCount:S.length,agentCount:C.length,agentDirectories:D,pluginHooks:w,dispatcherWorkflowExtensionPath:O,mcpConfigPath:A,pluginMcpConfigPaths:T,cleanup:()=>l?r.promises.rm(u,{recursive:!0,force:!0}):Promise.resolve()}}export{s as DISPATCHER_AGENT_NAME,m as adaptAgentDefinition,C as collectResources,b as mergeMcpConfigs,l as selectWorkflowExtensionForProcess};
|
|
3
|
+
//# sourceMappingURL=resourceCollector.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.mjs","names":[],"sources":["../../src/services/resourceCollector.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { parse, stringify } from 'yaml';\nimport { applyMcpAllowlist } from './mcpFilter.ts';\nimport type { PluginEntry } from '@agimon-ai/doompi-config/domains';\nimport type { HarnessResourceOptions, HarnessResources, PluginHookSource } from '../interfaces/index.ts';\nimport { type JsonObject, toPiToolName } from '../utils/index.ts';\n\nexport const DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst DISPATCHER_TOOLS = ['read', 'grep', 'find', 'ls', 'bash', 'launch_workflow', 'list_workflows'];\n\nexport function selectWorkflowExtensionForProcess(\n workflowExtension: string | undefined,\n dispatcherWorkflowExtension: string | undefined,\n environment: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const isDispatcherChild =\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME && Boolean(environment.PI_SUBAGENT_PARENT_SESSION);\n return isDispatcherChild && dispatcherWorkflowExtension ? dispatcherWorkflowExtension : workflowExtension;\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\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.prototype.hasOwnProperty.call(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 filesNamed(directory: string, filename: string): string[] {\n if (!fs.existsSync(directory)) return [];\n const results: string[] = [];\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...filesNamed(candidate, filename));\n if (entry.isFile() && entry.name === filename) results.push(candidate);\n }\n return results;\n}\n\nfunction markdownFiles(directory: string): string[] {\n if (!fs.existsSync(directory)) return [];\n const results: string[] = [];\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...markdownFiles(candidate));\n if (entry.isFile() && entry.name.endsWith('.md')) results.push(candidate);\n }\n return results;\n}\n\nfunction frontmatterName(filePath: string): string {\n const { attributes } = splitFrontmatter(fs.readFileSync(filePath, 'utf8'));\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${filePath}`);\n return attributes.name;\n}\n\nfunction assertUnique(resources: Array<{ name: string; path: string }>, kind: string): void {\n const seen = new Map<string, string>();\n for (const resource of resources) {\n const previous = seen.get(resource.name);\n if (previous && fs.readFileSync(previous, 'utf8') !== fs.readFileSync(resource.path, 'utf8')) {\n throw new Error(`Conflicting ${kind} \"${resource.name}\": ${previous} and ${resource.path}`);\n }\n seen.set(resource.name, resource.path);\n }\n}\n\nfunction dispatcherAgentSource(dispatcherWorkflowExtension: string): 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 extensions: [dispatcherWorkflowExtension],\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\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\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\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 skillDirectories = options.sharedSkills === false ? [] : [sharedSkills];\n const skillSources =\n options.sharedSkills === false\n ? []\n : filesNamed(sharedSkills, 'SKILL.md').map((filePath) => ({\n name: frontmatterName(filePath),\n path: filePath,\n }));\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 (fs.existsSync(skills)) {\n const found = filesNamed(skills, 'SKILL.md')\n .map((filePath) => ({ name: frontmatterName(filePath), path: filePath }))\n .filter((skill) => keepsName(entry.skills, skill.name));\n // A subset lists individual skill directories, since Pi discovers skills\n // by directory and would otherwise pick up the whole plugin again.\n if (entry.skills) skillDirectories.push(...found.map((skill) => path.dirname(skill.path)));\n else skillDirectories.push(skills);\n skillSources.push(...found);\n }\n const agents = path.join(pluginDirectory, 'agents');\n agentSources.push(\n ...markdownFiles(agents)\n .map((filePath) => ({ name: frontmatterName(filePath), 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 && fs.existsSync(hookConfig)) {\n pluginHooks.push({ pluginRoot: pluginDirectory, configPath: hookConfig });\n }\n const mcpConfig = path.join(pluginDirectory, '.mcp.json');\n if (entry.mcp !== false && fs.existsSync(mcpConfig)) {\n mcpPaths.push(mcpConfig);\n pluginMcpConfigPaths.push(mcpConfig);\n }\n }\n\n assertUnique(skillSources, 'skill');\n assertUnique(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 let dispatcherWorkflowExtensionPath: string | undefined;\n const outputDirectory = path.join(temporaryDirectory, 'agents');\n await fs.promises.rm(outputDirectory, { recursive: true, force: true });\n if (options.agents && (agentSources.length > 0 || options.dispatcherWorkflowExtension)) {\n await fs.promises.mkdir(outputDirectory, { mode: 0o700 });\n for (const source of agentSources) {\n const adapted = adaptAgentDefinition(fs.readFileSync(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 if (options.dispatcherWorkflowExtension) {\n dispatcherWorkflowExtensionPath = options.dispatcherWorkflowExtension;\n await fs.promises.writeFile(\n path.join(outputDirectory, `${DISPATCHER_AGENT_NAME}.md`),\n dispatcherAgentSource(options.dispatcherWorkflowExtension),\n { mode: 0o600 },\n );\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 mergeMcpConfigs(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 dispatcherWorkflowExtensionPath,\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,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`);let t=require(`node:path`);t=e.__toESM(t,1);let n=require(`node:fs`);n=e.__toESM(n,1);let r=require(`@agimon-ai/doompi-config/domains`),i=require(`@earendil-works/pi-coding-agent`);const a=`skills`,o=`.claude/skills`;let s;async function c(){return s??=import(`gpt-tokenizer`),(await s).countTokens}function l(e){let n=e.map(e=>t.default.resolve(e));return e=>{let r=t.default.resolve(e);return n.some(e=>e===r||e.startsWith(`${r}${t.default.sep}`)||r.startsWith(`${e}${t.default.sep}`))}}function u(e,n,r,a,o,s){let c=(0,i.loadSkillsFromDir)({dir:e,source:r});for(let t of c.diagnostics)s.push(`${t.path??e}: ${t.message}`);let l=c.skills.filter(e=>a(t.default.dirname(e.filePath)));return o.push(...l),l.map(e=>({name:e.name,description:e.description,filePath:e.filePath,baseDir:e.baseDir,group:n,owner:r,modelInvocable:!e.disableModelInvocation})).sort((e,t)=>e.name.localeCompare(t.name))}function d(e){return e.sort((e,t)=>e.owner.localeCompare(t.owner))}async function f(e){let{repoRoot:s}=e,f=l(e.activeSkillDirectories),p=[],m=[],h=[];for(let t of e.extensionSources){let e=t.directories.flatMap(e=>u(e,`extensions`,t.source,()=>!0,m,p));e.length>0&&h.push({owner:t.source,skills:e})}let g=[];for(let e of(0,r.resolvePluginEntries)(s,(0,r.listDomainNames)(s),[])){let r=t.default.join(e.directory,a);if(!n.default.existsSync(r))continue;let i=t.default.basename(e.directory),o=u(r,`plugins`,i,f,m,p);o.length>0&&g.push({owner:i,skills:o})}let _=u(t.default.join(s,`.claude`,a),`default`,o,f,m,p),v=_.length>0?[{owner:o,skills:_}]:[],y=[{key:`extensions`,label:`extensions`,owners:d(h)},{key:`plugins`,label:`plugins`,owners:d(g)},{key:`default`,label:`default`,owners:v}],b=await c(),x=(0,i.formatSkillsForPrompt)(m),S=0;for(let e of m)try{S+=b(n.default.readFileSync(e.filePath,`utf8`))}catch(t){p.push(`${e.filePath}: ${t instanceof Error?t.message:String(t)}`)}return{groups:y,skillCount:m.length,promptTokens:x?b(x):0,bodyTokens:S,diagnostics:p}}function p(e,t){for(let n of e.groups)for(let e of n.owners){let n=e.skills.find(e=>e.name===t);if(n)return n}}exports.buildSkillCatalog=f,exports.counter=c,exports.findSkill=p;
|
|
2
|
+
//# sourceMappingURL=skillCatalog.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCatalog.cjs","names":["path","fs"],"sources":["../../src/services/skillCatalog.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { listDomainNames, resolvePluginEntries } from '@agimon-ai/doompi-config/domains';\nimport { formatSkillsForPrompt, loadSkillsFromDir, type Skill } from '@earendil-works/pi-coding-agent';\nimport type { SkillSourceEntry } from './skillSources.ts';\n\nconst SKILLS_DIRECTORY = 'skills';\nconst SHARED_SKILLS_OWNER = '.claude/skills';\n\nexport type SkillGroupKey = 'extensions' | 'plugins' | 'default';\n\nexport interface SkillEntry {\n name: string;\n description: string;\n filePath: string;\n baseDir: string;\n group: SkillGroupKey;\n /** Package name for an extension, plugin directory name, or `.claude/skills`. */\n owner: string;\n modelInvocable: boolean;\n}\n\nexport interface SkillOwnerNode {\n owner: string;\n skills: SkillEntry[];\n}\n\nexport interface SkillGroup {\n key: SkillGroupKey;\n label: string;\n owners: SkillOwnerNode[];\n}\n\nexport interface SkillCatalog {\n groups: SkillGroup[];\n skillCount: number;\n /** Tokens the `<available_skills>` prompt block costs on every request. */\n promptTokens: number;\n /** Tokens every loaded SKILL.md costs in full, if all of them were read. */\n bodyTokens: number;\n /** Frontmatter and read failures, surfaced instead of thrown. */\n diagnostics: string[];\n}\n\nexport interface SkillCatalogOptions {\n repoRoot: string;\n /** What the current selection resolved to, from `HarnessState.skillDirectories`. */\n activeSkillDirectories: readonly string[];\n extensionSources: readonly SkillSourceEntry[];\n}\n\n/**\n * The tokenizer, loaded on first use rather than at import.\n *\n * `gpt-tokenizer` carries its whole vocabulary and costs about a tenth of a\n * second to load. This module is reachable from the skills extension, which Pi\n * loads at session start, so a top-level import would charge every session for\n * a surface most of them never open.\n */\nlet tokenizer: Promise<typeof import('gpt-tokenizer')> | undefined;\n\nexport async function counter(): Promise<(text: string) => number> {\n tokenizer ??= import('gpt-tokenizer');\n return (await tokenizer).countTokens;\n}\n\n/**\n * Matches a directory against the active set.\n *\n * A domain that lists a plugin subset puts individual skill directories in the\n * set rather than the plugin's `skills` root, so containment has to be checked\n * both ways: the set may hold an ancestor of the directory, or a descendant of\n * it.\n */\nfunction createActiveMatcher(directories: readonly string[]): (directory: string) => boolean {\n const active = directories.map((directory) => path.resolve(directory));\n return (directory) => {\n const resolved = path.resolve(directory);\n return active.some(\n (entry) =>\n entry === resolved || entry.startsWith(`${resolved}${path.sep}`) || resolved.startsWith(`${entry}${path.sep}`),\n );\n };\n}\n\nfunction collect(\n directory: string,\n group: SkillGroupKey,\n owner: string,\n isActive: (directory: string) => boolean,\n loaded: Skill[],\n diagnostics: string[],\n): SkillEntry[] {\n const result = loadSkillsFromDir({ dir: directory, source: owner });\n for (const diagnostic of result.diagnostics) {\n diagnostics.push(`${diagnostic.path ?? directory}: ${diagnostic.message}`);\n }\n // Checked per skill, not per root: a subset domain selects some of a plugin's\n // skills and leaves the rest on disk, unloaded and therefore not listed.\n const kept = result.skills.filter((skill) => isActive(path.dirname(skill.filePath)));\n // Kept in their loaded form as well, because the prompt-block cost is measured\n // by handing them back to Pi's own formatter.\n loaded.push(...kept);\n return kept\n .map((skill) => ({\n name: skill.name,\n description: skill.description,\n filePath: skill.filePath,\n baseDir: skill.baseDir,\n group,\n owner,\n modelInvocable: !skill.disableModelInvocation,\n }))\n .sort((left, right) => left.name.localeCompare(right.name));\n}\n\nfunction sortOwners(owners: SkillOwnerNode[]): SkillOwnerNode[] {\n return owners.sort((left, right) => left.owner.localeCompare(right.owner));\n}\n\n/**\n * Every skill this session actually loaded, grouped by where it comes from,\n * priced in tokens.\n *\n * Discovery runs over `loadSkillsFromDir` from Pi rather than the harness's own\n * walker so the listing matches what Pi would load, including its ignore-file\n * handling; the same skills are then handed to Pi's `formatSkillsForPrompt` so\n * the always-on figure is the real prompt block rather than a reconstruction of\n * it.\n */\nexport async function buildSkillCatalog(options: SkillCatalogOptions): Promise<SkillCatalog> {\n const { repoRoot } = options;\n const isActive = createActiveMatcher(options.activeSkillDirectories);\n const diagnostics: string[] = [];\n const loaded: Skill[] = [];\n\n const extensionOwners: SkillOwnerNode[] = [];\n for (const entry of options.extensionSources) {\n const skills = entry.directories.flatMap((directory) =>\n collect(directory, 'extensions', entry.source, () => true, loaded, diagnostics),\n );\n if (skills.length > 0) extensionOwners.push({ owner: entry.source, skills });\n }\n\n const pluginOwners: SkillOwnerNode[] = [];\n for (const entry of resolvePluginEntries(repoRoot, listDomainNames(repoRoot), [])) {\n const directory = path.join(entry.directory, SKILLS_DIRECTORY);\n if (!fs.existsSync(directory)) continue;\n const owner = path.basename(entry.directory);\n const skills = collect(directory, 'plugins', owner, isActive, loaded, diagnostics);\n if (skills.length > 0) pluginOwners.push({ owner, skills });\n }\n\n const sharedDirectory = path.join(repoRoot, '.claude', SKILLS_DIRECTORY);\n const sharedSkills = collect(sharedDirectory, 'default', SHARED_SKILLS_OWNER, isActive, loaded, diagnostics);\n const defaultOwners = sharedSkills.length > 0 ? [{ owner: SHARED_SKILLS_OWNER, skills: sharedSkills }] : [];\n\n const groups: SkillGroup[] = [\n { key: 'extensions', label: 'extensions', owners: sortOwners(extensionOwners) },\n { key: 'plugins', label: 'plugins', owners: sortOwners(pluginOwners) },\n { key: 'default', label: 'default', owners: defaultOwners },\n ];\n\n const countTokens = await counter();\n const prompt = formatSkillsForPrompt(loaded);\n let bodyTokens = 0;\n for (const skill of loaded) {\n try {\n bodyTokens += countTokens(fs.readFileSync(skill.filePath, 'utf8'));\n } catch (error) {\n diagnostics.push(`${skill.filePath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n return {\n groups,\n skillCount: loaded.length,\n promptTokens: prompt ? countTokens(prompt) : 0,\n bodyTokens,\n diagnostics,\n };\n}\n\n/** The skills a name resolves to, used to decide what `enter` can invoke. */\nexport function findSkill(catalog: SkillCatalog, name: string): SkillEntry | undefined {\n for (const group of catalog.groups) {\n for (const owner of group.owners) {\n const match = owner.skills.find((skill) => skill.name === name);\n if (match) return match;\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SkillSourceEntry } from "./skillSources.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/services/skillCatalog.d.ts
|
|
4
|
+
type SkillGroupKey = 'extensions' | 'plugins' | 'default';
|
|
5
|
+
interface SkillEntry {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
baseDir: string;
|
|
10
|
+
group: SkillGroupKey;
|
|
11
|
+
/** Package name for an extension, plugin directory name, or `.claude/skills`. */
|
|
12
|
+
owner: string;
|
|
13
|
+
modelInvocable: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface SkillOwnerNode {
|
|
16
|
+
owner: string;
|
|
17
|
+
skills: SkillEntry[];
|
|
18
|
+
}
|
|
19
|
+
interface SkillGroup {
|
|
20
|
+
key: SkillGroupKey;
|
|
21
|
+
label: string;
|
|
22
|
+
owners: SkillOwnerNode[];
|
|
23
|
+
}
|
|
24
|
+
interface SkillCatalog {
|
|
25
|
+
groups: SkillGroup[];
|
|
26
|
+
skillCount: number;
|
|
27
|
+
/** Tokens the `<available_skills>` prompt block costs on every request. */
|
|
28
|
+
promptTokens: number;
|
|
29
|
+
/** Tokens every loaded SKILL.md costs in full, if all of them were read. */
|
|
30
|
+
bodyTokens: number;
|
|
31
|
+
/** Frontmatter and read failures, surfaced instead of thrown. */
|
|
32
|
+
diagnostics: string[];
|
|
33
|
+
}
|
|
34
|
+
interface SkillCatalogOptions {
|
|
35
|
+
repoRoot: string;
|
|
36
|
+
/** What the current selection resolved to, from `HarnessState.skillDirectories`. */
|
|
37
|
+
activeSkillDirectories: readonly string[];
|
|
38
|
+
extensionSources: readonly SkillSourceEntry[];
|
|
39
|
+
}
|
|
40
|
+
declare function counter(): Promise<(text: string) => number>;
|
|
41
|
+
/**
|
|
42
|
+
* Every skill this session actually loaded, grouped by where it comes from,
|
|
43
|
+
* priced in tokens.
|
|
44
|
+
*
|
|
45
|
+
* Discovery runs over `loadSkillsFromDir` from Pi rather than the harness's own
|
|
46
|
+
* walker so the listing matches what Pi would load, including its ignore-file
|
|
47
|
+
* handling; the same skills are then handed to Pi's `formatSkillsForPrompt` so
|
|
48
|
+
* the always-on figure is the real prompt block rather than a reconstruction of
|
|
49
|
+
* it.
|
|
50
|
+
*/
|
|
51
|
+
declare function buildSkillCatalog(options: SkillCatalogOptions): Promise<SkillCatalog>;
|
|
52
|
+
/** The skills a name resolves to, used to decide what `enter` can invoke. */
|
|
53
|
+
declare function findSkill(catalog: SkillCatalog, name: string): SkillEntry | undefined;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { SkillCatalog, SkillCatalogOptions, SkillEntry, SkillGroup, SkillGroupKey, SkillOwnerNode, buildSkillCatalog, counter, findSkill };
|
|
56
|
+
//# sourceMappingURL=skillCatalog.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCatalog.d.cts","names":[],"sources":["../../src/services/skillCatalog.ts"],"mappings":";;;KASY,aAAA;AAAA,UAEK,UAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,KAAA,EAAO,aAAA;EALQ;EAOf,KAAA;EACA,cAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA;EACA,MAAA,EAAQ,UAAA;AAAA;AAAA,UAGO,UAAA;EACf,GAAA,EAAK,aAAA;EACL,KAAA;EACA,MAAA,EAAQ,cAAA;AAAA;AAAA,UAGO,YAAA;EACf,MAAA,EAAQ,UAAA;EACR,UAAA;;EAEA,YAAA;EAdA;EAgBA,UAAA;EAfQ;EAiBR,WAAA;AAAA;AAAA,UAGe,mBAAA;EACf,QAAA;;EAEA,sBAAA;EACA,gBAAA,WAA2B,gBAAA;AAAA;AAAA,iBAaP,OAAA,CAAA,GAAW,OAAA,EAAS,IAAA;;;;;AA5B1C;;;;;;iBAiGsB,iBAAA,CAAkB,OAAA,EAAS,mBAAA,GAAsB,OAAA,CAAQ,YAAA;;iBAsD/D,SAAA,CAAU,OAAA,EAAS,YAAA,EAAc,IAAA,WAAe,UAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SkillSourceEntry } from "./skillSources.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/services/skillCatalog.d.ts
|
|
4
|
+
type SkillGroupKey = 'extensions' | 'plugins' | 'default';
|
|
5
|
+
interface SkillEntry {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
baseDir: string;
|
|
10
|
+
group: SkillGroupKey;
|
|
11
|
+
/** Package name for an extension, plugin directory name, or `.claude/skills`. */
|
|
12
|
+
owner: string;
|
|
13
|
+
modelInvocable: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface SkillOwnerNode {
|
|
16
|
+
owner: string;
|
|
17
|
+
skills: SkillEntry[];
|
|
18
|
+
}
|
|
19
|
+
interface SkillGroup {
|
|
20
|
+
key: SkillGroupKey;
|
|
21
|
+
label: string;
|
|
22
|
+
owners: SkillOwnerNode[];
|
|
23
|
+
}
|
|
24
|
+
interface SkillCatalog {
|
|
25
|
+
groups: SkillGroup[];
|
|
26
|
+
skillCount: number;
|
|
27
|
+
/** Tokens the `<available_skills>` prompt block costs on every request. */
|
|
28
|
+
promptTokens: number;
|
|
29
|
+
/** Tokens every loaded SKILL.md costs in full, if all of them were read. */
|
|
30
|
+
bodyTokens: number;
|
|
31
|
+
/** Frontmatter and read failures, surfaced instead of thrown. */
|
|
32
|
+
diagnostics: string[];
|
|
33
|
+
}
|
|
34
|
+
interface SkillCatalogOptions {
|
|
35
|
+
repoRoot: string;
|
|
36
|
+
/** What the current selection resolved to, from `HarnessState.skillDirectories`. */
|
|
37
|
+
activeSkillDirectories: readonly string[];
|
|
38
|
+
extensionSources: readonly SkillSourceEntry[];
|
|
39
|
+
}
|
|
40
|
+
declare function counter(): Promise<(text: string) => number>;
|
|
41
|
+
/**
|
|
42
|
+
* Every skill this session actually loaded, grouped by where it comes from,
|
|
43
|
+
* priced in tokens.
|
|
44
|
+
*
|
|
45
|
+
* Discovery runs over `loadSkillsFromDir` from Pi rather than the harness's own
|
|
46
|
+
* walker so the listing matches what Pi would load, including its ignore-file
|
|
47
|
+
* handling; the same skills are then handed to Pi's `formatSkillsForPrompt` so
|
|
48
|
+
* the always-on figure is the real prompt block rather than a reconstruction of
|
|
49
|
+
* it.
|
|
50
|
+
*/
|
|
51
|
+
declare function buildSkillCatalog(options: SkillCatalogOptions): Promise<SkillCatalog>;
|
|
52
|
+
/** The skills a name resolves to, used to decide what `enter` can invoke. */
|
|
53
|
+
declare function findSkill(catalog: SkillCatalog, name: string): SkillEntry | undefined;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { SkillCatalog, SkillCatalogOptions, SkillEntry, SkillGroup, SkillGroupKey, SkillOwnerNode, buildSkillCatalog, counter, findSkill };
|
|
56
|
+
//# sourceMappingURL=skillCatalog.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCatalog.d.mts","names":[],"sources":["../../src/services/skillCatalog.ts"],"mappings":";;;KASY,aAAA;AAAA,UAEK,UAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,KAAA,EAAO,aAAA;EALQ;EAOf,KAAA;EACA,cAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA;EACA,MAAA,EAAQ,UAAA;AAAA;AAAA,UAGO,UAAA;EACf,GAAA,EAAK,aAAA;EACL,KAAA;EACA,MAAA,EAAQ,cAAA;AAAA;AAAA,UAGO,YAAA;EACf,MAAA,EAAQ,UAAA;EACR,UAAA;;EAEA,YAAA;EAdA;EAgBA,UAAA;EAfQ;EAiBR,WAAA;AAAA;AAAA,UAGe,mBAAA;EACf,QAAA;;EAEA,sBAAA;EACA,gBAAA,WAA2B,gBAAA;AAAA;AAAA,iBAaP,OAAA,CAAA,GAAW,OAAA,EAAS,IAAA;;;;;AA5B1C;;;;;;iBAiGsB,iBAAA,CAAkB,OAAA,EAAS,mBAAA,GAAsB,OAAA,CAAQ,YAAA;;iBAsD/D,SAAA,CAAU,OAAA,EAAS,YAAA,EAAc,IAAA,WAAe,UAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"node:path";import t from"node:fs";import{listDomainNames as n,resolvePluginEntries as r}from"@agimon-ai/doompi-config/domains";import{formatSkillsForPrompt as i,loadSkillsFromDir as a}from"@earendil-works/pi-coding-agent";const o=`skills`,s=`.claude/skills`;let c;async function l(){return c??=import(`gpt-tokenizer`),(await c).countTokens}function u(t){let n=t.map(t=>e.resolve(t));return t=>{let r=e.resolve(t);return n.some(t=>t===r||t.startsWith(`${r}${e.sep}`)||r.startsWith(`${t}${e.sep}`))}}function d(t,n,r,i,o,s){let c=a({dir:t,source:r});for(let e of c.diagnostics)s.push(`${e.path??t}: ${e.message}`);let l=c.skills.filter(t=>i(e.dirname(t.filePath)));return o.push(...l),l.map(e=>({name:e.name,description:e.description,filePath:e.filePath,baseDir:e.baseDir,group:n,owner:r,modelInvocable:!e.disableModelInvocation})).sort((e,t)=>e.name.localeCompare(t.name))}function f(e){return e.sort((e,t)=>e.owner.localeCompare(t.owner))}async function p(a){let{repoRoot:c}=a,p=u(a.activeSkillDirectories),m=[],h=[],g=[];for(let e of a.extensionSources){let t=e.directories.flatMap(t=>d(t,`extensions`,e.source,()=>!0,h,m));t.length>0&&g.push({owner:e.source,skills:t})}let _=[];for(let i of r(c,n(c),[])){let n=e.join(i.directory,o);if(!t.existsSync(n))continue;let r=e.basename(i.directory),a=d(n,`plugins`,r,p,h,m);a.length>0&&_.push({owner:r,skills:a})}let v=d(e.join(c,`.claude`,o),`default`,s,p,h,m),y=v.length>0?[{owner:s,skills:v}]:[],b=[{key:`extensions`,label:`extensions`,owners:f(g)},{key:`plugins`,label:`plugins`,owners:f(_)},{key:`default`,label:`default`,owners:y}],x=await l(),S=i(h),C=0;for(let e of h)try{C+=x(t.readFileSync(e.filePath,`utf8`))}catch(t){m.push(`${e.filePath}: ${t instanceof Error?t.message:String(t)}`)}return{groups:b,skillCount:h.length,promptTokens:S?x(S):0,bodyTokens:C,diagnostics:m}}function m(e,t){for(let n of e.groups)for(let e of n.owners){let n=e.skills.find(e=>e.name===t);if(n)return n}}export{p as buildSkillCatalog,l as counter,m as findSkill};
|
|
2
|
+
//# sourceMappingURL=skillCatalog.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCatalog.mjs","names":[],"sources":["../../src/services/skillCatalog.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { listDomainNames, resolvePluginEntries } from '@agimon-ai/doompi-config/domains';\nimport { formatSkillsForPrompt, loadSkillsFromDir, type Skill } from '@earendil-works/pi-coding-agent';\nimport type { SkillSourceEntry } from './skillSources.ts';\n\nconst SKILLS_DIRECTORY = 'skills';\nconst SHARED_SKILLS_OWNER = '.claude/skills';\n\nexport type SkillGroupKey = 'extensions' | 'plugins' | 'default';\n\nexport interface SkillEntry {\n name: string;\n description: string;\n filePath: string;\n baseDir: string;\n group: SkillGroupKey;\n /** Package name for an extension, plugin directory name, or `.claude/skills`. */\n owner: string;\n modelInvocable: boolean;\n}\n\nexport interface SkillOwnerNode {\n owner: string;\n skills: SkillEntry[];\n}\n\nexport interface SkillGroup {\n key: SkillGroupKey;\n label: string;\n owners: SkillOwnerNode[];\n}\n\nexport interface SkillCatalog {\n groups: SkillGroup[];\n skillCount: number;\n /** Tokens the `<available_skills>` prompt block costs on every request. */\n promptTokens: number;\n /** Tokens every loaded SKILL.md costs in full, if all of them were read. */\n bodyTokens: number;\n /** Frontmatter and read failures, surfaced instead of thrown. */\n diagnostics: string[];\n}\n\nexport interface SkillCatalogOptions {\n repoRoot: string;\n /** What the current selection resolved to, from `HarnessState.skillDirectories`. */\n activeSkillDirectories: readonly string[];\n extensionSources: readonly SkillSourceEntry[];\n}\n\n/**\n * The tokenizer, loaded on first use rather than at import.\n *\n * `gpt-tokenizer` carries its whole vocabulary and costs about a tenth of a\n * second to load. This module is reachable from the skills extension, which Pi\n * loads at session start, so a top-level import would charge every session for\n * a surface most of them never open.\n */\nlet tokenizer: Promise<typeof import('gpt-tokenizer')> | undefined;\n\nexport async function counter(): Promise<(text: string) => number> {\n tokenizer ??= import('gpt-tokenizer');\n return (await tokenizer).countTokens;\n}\n\n/**\n * Matches a directory against the active set.\n *\n * A domain that lists a plugin subset puts individual skill directories in the\n * set rather than the plugin's `skills` root, so containment has to be checked\n * both ways: the set may hold an ancestor of the directory, or a descendant of\n * it.\n */\nfunction createActiveMatcher(directories: readonly string[]): (directory: string) => boolean {\n const active = directories.map((directory) => path.resolve(directory));\n return (directory) => {\n const resolved = path.resolve(directory);\n return active.some(\n (entry) =>\n entry === resolved || entry.startsWith(`${resolved}${path.sep}`) || resolved.startsWith(`${entry}${path.sep}`),\n );\n };\n}\n\nfunction collect(\n directory: string,\n group: SkillGroupKey,\n owner: string,\n isActive: (directory: string) => boolean,\n loaded: Skill[],\n diagnostics: string[],\n): SkillEntry[] {\n const result = loadSkillsFromDir({ dir: directory, source: owner });\n for (const diagnostic of result.diagnostics) {\n diagnostics.push(`${diagnostic.path ?? directory}: ${diagnostic.message}`);\n }\n // Checked per skill, not per root: a subset domain selects some of a plugin's\n // skills and leaves the rest on disk, unloaded and therefore not listed.\n const kept = result.skills.filter((skill) => isActive(path.dirname(skill.filePath)));\n // Kept in their loaded form as well, because the prompt-block cost is measured\n // by handing them back to Pi's own formatter.\n loaded.push(...kept);\n return kept\n .map((skill) => ({\n name: skill.name,\n description: skill.description,\n filePath: skill.filePath,\n baseDir: skill.baseDir,\n group,\n owner,\n modelInvocable: !skill.disableModelInvocation,\n }))\n .sort((left, right) => left.name.localeCompare(right.name));\n}\n\nfunction sortOwners(owners: SkillOwnerNode[]): SkillOwnerNode[] {\n return owners.sort((left, right) => left.owner.localeCompare(right.owner));\n}\n\n/**\n * Every skill this session actually loaded, grouped by where it comes from,\n * priced in tokens.\n *\n * Discovery runs over `loadSkillsFromDir` from Pi rather than the harness's own\n * walker so the listing matches what Pi would load, including its ignore-file\n * handling; the same skills are then handed to Pi's `formatSkillsForPrompt` so\n * the always-on figure is the real prompt block rather than a reconstruction of\n * it.\n */\nexport async function buildSkillCatalog(options: SkillCatalogOptions): Promise<SkillCatalog> {\n const { repoRoot } = options;\n const isActive = createActiveMatcher(options.activeSkillDirectories);\n const diagnostics: string[] = [];\n const loaded: Skill[] = [];\n\n const extensionOwners: SkillOwnerNode[] = [];\n for (const entry of options.extensionSources) {\n const skills = entry.directories.flatMap((directory) =>\n collect(directory, 'extensions', entry.source, () => true, loaded, diagnostics),\n );\n if (skills.length > 0) extensionOwners.push({ owner: entry.source, skills });\n }\n\n const pluginOwners: SkillOwnerNode[] = [];\n for (const entry of resolvePluginEntries(repoRoot, listDomainNames(repoRoot), [])) {\n const directory = path.join(entry.directory, SKILLS_DIRECTORY);\n if (!fs.existsSync(directory)) continue;\n const owner = path.basename(entry.directory);\n const skills = collect(directory, 'plugins', owner, isActive, loaded, diagnostics);\n if (skills.length > 0) pluginOwners.push({ owner, skills });\n }\n\n const sharedDirectory = path.join(repoRoot, '.claude', SKILLS_DIRECTORY);\n const sharedSkills = collect(sharedDirectory, 'default', SHARED_SKILLS_OWNER, isActive, loaded, diagnostics);\n const defaultOwners = sharedSkills.length > 0 ? [{ owner: SHARED_SKILLS_OWNER, skills: sharedSkills }] : [];\n\n const groups: SkillGroup[] = [\n { key: 'extensions', label: 'extensions', owners: sortOwners(extensionOwners) },\n { key: 'plugins', label: 'plugins', owners: sortOwners(pluginOwners) },\n { key: 'default', label: 'default', owners: defaultOwners },\n ];\n\n const countTokens = await counter();\n const prompt = formatSkillsForPrompt(loaded);\n let bodyTokens = 0;\n for (const skill of loaded) {\n try {\n bodyTokens += countTokens(fs.readFileSync(skill.filePath, 'utf8'));\n } catch (error) {\n diagnostics.push(`${skill.filePath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n return {\n groups,\n skillCount: loaded.length,\n promptTokens: prompt ? countTokens(prompt) : 0,\n bodyTokens,\n diagnostics,\n };\n}\n\n/** The skills a name resolves to, used to decide what `enter` can invoke. */\nexport function findSkill(catalog: SkillCatalog, name: string): SkillEntry | undefined {\n for (const group of catalog.groups) {\n for (const owner of group.owners) {\n const match = owner.skills.find((skill) => skill.name === name);\n if (match) return match;\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`);let t=require(`node:path`);t=e.__toESM(t,1);let n=require(`node:fs`);n=e.__toESM(n,1);let r=require(`@agimon-ai/doompi-extension-contracts/skills`),i=require(`@agimon-ai/doompi-extension-contracts/protocol`);function a(e){let a=new Map,o=new Map,s=0,c,l=()=>{c?.(),c=void 0};return e.on(`session_start`,(u,d)=>{l(),a.clear(),o.clear();let f=(0,i.createProtocolRuntime)({bus:e.events,source:`@agimon-ai/doompi`,sessionId:d.sessionManager.getSessionId()}),p=f.provide(r.SkillSourceRegistrationProtocol,({contribution:e})=>{let r=e.directories.filter(e=>t.default.isAbsolute(e)&&n.default.existsSync(e)),i=`skill-source-${++s}`,c=a.get(e.source);return c&&o.delete(c.handleId),a.set(e.source,{handleId:i,directories:r}),o.set(i,e.source),{handleId:i}}),m=f.provide(r.SkillSourceUnregistrationProtocol,({handleId:e})=>{let t=o.get(e);return t?(o.delete(e),a.get(t)?.handleId===e&&a.delete(t),{removed:!0}):{removed:!1}});c=()=>{p(),m()}}),e.on(`session_shutdown`,()=>{l(),a.clear(),o.clear()}),{list(){return[...a.entries()].map(([e,t])=>({source:e,directories:[...t.directories]})).sort((e,t)=>e.source.localeCompare(t.source))},dispose(){l(),a.clear(),o.clear()}}}exports.provideSkillSources=a;
|
|
2
|
+
//# sourceMappingURL=skillSources.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillSources.cjs","names":["SkillSourceRegistrationProtocol","path","fs","SkillSourceUnregistrationProtocol"],"sources":["../../src/services/skillSources.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport {\n SkillSourceRegistrationProtocol,\n SkillSourceUnregistrationProtocol,\n} from '@agimon-ai/doompi-extension-contracts/skills';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nconst HOST_SOURCE = '@agimon-ai/doompi';\n\nexport interface SkillSourceEntry {\n source: string;\n directories: string[];\n}\n\nexport interface SkillSourceRegistry {\n /** Registered sources, sorted by name so the catalogue order is stable. */\n list(): readonly SkillSourceEntry[];\n dispose(): void;\n}\n\n/**\n * Hosts the registry extensions publish their skill directories to.\n *\n * Contributions are keyed by source rather than by handle, so a reload that\n * re-registers the same package replaces its entry instead of doubling it. The\n * handle is still tracked, because an unregistration that arrives after a\n * replacement must not take the newer entry down with it.\n */\nexport function provideSkillSources(pi: Pick<ExtensionAPI, 'events' | 'on'>): SkillSourceRegistry {\n const bySource = new Map<string, { handleId: string; directories: string[] }>();\n const sourceByHandle = new Map<string, string>();\n let handleSequence = 0;\n let disposeProviders: (() => void) | undefined;\n\n const stopProviders = (): void => {\n disposeProviders?.();\n disposeProviders = undefined;\n };\n\n pi.on('session_start', (_event, ctx) => {\n stopProviders();\n bySource.clear();\n sourceByHandle.clear();\n const runtime = createProtocolRuntime({\n bus: pi.events,\n source: HOST_SOURCE,\n sessionId: ctx.sessionManager.getSessionId(),\n });\n\n const stopRegister = runtime.provide(SkillSourceRegistrationProtocol, ({ contribution }) => {\n // A path that does not resolve is dropped rather than rejected: the\n // contributor guards on existence too, and failing its registration would\n // surface as a session-start error for a directory nobody can browse.\n const directories = contribution.directories.filter(\n (directory) => path.isAbsolute(directory) && fs.existsSync(directory),\n );\n const handleId = `skill-source-${++handleSequence}`;\n const previous = bySource.get(contribution.source);\n if (previous) sourceByHandle.delete(previous.handleId);\n bySource.set(contribution.source, { handleId, directories });\n sourceByHandle.set(handleId, contribution.source);\n return { handleId };\n });\n\n const stopUnregister = runtime.provide(SkillSourceUnregistrationProtocol, ({ handleId }) => {\n const source = sourceByHandle.get(handleId);\n if (!source) return { removed: false };\n sourceByHandle.delete(handleId);\n // Guarded so a late unregistration cannot remove the replacement that\n // already took this source's slot.\n if (bySource.get(source)?.handleId === handleId) bySource.delete(source);\n return { removed: true };\n });\n\n disposeProviders = () => {\n stopRegister();\n stopUnregister();\n };\n });\n\n pi.on('session_shutdown', () => {\n stopProviders();\n bySource.clear();\n sourceByHandle.clear();\n });\n\n return {\n list() {\n return [...bySource.entries()]\n .map(([source, entry]) => ({ source, directories: [...entry.directories] }))\n .sort((left, right) => left.source.localeCompare(right.source));\n },\n dispose() {\n stopProviders();\n bySource.clear();\n sourceByHandle.clear();\n },\n };\n}\n"],"mappings":"wUA8BA,SAAgB,EAAoB,EAA8D,CAChG,IAAM,EAAW,IAAI,IACf,EAAiB,IAAI,IACvB,EAAiB,EACjB,EAEE,MAA4B,CAChC,KAAoB,CACpB,EAAmB,IAAA,IAkDrB,OA/CA,EAAG,GAAG,iBAAkB,EAAQ,IAAQ,CACtC,GAAe,CACf,EAAS,OAAO,CAChB,EAAe,OAAO,CACtB,IAAM,GAAA,EAAA,EAAA,uBAAgC,CACpC,IAAK,EAAG,OACR,OAAQ,oBACR,UAAW,EAAI,eAAe,cAAc,CAC7C,CAAC,CAEI,EAAe,EAAQ,QAAQA,EAAAA,iCAAkC,CAAE,kBAAmB,CAI1F,IAAM,EAAc,EAAa,YAAY,OAC1C,GAAcC,EAAAA,QAAK,WAAW,EAAU,EAAIC,EAAAA,QAAG,WAAW,EAAU,CACtE,CACK,EAAW,gBAAgB,EAAE,IAC7B,EAAW,EAAS,IAAI,EAAa,OAAO,CAIlD,OAHI,GAAU,EAAe,OAAO,EAAS,SAAS,CACtD,EAAS,IAAI,EAAa,OAAQ,CAAE,WAAU,cAAa,CAAC,CAC5D,EAAe,IAAI,EAAU,EAAa,OAAO,CAC1C,CAAE,WAAU,EACnB,CAEI,EAAiB,EAAQ,QAAQC,EAAAA,mCAAoC,CAAE,cAAe,CAC1F,IAAM,EAAS,EAAe,IAAI,EAAS,CAM3C,OALK,GACL,EAAe,OAAO,EAAS,CAG3B,EAAS,IAAI,EAAO,EAAE,WAAa,GAAU,EAAS,OAAO,EAAO,CACjE,CAAE,QAAS,GAAM,EALJ,CAAE,QAAS,GAAO,EAMtC,CAEF,MAAyB,CACvB,GAAc,CACd,GAAgB,GAElB,CAEF,EAAG,GAAG,uBAA0B,CAC9B,GAAe,CACf,EAAS,OAAO,CAChB,EAAe,OAAO,EACtB,CAEK,CACL,MAAO,CACL,MAAO,CAAC,GAAG,EAAS,SAAS,CAAC,CAC3B,KAAK,CAAC,EAAQ,MAAY,CAAE,SAAQ,YAAa,CAAC,GAAG,EAAM,YAAY,CAAE,EAAE,CAC3E,MAAM,EAAM,IAAU,EAAK,OAAO,cAAc,EAAM,OAAO,CAAC,EAEnE,SAAU,CACR,GAAe,CACf,EAAS,OAAO,CAChB,EAAe,OAAO,EAEzB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region src/services/skillSources.d.ts
|
|
4
|
+
interface SkillSourceEntry {
|
|
5
|
+
source: string;
|
|
6
|
+
directories: string[];
|
|
7
|
+
}
|
|
8
|
+
interface SkillSourceRegistry {
|
|
9
|
+
/** Registered sources, sorted by name so the catalogue order is stable. */
|
|
10
|
+
list(): readonly SkillSourceEntry[];
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Hosts the registry extensions publish their skill directories to.
|
|
15
|
+
*
|
|
16
|
+
* Contributions are keyed by source rather than by handle, so a reload that
|
|
17
|
+
* re-registers the same package replaces its entry instead of doubling it. The
|
|
18
|
+
* handle is still tracked, because an unregistration that arrives after a
|
|
19
|
+
* replacement must not take the newer entry down with it.
|
|
20
|
+
*/
|
|
21
|
+
declare function provideSkillSources(pi: Pick<ExtensionAPI, 'events' | 'on'>): SkillSourceRegistry;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { SkillSourceEntry, SkillSourceRegistry, provideSkillSources };
|
|
24
|
+
//# sourceMappingURL=skillSources.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillSources.d.cts","names":[],"sources":["../../src/services/skillSources.ts"],"mappings":";;;UAWiB,gBAAA;EACf,MAAA;EACA,WAAA;AAAA;AAAA,UAGe,mBAAA;EAJf;EAMA,IAAA,aAAiB,gBAAA;EACjB,OAAA;AAAA;;;;;;;;AAWF;iBAAgB,mBAAA,CAAoB,EAAA,EAAI,IAAA,CAAK,YAAA,qBAAiC,mBAAA"}
|