@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 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.cjs","names":["path","ASK_USER_PROMPT_EVENT","prompt","ASK_USER_BLOCKED_EVENT"],"sources":["../../src/entries/notifications.ts"],"sourcesContent":["import path from 'node:path';\nimport type { ExtensionAPI, ExtensionContext, ExtensionUIContext } from '@earendil-works/pi-coding-agent';\nimport {\n ASK_USER_BLOCKED_EVENT,\n ASK_USER_PROMPT_EVENT,\n type AskUserBlockedEventPayload,\n type AskUserPromptEventPayload,\n} from '@juicesharp/rpiv-ask-user-question/events';\n\ninterface Notification {\n title: string;\n subtitle: string;\n body: string;\n}\n\nconst BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\nconst COMMAND_TIMEOUT_MS = 3_000;\nconst EXTENSION_INPUT_SOURCE = 'extension';\nconst INPUT_EVENT = 'input';\nconst MAX_BODY_LENGTH = 240;\nconst MAX_PROMPT_TITLE_LENGTH = 36;\nconst OSASCRIPT_EXPRESSION_FLAG = '-e';\nconst TITLE_FRAME_INTERVAL_MS = 80;\n\nfunction promptTitle(prompt: string): string | undefined {\n const normalized = prompt.replace(/\\s+/g, ' ').trim();\n if (!normalized) return undefined;\n return normalized.length > MAX_PROMPT_TITLE_LENGTH\n ? `${normalized.slice(0, MAX_PROMPT_TITLE_LENGTH - 1)}…`\n : normalized;\n}\n\nfunction shellTabTitle(pi: ExtensionAPI, cwd: string, prompt?: string, frame?: string): string {\n const prefix = frame ? `${frame} ` : '';\n const repository = path.basename(cwd);\n const label = pi.getSessionName() ?? prompt;\n return label ? `${prefix}π - ${label} - ${repository}` : `${prefix}π - ${repository}`;\n}\n\nfunction notificationBody(body: string): string {\n const normalized = body.replace(/\\s+/g, ' ').trim();\n return normalized.length > MAX_BODY_LENGTH ? `${normalized.slice(0, MAX_BODY_LENGTH - 1)}…` : normalized;\n}\n\nasync function execute(pi: ExtensionAPI, command: string, args: string[]): Promise<boolean> {\n try {\n const result = await pi.exec(command, args, { timeout: COMMAND_TIMEOUT_MS });\n return result.code === 0;\n } catch {\n return false;\n }\n}\n\nexport async function sendSystemNotification(\n pi: ExtensionAPI,\n notification: Notification,\n platform = process.platform,\n): Promise<void> {\n const body = notificationBody(notification.body);\n const sentToCmux = await execute(pi, 'cmux', [\n 'notify',\n '--title',\n notification.title,\n '--subtitle',\n notification.subtitle,\n '--body',\n body,\n ]);\n if (sentToCmux || platform !== 'darwin') return;\n\n await execute(pi, 'osascript', [\n OSASCRIPT_EXPRESSION_FLAG,\n 'on run argv',\n OSASCRIPT_EXPRESSION_FLAG,\n 'display notification (item 3 of argv) with title (item 1 of argv) subtitle (item 2 of argv)',\n OSASCRIPT_EXPRESSION_FLAG,\n 'end run',\n notification.title,\n notification.subtitle,\n body,\n ]);\n}\n\nfunction wrapAttentionDialogs(\n ui: ExtensionUIContext,\n shouldNotify: () => boolean,\n notify: (title: string) => void,\n): void {\n const originalConfirm = ui.confirm.bind(ui);\n ui.confirm = (title, message, options) => {\n if (shouldNotify()) notify(`${title}: ${message}`);\n return originalConfirm(title, message, options);\n };\n\n const originalSelect = ui.select.bind(ui);\n ui.select = (title, options, dialogOptions) => {\n if (shouldNotify()) notify(title);\n return originalSelect(title, options, dialogOptions);\n };\n\n const originalInput = ui.input.bind(ui);\n ui.input = (title, placeholder, options) => {\n if (shouldNotify()) notify(title);\n return originalInput(title, placeholder, options);\n };\n\n const originalEditor = ui.editor.bind(ui);\n ui.editor = (title, prefill) => {\n if (shouldNotify()) notify(title);\n return originalEditor(title, prefill);\n };\n}\n\nexport default function notifications(pi: ExtensionAPI): void {\n if (process.env.PI_SUBAGENT_CHILD) return;\n\n let agentRunning = false;\n let askUserBlocked = false;\n let firstPromptTitle: string | undefined;\n let frameIndex = 0;\n let titleTimer: ReturnType<typeof setInterval> | undefined;\n const wrappedUis = new WeakSet<ExtensionUIContext>();\n const stopTitleAnimation = (context: ExtensionContext) => {\n if (titleTimer) {\n clearInterval(titleTimer);\n titleTimer = undefined;\n }\n frameIndex = 0;\n if (context.hasUI) context.ui.setTitle(shellTabTitle(pi, context.cwd, firstPromptTitle));\n };\n const startTitleAnimation = (context: ExtensionContext) => {\n stopTitleAnimation(context);\n if (!context.hasUI) return;\n\n const renderFrame = () => {\n context.ui.setTitle(\n shellTabTitle(pi, context.cwd, firstPromptTitle, BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length]),\n );\n frameIndex += 1;\n };\n renderFrame();\n titleTimer = setInterval(renderFrame, TITLE_FRAME_INTERVAL_MS);\n };\n const notifyAttention = (body: string) => {\n void sendSystemNotification(pi, {\n title: 'Pi needs your input',\n subtitle: 'Approval or feedback required',\n body,\n });\n };\n\n pi.events.on(ASK_USER_PROMPT_EVENT, (payload) => {\n const prompt = payload as AskUserPromptEventPayload;\n const firstQuestion = prompt.questions[0]?.question ?? 'The agent is waiting for your feedback.';\n notifyAttention(firstQuestion);\n });\n pi.events.on(ASK_USER_BLOCKED_EVENT, (payload) => {\n askUserBlocked = (payload as AskUserBlockedEventPayload).active;\n });\n\n pi.on(INPUT_EVENT, (event, context) => {\n if (firstPromptTitle || event.source === EXTENSION_INPUT_SOURCE) return;\n\n firstPromptTitle = promptTitle(event.text);\n if (firstPromptTitle && context.hasUI) {\n context.ui.setTitle(shellTabTitle(pi, context.cwd, firstPromptTitle));\n }\n });\n\n pi.on('session_start', (_event, context) => {\n if (wrappedUis.has(context.ui)) return;\n wrappedUis.add(context.ui);\n wrapAttentionDialogs(context.ui, () => agentRunning && !askUserBlocked, notifyAttention);\n });\n\n pi.on('agent_start', (_event, context) => {\n agentRunning = true;\n startTitleAnimation(context);\n });\n\n pi.on('agent_settled', async (_event, context) => {\n agentRunning = false;\n askUserBlocked = false;\n stopTitleAnimation(context);\n if (context.hasPendingMessages()) return;\n\n await sendSystemNotification(pi, {\n title: 'Pi finished',\n subtitle: pi.getSessionName() ?? path.basename(context.cwd),\n body: 'The agent finished its work and is waiting for you.',\n });\n });\n\n pi.on('session_shutdown', (_event, context) => {\n agentRunning = false;\n askUserBlocked = false;\n stopTitleAnimation(context);\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region src/entries/notifications.d.ts
|
|
4
|
+
interface Notification {
|
|
5
|
+
title: string;
|
|
6
|
+
subtitle: string;
|
|
7
|
+
body: string;
|
|
8
|
+
}
|
|
9
|
+
declare function sendSystemNotification(pi: ExtensionAPI, notification: Notification, platform?: NodeJS.Platform): Promise<void>;
|
|
10
|
+
declare function notifications(pi: ExtensionAPI): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { notifications as default, sendSystemNotification };
|
|
13
|
+
//# sourceMappingURL=notifications.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.cts","names":[],"sources":["../../src/entries/notifications.ts"],"mappings":";;;UASU,YAAA;EACR,KAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,iBAyCoB,sBAAA,CACpB,EAAA,EAAI,YAAA,EACJ,YAAA,EAAc,YAAA,EACd,QAAA,GAAQ,MAAA,CAAA,QAAA,GACP,OAAA;AAAA,iBAwDqB,aAAA,CAAc,EAAA,EAAI,YAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region src/entries/notifications.d.ts
|
|
4
|
+
interface Notification {
|
|
5
|
+
title: string;
|
|
6
|
+
subtitle: string;
|
|
7
|
+
body: string;
|
|
8
|
+
}
|
|
9
|
+
declare function sendSystemNotification(pi: ExtensionAPI, notification: Notification, platform?: NodeJS.Platform): Promise<void>;
|
|
10
|
+
declare function notifications(pi: ExtensionAPI): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { notifications as default, sendSystemNotification };
|
|
13
|
+
//# sourceMappingURL=notifications.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.mts","names":[],"sources":["../../src/entries/notifications.ts"],"mappings":";;;UASU,YAAA;EACR,KAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,iBAyCoB,sBAAA,CACpB,EAAA,EAAI,YAAA,EACJ,YAAA,EAAc,YAAA,EACd,QAAA,GAAQ,MAAA,CAAA,QAAA,GACP,OAAA;AAAA,iBAwDqB,aAAA,CAAc,EAAA,EAAI,YAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ASK_USER_BLOCKED_EVENT as e,ASK_USER_PROMPT_EVENT as t}from"../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";import n from"node:path";const r=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`];function i(e){let t=e.replace(/\s+/g,` `).trim();if(t)return t.length>36?`${t.slice(0,35)}…`:t}function a(e,t,r,i){let a=i?`${i} `:``,o=n.basename(t),s=e.getSessionName()??r;return s?`${a}π - ${s} - ${o}`:`${a}π - ${o}`}function o(e){let t=e.replace(/\s+/g,` `).trim();return t.length>240?`${t.slice(0,239)}…`:t}async function s(e,t,n){try{return(await e.exec(t,n,{timeout:3e3})).code===0}catch{return!1}}async function c(e,t,n=process.platform){let r=o(t.body);await s(e,`cmux`,[`notify`,`--title`,t.title,`--subtitle`,t.subtitle,`--body`,r])||n!==`darwin`||await s(e,`osascript`,[`-e`,`on run argv`,`-e`,`display notification (item 3 of argv) with title (item 1 of argv) subtitle (item 2 of argv)`,`-e`,`end run`,t.title,t.subtitle,r])}function l(e,t,n){let r=e.confirm.bind(e);e.confirm=(e,i,a)=>(t()&&n(`${e}: ${i}`),r(e,i,a));let i=e.select.bind(e);e.select=(e,r,a)=>(t()&&n(e),i(e,r,a));let a=e.input.bind(e);e.input=(e,r,i)=>(t()&&n(e),a(e,r,i));let o=e.editor.bind(e);e.editor=(e,r)=>(t()&&n(e),o(e,r))}function u(o){if(process.env.PI_SUBAGENT_CHILD)return;let s=!1,u=!1,d,f=0,p,m=new WeakSet,h=e=>{p&&=(clearInterval(p),void 0),f=0,e.hasUI&&e.ui.setTitle(a(o,e.cwd,d))},g=e=>{if(h(e),!e.hasUI)return;let t=()=>{e.ui.setTitle(a(o,e.cwd,d,r[f%r.length])),f+=1};t(),p=setInterval(t,80)},_=e=>{c(o,{title:`Pi needs your input`,subtitle:`Approval or feedback required`,body:e})};o.events.on(t,e=>{_(e.questions[0]?.question??`The agent is waiting for your feedback.`)}),o.events.on(e,e=>{u=e.active}),o.on(`input`,(e,t)=>{d||e.source===`extension`||(d=i(e.text),d&&t.hasUI&&t.ui.setTitle(a(o,t.cwd,d)))}),o.on(`session_start`,(e,t)=>{m.has(t.ui)||(m.add(t.ui),l(t.ui,()=>s&&!u,_))}),o.on(`agent_start`,(e,t)=>{s=!0,g(t)}),o.on(`agent_settled`,async(e,t)=>{s=!1,u=!1,h(t),!t.hasPendingMessages()&&await c(o,{title:`Pi finished`,subtitle:o.getSessionName()??n.basename(t.cwd),body:`The agent finished its work and is waiting for you.`})}),o.on(`session_shutdown`,(e,t)=>{s=!1,u=!1,h(t)})}export{u as default,c as sendSystemNotification};
|
|
2
|
+
//# sourceMappingURL=notifications.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.mjs","names":["prompt"],"sources":["../../src/entries/notifications.ts"],"sourcesContent":["import path from 'node:path';\nimport type { ExtensionAPI, ExtensionContext, ExtensionUIContext } from '@earendil-works/pi-coding-agent';\nimport {\n ASK_USER_BLOCKED_EVENT,\n ASK_USER_PROMPT_EVENT,\n type AskUserBlockedEventPayload,\n type AskUserPromptEventPayload,\n} from '@juicesharp/rpiv-ask-user-question/events';\n\ninterface Notification {\n title: string;\n subtitle: string;\n body: string;\n}\n\nconst BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\nconst COMMAND_TIMEOUT_MS = 3_000;\nconst EXTENSION_INPUT_SOURCE = 'extension';\nconst INPUT_EVENT = 'input';\nconst MAX_BODY_LENGTH = 240;\nconst MAX_PROMPT_TITLE_LENGTH = 36;\nconst OSASCRIPT_EXPRESSION_FLAG = '-e';\nconst TITLE_FRAME_INTERVAL_MS = 80;\n\nfunction promptTitle(prompt: string): string | undefined {\n const normalized = prompt.replace(/\\s+/g, ' ').trim();\n if (!normalized) return undefined;\n return normalized.length > MAX_PROMPT_TITLE_LENGTH\n ? `${normalized.slice(0, MAX_PROMPT_TITLE_LENGTH - 1)}…`\n : normalized;\n}\n\nfunction shellTabTitle(pi: ExtensionAPI, cwd: string, prompt?: string, frame?: string): string {\n const prefix = frame ? `${frame} ` : '';\n const repository = path.basename(cwd);\n const label = pi.getSessionName() ?? prompt;\n return label ? `${prefix}π - ${label} - ${repository}` : `${prefix}π - ${repository}`;\n}\n\nfunction notificationBody(body: string): string {\n const normalized = body.replace(/\\s+/g, ' ').trim();\n return normalized.length > MAX_BODY_LENGTH ? `${normalized.slice(0, MAX_BODY_LENGTH - 1)}…` : normalized;\n}\n\nasync function execute(pi: ExtensionAPI, command: string, args: string[]): Promise<boolean> {\n try {\n const result = await pi.exec(command, args, { timeout: COMMAND_TIMEOUT_MS });\n return result.code === 0;\n } catch {\n return false;\n }\n}\n\nexport async function sendSystemNotification(\n pi: ExtensionAPI,\n notification: Notification,\n platform = process.platform,\n): Promise<void> {\n const body = notificationBody(notification.body);\n const sentToCmux = await execute(pi, 'cmux', [\n 'notify',\n '--title',\n notification.title,\n '--subtitle',\n notification.subtitle,\n '--body',\n body,\n ]);\n if (sentToCmux || platform !== 'darwin') return;\n\n await execute(pi, 'osascript', [\n OSASCRIPT_EXPRESSION_FLAG,\n 'on run argv',\n OSASCRIPT_EXPRESSION_FLAG,\n 'display notification (item 3 of argv) with title (item 1 of argv) subtitle (item 2 of argv)',\n OSASCRIPT_EXPRESSION_FLAG,\n 'end run',\n notification.title,\n notification.subtitle,\n body,\n ]);\n}\n\nfunction wrapAttentionDialogs(\n ui: ExtensionUIContext,\n shouldNotify: () => boolean,\n notify: (title: string) => void,\n): void {\n const originalConfirm = ui.confirm.bind(ui);\n ui.confirm = (title, message, options) => {\n if (shouldNotify()) notify(`${title}: ${message}`);\n return originalConfirm(title, message, options);\n };\n\n const originalSelect = ui.select.bind(ui);\n ui.select = (title, options, dialogOptions) => {\n if (shouldNotify()) notify(title);\n return originalSelect(title, options, dialogOptions);\n };\n\n const originalInput = ui.input.bind(ui);\n ui.input = (title, placeholder, options) => {\n if (shouldNotify()) notify(title);\n return originalInput(title, placeholder, options);\n };\n\n const originalEditor = ui.editor.bind(ui);\n ui.editor = (title, prefill) => {\n if (shouldNotify()) notify(title);\n return originalEditor(title, prefill);\n };\n}\n\nexport default function notifications(pi: ExtensionAPI): void {\n if (process.env.PI_SUBAGENT_CHILD) return;\n\n let agentRunning = false;\n let askUserBlocked = false;\n let firstPromptTitle: string | undefined;\n let frameIndex = 0;\n let titleTimer: ReturnType<typeof setInterval> | undefined;\n const wrappedUis = new WeakSet<ExtensionUIContext>();\n const stopTitleAnimation = (context: ExtensionContext) => {\n if (titleTimer) {\n clearInterval(titleTimer);\n titleTimer = undefined;\n }\n frameIndex = 0;\n if (context.hasUI) context.ui.setTitle(shellTabTitle(pi, context.cwd, firstPromptTitle));\n };\n const startTitleAnimation = (context: ExtensionContext) => {\n stopTitleAnimation(context);\n if (!context.hasUI) return;\n\n const renderFrame = () => {\n context.ui.setTitle(\n shellTabTitle(pi, context.cwd, firstPromptTitle, BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length]),\n );\n frameIndex += 1;\n };\n renderFrame();\n titleTimer = setInterval(renderFrame, TITLE_FRAME_INTERVAL_MS);\n };\n const notifyAttention = (body: string) => {\n void sendSystemNotification(pi, {\n title: 'Pi needs your input',\n subtitle: 'Approval or feedback required',\n body,\n });\n };\n\n pi.events.on(ASK_USER_PROMPT_EVENT, (payload) => {\n const prompt = payload as AskUserPromptEventPayload;\n const firstQuestion = prompt.questions[0]?.question ?? 'The agent is waiting for your feedback.';\n notifyAttention(firstQuestion);\n });\n pi.events.on(ASK_USER_BLOCKED_EVENT, (payload) => {\n askUserBlocked = (payload as AskUserBlockedEventPayload).active;\n });\n\n pi.on(INPUT_EVENT, (event, context) => {\n if (firstPromptTitle || event.source === EXTENSION_INPUT_SOURCE) return;\n\n firstPromptTitle = promptTitle(event.text);\n if (firstPromptTitle && context.hasUI) {\n context.ui.setTitle(shellTabTitle(pi, context.cwd, firstPromptTitle));\n }\n });\n\n pi.on('session_start', (_event, context) => {\n if (wrappedUis.has(context.ui)) return;\n wrappedUis.add(context.ui);\n wrapAttentionDialogs(context.ui, () => agentRunning && !askUserBlocked, notifyAttention);\n });\n\n pi.on('agent_start', (_event, context) => {\n agentRunning = true;\n startTitleAnimation(context);\n });\n\n pi.on('agent_settled', async (_event, context) => {\n agentRunning = false;\n askUserBlocked = false;\n stopTitleAnimation(context);\n if (context.hasPendingMessages()) return;\n\n await sendSystemNotification(pi, {\n title: 'Pi finished',\n subtitle: pi.getSessionName() ?? path.basename(context.cwd),\n body: 'The agent finished its work and is waiting for you.',\n });\n });\n\n pi.on('session_shutdown', (_event, context) => {\n agentRunning = false;\n askUserBlocked = false;\n stopTitleAnimation(context);\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t=process.argv.find(e=>e.startsWith(`ollama/`))?.slice(7)??`kimi-k2.6:cloud`;e.registerProvider(`ollama`,{name:`Ollama`,baseUrl:process.env.DOOMPI_OLLAMA_BASE_URL??`http://localhost:11434/v1`,apiKey:`$OLLAMA_API_KEY`,api:`openai-completions`,models:[{id:t,name:t,reasoning:!1,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:262144,maxTokens:32768,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!1}}]})}module.exports=e;
|
|
2
|
+
//# sourceMappingURL=ollamaProvider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollamaProvider.cjs","names":[],"sources":["../../src/entries/ollamaProvider.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nexport default function registerOllama(pi: ExtensionAPI): void {\n const modelArgument = process.argv.find((argument) => argument.startsWith('ollama/'));\n const model = modelArgument?.slice('ollama/'.length) ?? 'kimi-k2.6:cloud';\n pi.registerProvider('ollama', {\n name: 'Ollama',\n baseUrl: process.env.DOOMPI_OLLAMA_BASE_URL ?? 'http://localhost:11434/v1',\n apiKey: '$OLLAMA_API_KEY',\n api: 'openai-completions',\n models: [\n {\n id: model,\n name: model,\n reasoning: false,\n input: ['text', 'image'],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 262_144,\n maxTokens: 32_768,\n compat: {\n supportsDeveloperRole: false,\n supportsReasoningEffort: false,\n },\n },\n ],\n });\n}\n"],"mappings":"AAEA,SAAwB,EAAe,EAAwB,CAE7D,IAAM,EADgB,QAAQ,KAAK,KAAM,GAAa,EAAS,WAAW,UAAU,CACzD,EAAE,MAAM,EAAiB,EAAI,kBACxD,EAAG,iBAAiB,SAAU,CAC5B,KAAM,SACN,QAAS,QAAQ,IAAI,wBAA0B,4BAC/C,OAAQ,kBACR,IAAK,qBACL,OAAQ,CACN,CACE,GAAI,EACJ,KAAM,EACN,UAAW,GACX,MAAO,CAAC,OAAQ,QAAQ,CACxB,KAAM,CAAE,MAAO,EAAG,OAAQ,EAAG,UAAW,EAAG,WAAY,EAAG,CAC1D,cAAe,OACf,UAAW,MACX,OAAQ,CACN,sBAAuB,GACvB,wBAAyB,GAC1B,CACF,CACF,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollamaProvider.d.cts","names":[],"sources":["../../src/entries/ollamaProvider.ts"],"mappings":";;;iBAEwB,cAAA,CAAe,EAAA,EAAI,YAAA;AAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region src/entries/ollamaProvider.d.ts
|
|
4
|
+
declare function registerOllama(pi: ExtensionAPI): void;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { registerOllama as default };
|
|
7
|
+
//# sourceMappingURL=ollamaProvider.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollamaProvider.d.mts","names":[],"sources":["../../src/entries/ollamaProvider.ts"],"mappings":";;;iBAEwB,cAAA,CAAe,EAAA,EAAI,YAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t=process.argv.find(e=>e.startsWith(`ollama/`))?.slice(7)??`kimi-k2.6:cloud`;e.registerProvider(`ollama`,{name:`Ollama`,baseUrl:process.env.DOOMPI_OLLAMA_BASE_URL??`http://localhost:11434/v1`,apiKey:`$OLLAMA_API_KEY`,api:`openai-completions`,models:[{id:t,name:t,reasoning:!1,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:262144,maxTokens:32768,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!1}}]})}export{e as default};
|
|
2
|
+
//# sourceMappingURL=ollamaProvider.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollamaProvider.mjs","names":[],"sources":["../../src/entries/ollamaProvider.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nexport default function registerOllama(pi: ExtensionAPI): void {\n const modelArgument = process.argv.find((argument) => argument.startsWith('ollama/'));\n const model = modelArgument?.slice('ollama/'.length) ?? 'kimi-k2.6:cloud';\n pi.registerProvider('ollama', {\n name: 'Ollama',\n baseUrl: process.env.DOOMPI_OLLAMA_BASE_URL ?? 'http://localhost:11434/v1',\n apiKey: '$OLLAMA_API_KEY',\n api: 'openai-completions',\n models: [\n {\n id: model,\n name: model,\n reasoning: false,\n input: ['text', 'image'],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 262_144,\n maxTokens: 32_768,\n compat: {\n supportsDeveloperRole: false,\n supportsReasoningEffort: false,\n },\n },\n ],\n });\n}\n"],"mappings":"AAEA,SAAwB,EAAe,EAAwB,CAE7D,IAAM,EADgB,QAAQ,KAAK,KAAM,GAAa,EAAS,WAAW,UAAU,CACzD,EAAE,MAAM,EAAiB,EAAI,kBACxD,EAAG,iBAAiB,SAAU,CAC5B,KAAM,SACN,QAAS,QAAQ,IAAI,wBAA0B,4BAC/C,OAAQ,kBACR,IAAK,qBACL,OAAQ,CACN,CACE,GAAI,EACJ,KAAM,EACN,UAAW,GACX,MAAO,CAAC,OAAQ,QAAQ,CACxB,KAAM,CAAE,MAAO,EAAG,OAAQ,EAAG,UAAW,EAAG,WAAY,EAAG,CAC1D,cAAe,OACf,UAAW,MACX,OAAQ,CACN,sBAAuB,GACvB,wBAAyB,GAC1B,CACF,CACF,CACF,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../logSinkTelemetry.cjs`);let n=require(`node:fs`);n=e.__toESM(n,1);let r=require(`@agimon-ai/doompi-config`);function i(e,i=t.createHarnessTelemetry()){e.on(`before_agent_start`,async(e,a)=>{let{personaFile:o}=(0,r.requireDoomConfigContext)(a).harness;if(o)try{let t=n.default.readFileSync(o,`utf8`).trim();return t?{systemPrompt:`${e.systemPrompt}\n\n${t}`}:void 0}catch(e){let n=e instanceof Error?e.message:String(e);i.recordError(t.HARNESS_EVENT.personaReadFailed,e),process.stderr.write(`[pi-persona] could not read ${o}: ${n}\n`);return}})}module.exports=i;
|
|
2
|
+
//# sourceMappingURL=persona.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona.cjs","names":["createHarnessTelemetry","fs","HARNESS_EVENT"],"sources":["../../src/entries/persona.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\n\n/**\n * Appends the selected profile's persona to the system prompt.\n *\n * The harness writes the assembled persona to a file in the run directory and\n * records the path in the harness state, so agents/ stays the single source of\n * persona material and is never copied into config.\n */\nexport default function persona(pi: ExtensionAPI, telemetry: HarnessTelemetry = createHarnessTelemetry()): void {\n pi.on('before_agent_start', async (event, ctx) => {\n const { personaFile } = requireDoomConfigContext(ctx).harness;\n if (!personaFile) return undefined;\n\n try {\n const content = fs.readFileSync(personaFile, 'utf8').trim();\n return content ? { systemPrompt: `${event.systemPrompt}\\n\\n${content}` } : undefined;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(HARNESS_EVENT.personaReadFailed, error);\n process.stderr.write(`[pi-persona] could not read ${personaFile}: ${reason}\\n`);\n return undefined;\n }\n });\n}\n"],"mappings":"8KAYA,SAAwB,EAAQ,EAAkB,EAA8BA,EAAAA,wBAAwB,CAAQ,CAC9G,EAAG,GAAG,qBAAsB,MAAO,EAAO,IAAQ,CAChD,GAAM,CAAE,gBAAA,EAAA,EAAA,0BAAyC,EAAI,CAAC,QACjD,KAEL,GAAI,CACF,IAAM,EAAUC,EAAAA,QAAG,aAAa,EAAa,OAAO,CAAC,MAAM,CAC3D,OAAO,EAAU,CAAE,aAAc,GAAG,EAAM,aAAa,MAAM,IAAW,CAAG,IAAA,SACpE,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAChE,EAAU,YAAYC,EAAAA,cAAc,kBAAmB,EAAM,CAClE,QAAQ,OAAO,MAAM,+BAA+B,EAAY,IAAI,EAAO,IAAI,CAC/E,SAEF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.cjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
|
|
4
|
+
//#region src/entries/persona.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Appends the selected profile's persona to the system prompt.
|
|
7
|
+
*
|
|
8
|
+
* The harness writes the assembled persona to a file in the run directory and
|
|
9
|
+
* records the path in the harness state, so agents/ stays the single source of
|
|
10
|
+
* persona material and is never copied into config.
|
|
11
|
+
*/
|
|
12
|
+
declare function persona(pi: ExtensionAPI, telemetry?: HarnessTelemetry): void;
|
|
13
|
+
export = persona;
|
|
14
|
+
//# sourceMappingURL=persona.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona.d.cts","names":[],"sources":["../../src/entries/persona.ts"],"mappings":";;;;;;AAGsG;;;;;iBAS9E,OAAA,CAAQ,EAAA,EAAI,YAAA,EAAc,SAAA,GAAW,gBAAA;AAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.mjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
|
|
4
|
+
//#region src/entries/persona.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Appends the selected profile's persona to the system prompt.
|
|
7
|
+
*
|
|
8
|
+
* The harness writes the assembled persona to a file in the run directory and
|
|
9
|
+
* records the path in the harness state, so agents/ stays the single source of
|
|
10
|
+
* persona material and is never copied into config.
|
|
11
|
+
*/
|
|
12
|
+
declare function persona(pi: ExtensionAPI, telemetry?: HarnessTelemetry): void;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { persona as default };
|
|
15
|
+
//# sourceMappingURL=persona.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona.d.mts","names":[],"sources":["../../src/entries/persona.ts"],"mappings":";;;;;;AAGsG;;;;;iBAS9E,OAAA,CAAQ,EAAA,EAAI,YAAA,EAAc,SAAA,GAAW,gBAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{HARNESS_EVENT as e,createHarnessTelemetry as t}from"../logSinkTelemetry.mjs";import n from"node:fs";import{requireDoomConfigContext as r}from"@agimon-ai/doompi-config";function i(i,a=t()){i.on(`before_agent_start`,async(t,i)=>{let{personaFile:o}=r(i).harness;if(o)try{let e=n.readFileSync(o,`utf8`).trim();return e?{systemPrompt:`${t.systemPrompt}\n\n${e}`}:void 0}catch(t){let n=t instanceof Error?t.message:String(t);a.recordError(e.personaReadFailed,t),process.stderr.write(`[pi-persona] could not read ${o}: ${n}\n`);return}})}export{i as default};
|
|
2
|
+
//# sourceMappingURL=persona.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona.mjs","names":[],"sources":["../../src/entries/persona.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\n\n/**\n * Appends the selected profile's persona to the system prompt.\n *\n * The harness writes the assembled persona to a file in the run directory and\n * records the path in the harness state, so agents/ stays the single source of\n * persona material and is never copied into config.\n */\nexport default function persona(pi: ExtensionAPI, telemetry: HarnessTelemetry = createHarnessTelemetry()): void {\n pi.on('before_agent_start', async (event, ctx) => {\n const { personaFile } = requireDoomConfigContext(ctx).harness;\n if (!personaFile) return undefined;\n\n try {\n const content = fs.readFileSync(personaFile, 'utf8').trim();\n return content ? { systemPrompt: `${event.systemPrompt}\\n\\n${content}` } : undefined;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(HARNESS_EVENT.personaReadFailed, error);\n process.stderr.write(`[pi-persona] could not read ${personaFile}: ${reason}\\n`);\n return undefined;\n }\n });\n}\n"],"mappings":"+KAYA,SAAwB,EAAQ,EAAkB,EAA8B,GAAwB,CAAQ,CAC9G,EAAG,GAAG,qBAAsB,MAAO,EAAO,IAAQ,CAChD,GAAM,CAAE,eAAgB,EAAyB,EAAI,CAAC,QACjD,KAEL,GAAI,CACF,IAAM,EAAU,EAAG,aAAa,EAAa,OAAO,CAAC,MAAM,CAC3D,OAAO,EAAU,CAAE,aAAc,GAAG,EAAM,aAAa,MAAM,IAAW,CAAG,IAAA,SACpE,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAChE,EAAU,YAAY,EAAc,kBAAmB,EAAM,CAClE,QAAQ,OAAO,MAAM,+BAA+B,EAAY,IAAI,EAAO,IAAI,CAC/E,SAEF"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}}),require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../logSinkTelemetry.cjs`),t=require(`../config/harnessState.cjs`),n=require(`../services/matrixSwitcher.cjs`),r=require(`./components/matrixPicker.cjs`);let i=require(`@agimon-ai/doompi-config`),a=require(`@agimon-ai/doompi-config/profiles`);const o=`(none)`,s=`warning`,c=`info`,l=`.doom/profiles.yaml`;function u(e){return e.map(e=>({value:e.name,label:e.name,description:d(e)}))}function d(e){let t=Object.keys(e.env).sort();return t.length>0?`${e.persona} (env: ${t.join(`, `)})`:e.persona}function f(e){let t=Object.keys(e.env).sort();return[`Profile ${e.name}`,`Persona: ${e.persona}`,`Env: ${t.join(`, `)||o}`,`Already loaded.`].join(`
|
|
2
|
+
`)}function p(d,p=e.createHarnessTelemetry()){d.registerCommand(`profile`,{description:`Show profiles and load a different persona and environment`,handler:async(m,h)=>{let g=(0,i.requireDoomConfigContext)(h).harness,_=(0,i.requireHarnessRoot)(g),v=g.profile,y;try{y=(0,a.loadProfiles)(_)}catch(t){let n=t instanceof Error?t.message:String(t);p.recordError(e.HARNESS_EVENT.profileLoadFailed,t),h.ui.notify(`Could not load ${l}: ${n}`,s);return}if(y.length===0){h.ui.notify(`No profiles found in ${l}.`,s);return}let b=`Profile (current: ${v??o})`,x=(h.mode===`tui`?await h.ui.custom((e,t,n,i)=>new r.MatrixPickerComponent({title:b,items:u(y),selected:v?[v]:[],multi:!1},t,n,i)):[await h.ui.select(b,y.map(e=>e.name))])?.[0],S=y.find(e=>e.name===x);if(S){if(S.name===v){h.ui.notify(f(S),c);return}h.ui.notify(await n.applyProfile(S,g),c),t.persistHarnessSelection(d,{...g,profile:S.name}),p.recordEvent(e.HARNESS_EVENT.profileApplied,{"harness.profile":S.name,...v?{"harness.profile.previous":v}:{}}),await h.waitForIdle(),await h.reload()}}})}exports.applyProfile=n.applyProfile,exports.default=p,exports.profileDescription=d,exports.profileItems=u,exports.profileSummary=f;
|
|
3
|
+
//# sourceMappingURL=profile.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.cjs","names":["createHarnessTelemetry","HARNESS_EVENT","MatrixPickerComponent","applyProfile"],"sources":["../../src/entries/profile.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { SelectItem } from '@earendil-works/pi-tui';\nimport { type AgentProfile, loadProfiles } from '@agimon-ai/doompi-config/profiles';\nimport { persistHarnessSelection, requireHarnessRoot } from '../config/harnessState.ts';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport { applyProfile } from '../services/matrixSwitcher.ts';\nimport { MatrixPickerComponent } from './components/matrixPicker.ts';\n\nconst NONE = '(none)';\nconst WARNING = 'warning';\nconst INFO = 'info';\nconst PROFILE_CONFIG_PATH = '.doom/profiles.yaml';\n\n/** Rows for the single-select profile picker. */\nexport function profileItems(profiles: AgentProfile[]): SelectItem[] {\n return profiles.map((profile) => ({\n value: profile.name,\n label: profile.name,\n description: profileDescription(profile),\n }));\n}\n\nexport function profileDescription(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return environmentKeys.length > 0 ? `${profile.persona} (env: ${environmentKeys.join(', ')})` : profile.persona;\n}\n\n/** Shown when the picked profile is already active. */\nexport function profileSummary(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return [\n `Profile ${profile.name}`,\n `Persona: ${profile.persona}`,\n `Env: ${environmentKeys.join(', ') || NONE}`,\n 'Already loaded.',\n ].join('\\n');\n}\n\n/** Loads one profile's persona and environment defaults. */\nexport { applyProfile } from '../services/matrixSwitcher.ts';\n\nexport default function profileExtension(\n pi: ExtensionAPI,\n telemetry: HarnessTelemetry = createHarnessTelemetry(),\n): void {\n pi.registerCommand('profile', {\n description: 'Show profiles and load a different persona and environment',\n handler: async (_args, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n const root = requireHarnessRoot(state);\n const current = state.profile;\n let profiles: AgentProfile[];\n try {\n profiles = loadProfiles(root);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(HARNESS_EVENT.profileLoadFailed, error);\n ctx.ui.notify(`Could not load ${PROFILE_CONFIG_PATH}: ${reason}`, WARNING);\n return;\n }\n\n if (profiles.length === 0) {\n ctx.ui.notify(`No profiles found in ${PROFILE_CONFIG_PATH}.`, WARNING);\n return;\n }\n\n const title = `Profile (current: ${current ?? NONE})`;\n const chosen =\n ctx.mode === 'tui'\n ? await ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n { title, items: profileItems(profiles), selected: current ? [current] : [], multi: false },\n theme,\n keybindings,\n done,\n ),\n )\n : [\n await ctx.ui.select(\n title,\n profiles.map((profile) => profile.name),\n ),\n ];\n\n const picked = chosen?.[0];\n const profile = profiles.find((candidate) => candidate.name === picked);\n if (!profile) return;\n if (profile.name === current) {\n ctx.ui.notify(profileSummary(profile), INFO);\n return;\n }\n\n ctx.ui.notify(await applyProfile(profile, state), INFO);\n persistHarnessSelection(pi, { ...state, profile: profile.name });\n void telemetry.recordEvent(HARNESS_EVENT.profileApplied, {\n 'harness.profile': profile.name,\n ...(current ? { 'harness.profile.previous': current } : {}),\n });\n await ctx.waitForIdle();\n await ctx.reload();\n },\n });\n}\n"],"mappings":"+YASA,MAAM,EAAO,SACP,EAAU,UACV,EAAO,OACP,EAAsB,sBAG5B,SAAgB,EAAa,EAAwC,CACnE,OAAO,EAAS,IAAK,IAAa,CAChC,MAAO,EAAQ,KACf,MAAO,EAAQ,KACf,YAAa,EAAmB,EAAQ,CACzC,EAAE,CAGL,SAAgB,EAAmB,EAA+B,CAChE,IAAM,EAAkB,OAAO,KAAK,EAAQ,IAAI,CAAC,MAAM,CACvD,OAAO,EAAgB,OAAS,EAAI,GAAG,EAAQ,QAAQ,SAAS,EAAgB,KAAK,KAAK,CAAC,GAAK,EAAQ,QAI1G,SAAgB,EAAe,EAA+B,CAC5D,IAAM,EAAkB,OAAO,KAAK,EAAQ,IAAI,CAAC,MAAM,CACvD,MAAO,CACL,WAAW,EAAQ,OACnB,YAAY,EAAQ,UACpB,QAAQ,EAAgB,KAAK,KAAK,EAAI,IACtC,kBACD,CAAC,KAAK;EAAK,CAMd,SAAwB,EACtB,EACA,EAA8BA,EAAAA,wBAAwB,CAChD,CACN,EAAG,gBAAgB,UAAW,CAC5B,YAAa,6DACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,IAAM,GAAA,EAAA,EAAA,0BAAiC,EAAI,CAAC,QACtC,GAAA,EAAA,EAAA,oBAA0B,EAAM,CAChC,EAAU,EAAM,QAClB,EACJ,GAAI,CACF,GAAA,EAAA,EAAA,cAAwB,EAAK,OACtB,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAChE,EAAU,YAAYC,EAAAA,cAAc,kBAAmB,EAAM,CAClE,EAAI,GAAG,OAAO,kBAAkB,EAAoB,IAAI,IAAU,EAAQ,CAC1E,OAGF,GAAI,EAAS,SAAW,EAAG,CACzB,EAAI,GAAG,OAAO,wBAAwB,EAAoB,GAAI,EAAQ,CACtE,OAGF,IAAM,EAAQ,qBAAqB,GAAW,EAAK,GAmB7C,GAjBJ,EAAI,OAAS,MACT,MAAM,EAAI,GAAG,QACV,EAAM,EAAO,EAAa,IACzB,IAAIC,EAAAA,sBACF,CAAE,QAAO,MAAO,EAAa,EAAS,CAAE,SAAU,EAAU,CAAC,EAAQ,CAAG,EAAE,CAAE,MAAO,GAAO,CAC1F,EACA,EACA,EACD,CACJ,CACD,CACE,MAAM,EAAI,GAAG,OACX,EACA,EAAS,IAAK,GAAY,EAAQ,KAAK,CACxC,CACF,IAEiB,GAClB,EAAU,EAAS,KAAM,GAAc,EAAU,OAAS,EAAO,CAClE,KACL,IAAI,EAAQ,OAAS,EAAS,CAC5B,EAAI,GAAG,OAAO,EAAe,EAAQ,CAAE,EAAK,CAC5C,OAGF,EAAI,GAAG,OAAO,MAAMC,EAAAA,aAAa,EAAS,EAAM,CAAE,EAAK,CACvD,EAAA,wBAAwB,EAAI,CAAE,GAAG,EAAO,QAAS,EAAQ,KAAM,CAAC,CAC3D,EAAU,YAAYF,EAAAA,cAAc,eAAgB,CACvD,kBAAmB,EAAQ,KAC3B,GAAI,EAAU,CAAE,2BAA4B,EAAS,CAAG,EAAE,CAC3D,CAAC,CACF,MAAM,EAAI,aAAa,CACvB,MAAM,EAAI,QAAQ,GAErB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.cjs";
|
|
2
|
+
import { applyProfile } from "../services/matrixSwitcher.cjs";
|
|
3
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { AgentProfile } from "@agimon-ai/doompi-config/profiles";
|
|
5
|
+
import { SelectItem } from "@earendil-works/pi-tui";
|
|
6
|
+
|
|
7
|
+
//#region src/entries/profile.d.ts
|
|
8
|
+
/** Rows for the single-select profile picker. */
|
|
9
|
+
declare function profileItems(profiles: AgentProfile[]): SelectItem[];
|
|
10
|
+
declare function profileDescription(profile: AgentProfile): string;
|
|
11
|
+
/** Shown when the picked profile is already active. */
|
|
12
|
+
declare function profileSummary(profile: AgentProfile): string;
|
|
13
|
+
declare function profileExtension(pi: ExtensionAPI, telemetry?: HarnessTelemetry): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { applyProfile, profileExtension as default, profileDescription, profileItems, profileSummary };
|
|
16
|
+
//# sourceMappingURL=profile.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.cts","names":[],"sources":["../../src/entries/profile.ts"],"mappings":";;;;;;;;iBAegB,YAAA,CAAa,QAAA,EAAU,YAAA,KAAiB,UAAA;AAAA,iBAQxC,kBAAA,CAAmB,OAAA,EAAS,YAAA;AAR5C;AAAA,iBAcgB,cAAA,CAAe,OAAA,EAAS,YAAA;AAAA,iBAahB,gBAAA,CACtB,EAAA,EAAI,YAAA,EACJ,SAAA,GAAW,gBAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.mjs";
|
|
2
|
+
import { applyProfile } from "../services/matrixSwitcher.mjs";
|
|
3
|
+
import { AgentProfile } from "@agimon-ai/doompi-config/profiles";
|
|
4
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { SelectItem } from "@earendil-works/pi-tui";
|
|
6
|
+
|
|
7
|
+
//#region src/entries/profile.d.ts
|
|
8
|
+
/** Rows for the single-select profile picker. */
|
|
9
|
+
declare function profileItems(profiles: AgentProfile[]): SelectItem[];
|
|
10
|
+
declare function profileDescription(profile: AgentProfile): string;
|
|
11
|
+
/** Shown when the picked profile is already active. */
|
|
12
|
+
declare function profileSummary(profile: AgentProfile): string;
|
|
13
|
+
declare function profileExtension(pi: ExtensionAPI, telemetry?: HarnessTelemetry): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { applyProfile, profileExtension as default, profileDescription, profileItems, profileSummary };
|
|
16
|
+
//# sourceMappingURL=profile.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.mts","names":[],"sources":["../../src/entries/profile.ts"],"mappings":";;;;;;;;iBAegB,YAAA,CAAa,QAAA,EAAU,YAAA,KAAiB,UAAA;AAAA,iBAQxC,kBAAA,CAAmB,OAAA,EAAS,YAAA;AAR5C;AAAA,iBAcgB,cAAA,CAAe,OAAA,EAAS,YAAA;AAAA,iBAahB,gBAAA,CACtB,EAAA,EAAI,YAAA,EACJ,SAAA,GAAW,gBAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{HARNESS_EVENT as e,createHarnessTelemetry as t}from"../logSinkTelemetry.mjs";import{persistHarnessSelection as n,requireHarnessRoot as r}from"../config/harnessState.mjs";import{applyProfile as i}from"../services/matrixSwitcher.mjs";import{MatrixPickerComponent as a}from"./components/matrixPicker.mjs";import{requireDoomConfigContext as o}from"@agimon-ai/doompi-config";import{loadProfiles as s}from"@agimon-ai/doompi-config/profiles";const c=`(none)`,l=`warning`,u=`info`,d=`.doom/profiles.yaml`;function f(e){return e.map(e=>({value:e.name,label:e.name,description:p(e)}))}function p(e){let t=Object.keys(e.env).sort();return t.length>0?`${e.persona} (env: ${t.join(`, `)})`:e.persona}function m(e){let t=Object.keys(e.env).sort();return[`Profile ${e.name}`,`Persona: ${e.persona}`,`Env: ${t.join(`, `)||c}`,`Already loaded.`].join(`
|
|
2
|
+
`)}function h(p,h=t()){p.registerCommand(`profile`,{description:`Show profiles and load a different persona and environment`,handler:async(t,g)=>{let _=o(g).harness,v=r(_),y=_.profile,b;try{b=s(v)}catch(t){let n=t instanceof Error?t.message:String(t);h.recordError(e.profileLoadFailed,t),g.ui.notify(`Could not load ${d}: ${n}`,l);return}if(b.length===0){g.ui.notify(`No profiles found in ${d}.`,l);return}let x=`Profile (current: ${y??c})`,S=(g.mode===`tui`?await g.ui.custom((e,t,n,r)=>new a({title:x,items:f(b),selected:y?[y]:[],multi:!1},t,n,r)):[await g.ui.select(x,b.map(e=>e.name))])?.[0],C=b.find(e=>e.name===S);if(C){if(C.name===y){g.ui.notify(m(C),u);return}g.ui.notify(await i(C,_),u),n(p,{..._,profile:C.name}),h.recordEvent(e.profileApplied,{"harness.profile":C.name,...y?{"harness.profile.previous":y}:{}}),await g.waitForIdle(),await g.reload()}}})}export{i as applyProfile,h as default,p as profileDescription,f as profileItems,m as profileSummary};
|
|
3
|
+
//# sourceMappingURL=profile.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.mjs","names":[],"sources":["../../src/entries/profile.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { SelectItem } from '@earendil-works/pi-tui';\nimport { type AgentProfile, loadProfiles } from '@agimon-ai/doompi-config/profiles';\nimport { persistHarnessSelection, requireHarnessRoot } from '../config/harnessState.ts';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport { applyProfile } from '../services/matrixSwitcher.ts';\nimport { MatrixPickerComponent } from './components/matrixPicker.ts';\n\nconst NONE = '(none)';\nconst WARNING = 'warning';\nconst INFO = 'info';\nconst PROFILE_CONFIG_PATH = '.doom/profiles.yaml';\n\n/** Rows for the single-select profile picker. */\nexport function profileItems(profiles: AgentProfile[]): SelectItem[] {\n return profiles.map((profile) => ({\n value: profile.name,\n label: profile.name,\n description: profileDescription(profile),\n }));\n}\n\nexport function profileDescription(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return environmentKeys.length > 0 ? `${profile.persona} (env: ${environmentKeys.join(', ')})` : profile.persona;\n}\n\n/** Shown when the picked profile is already active. */\nexport function profileSummary(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return [\n `Profile ${profile.name}`,\n `Persona: ${profile.persona}`,\n `Env: ${environmentKeys.join(', ') || NONE}`,\n 'Already loaded.',\n ].join('\\n');\n}\n\n/** Loads one profile's persona and environment defaults. */\nexport { applyProfile } from '../services/matrixSwitcher.ts';\n\nexport default function profileExtension(\n pi: ExtensionAPI,\n telemetry: HarnessTelemetry = createHarnessTelemetry(),\n): void {\n pi.registerCommand('profile', {\n description: 'Show profiles and load a different persona and environment',\n handler: async (_args, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n const root = requireHarnessRoot(state);\n const current = state.profile;\n let profiles: AgentProfile[];\n try {\n profiles = loadProfiles(root);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(HARNESS_EVENT.profileLoadFailed, error);\n ctx.ui.notify(`Could not load ${PROFILE_CONFIG_PATH}: ${reason}`, WARNING);\n return;\n }\n\n if (profiles.length === 0) {\n ctx.ui.notify(`No profiles found in ${PROFILE_CONFIG_PATH}.`, WARNING);\n return;\n }\n\n const title = `Profile (current: ${current ?? NONE})`;\n const chosen =\n ctx.mode === 'tui'\n ? await ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n { title, items: profileItems(profiles), selected: current ? [current] : [], multi: false },\n theme,\n keybindings,\n done,\n ),\n )\n : [\n await ctx.ui.select(\n title,\n profiles.map((profile) => profile.name),\n ),\n ];\n\n const picked = chosen?.[0];\n const profile = profiles.find((candidate) => candidate.name === picked);\n if (!profile) return;\n if (profile.name === current) {\n ctx.ui.notify(profileSummary(profile), INFO);\n return;\n }\n\n ctx.ui.notify(await applyProfile(profile, state), INFO);\n persistHarnessSelection(pi, { ...state, profile: profile.name });\n void telemetry.recordEvent(HARNESS_EVENT.profileApplied, {\n 'harness.profile': profile.name,\n ...(current ? { 'harness.profile.previous': current } : {}),\n });\n await ctx.waitForIdle();\n await ctx.reload();\n },\n });\n}\n"],"mappings":"0bASA,MAAM,EAAO,SACP,EAAU,UACV,EAAO,OACP,EAAsB,sBAG5B,SAAgB,EAAa,EAAwC,CACnE,OAAO,EAAS,IAAK,IAAa,CAChC,MAAO,EAAQ,KACf,MAAO,EAAQ,KACf,YAAa,EAAmB,EAAQ,CACzC,EAAE,CAGL,SAAgB,EAAmB,EAA+B,CAChE,IAAM,EAAkB,OAAO,KAAK,EAAQ,IAAI,CAAC,MAAM,CACvD,OAAO,EAAgB,OAAS,EAAI,GAAG,EAAQ,QAAQ,SAAS,EAAgB,KAAK,KAAK,CAAC,GAAK,EAAQ,QAI1G,SAAgB,EAAe,EAA+B,CAC5D,IAAM,EAAkB,OAAO,KAAK,EAAQ,IAAI,CAAC,MAAM,CACvD,MAAO,CACL,WAAW,EAAQ,OACnB,YAAY,EAAQ,UACpB,QAAQ,EAAgB,KAAK,KAAK,EAAI,IACtC,kBACD,CAAC,KAAK;EAAK,CAMd,SAAwB,EACtB,EACA,EAA8B,GAAwB,CAChD,CACN,EAAG,gBAAgB,UAAW,CAC5B,YAAa,6DACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,IAAM,EAAQ,EAAyB,EAAI,CAAC,QACtC,EAAO,EAAmB,EAAM,CAChC,EAAU,EAAM,QAClB,EACJ,GAAI,CACF,EAAW,EAAa,EAAK,OACtB,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAChE,EAAU,YAAY,EAAc,kBAAmB,EAAM,CAClE,EAAI,GAAG,OAAO,kBAAkB,EAAoB,IAAI,IAAU,EAAQ,CAC1E,OAGF,GAAI,EAAS,SAAW,EAAG,CACzB,EAAI,GAAG,OAAO,wBAAwB,EAAoB,GAAI,EAAQ,CACtE,OAGF,IAAM,EAAQ,qBAAqB,GAAW,EAAK,GAmB7C,GAjBJ,EAAI,OAAS,MACT,MAAM,EAAI,GAAG,QACV,EAAM,EAAO,EAAa,IACzB,IAAI,EACF,CAAE,QAAO,MAAO,EAAa,EAAS,CAAE,SAAU,EAAU,CAAC,EAAQ,CAAG,EAAE,CAAE,MAAO,GAAO,CAC1F,EACA,EACA,EACD,CACJ,CACD,CACE,MAAM,EAAI,GAAG,OACX,EACA,EAAS,IAAK,GAAY,EAAQ,KAAK,CACxC,CACF,IAEiB,GAClB,EAAU,EAAS,KAAM,GAAc,EAAU,OAAS,EAAO,CAClE,KACL,IAAI,EAAQ,OAAS,EAAS,CAC5B,EAAI,GAAG,OAAO,EAAe,EAAQ,CAAE,EAAK,CAC5C,OAGF,EAAI,GAAG,OAAO,MAAM,EAAa,EAAS,EAAM,CAAE,EAAK,CACvD,EAAwB,EAAI,CAAE,GAAG,EAAO,QAAS,EAAQ,KAAM,CAAC,CAC3D,EAAU,YAAY,EAAc,eAAgB,CACvD,kBAAmB,EAAQ,KAC3B,GAAI,EAAU,CAAE,2BAA4B,EAAS,CAAG,EAAE,CAC3D,CAAC,CACF,MAAM,EAAI,aAAa,CACvB,MAAM,EAAI,QAAQ,GAErB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../logSinkTelemetry.cjs`),n=require(`../utils/toolNames.cjs`);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`@agimon-ai/doompi-config`),a=require(`yaml`),o=require(`node:child_process`),s=require(`@agimon-ai/doompi-config/layeredConfig`);const c=`ESRCH`,l={sessionStart:`SessionStart`,preToolUse:`PreToolUse`,postToolUse:`PostToolUse`,stop:`Stop`,sessionEnd:`SessionEnd`};let u,d=[];const f=new Map;function p(e,t){let n=(0,i.requireDoomConfigContext)(e).harness;return{repoRoot:n.root??e.cwd,harness:n,telemetry:t,failures:[]}}function m(e,t,r,i){return{session_id:i,transcript_path:``,cwd:r,hook_event_name:t,tool_name:n.toClaudeToolName(e.toolName),tool_input:e.input,...e.type===`tool_result`?{tool_response:{success:!e.isError,content:e.content}}:{}}}async function h(e,n,r,i){let{repoRoot:a,telemetry:s}=r;return new Promise(r=>{let l=process.platform!==`win32`,u=(0,o.spawn)(`/bin/bash`,[`-c`,e.command],{cwd:a,env:{...process.env,CLAUDE_PROJECT_DIR:a,CODEX_REPO_ROOT:a,ORIGINAL_REPO_PATH:process.env.ORIGINAL_REPO_PATH??a,...i?{CLAUDE_PLUGIN_ROOT:i}:{}},stdio:[`pipe`,`pipe`,`pipe`],detached:l}),d=``,f=``,p=!1,m=!1,h=!1,g=null,_,v=e=>{try{if(l&&u.pid!==void 0){process.kill(-u.pid,e);return}u.kill(e)}catch(e){(e instanceof Error&&`code`in e?e.code:void 0)!==c&&process.emitWarning(`Could not signal repository hook process: ${String(e)}`)}},y=()=>{if(!l||u.pid===void 0)return!h;try{return process.kill(-u.pid,0),!0}catch(e){return(e instanceof Error&&`code`in e?e.code:void 0)!==c}},b=(e={})=>{p||(p=!0,clearTimeout(S),_&&clearTimeout(_),r(e))},x=()=>{let n=`Hook timed out after ${e.timeout??10} seconds.`;s?.recordWarning(t.HARNESS_EVENT.hookFailed,n,{"hook.reason":`timeout`,"hook.exit_code":g??-1}),process.stderr.write(`[pi-hook] advisory hook timed out: ${e.command}\n${f}`),b({failure:{command:e.command,message:n,reason:`timeout`}})},S=setTimeout(()=>{m=!0,v(`SIGTERM`),_=setTimeout(()=>{y()&&v(`SIGKILL`),x()},2e3)},(e.timeout??10)*1e3);u.stdout.on(`data`,e=>{d+=e.toString()}),u.stderr.on(`data`,e=>{f+=e.toString()}),u.once(`error`,n=>{m||(s?.recordError(t.HARNESS_EVENT.hookFailed,n,{"hook.reason":`spawn_failed`}),process.stderr.write(`[pi-hook] advisory hook failed: ${n.message}\n`),b({failure:{command:e.command,message:n.message,reason:`spawn_failed`}}))}),u.once(`exit`,n=>{if(h=!0,g=n,m)return;if(n!==0){let r=f.trim()||`Advisory hook exited with code ${n??`unknown`}`;s?.recordWarning(t.HARNESS_EVENT.hookFailed,r,{"hook.reason":`non_zero_exit`,"hook.exit_code":n??-1}),process.stderr.write(`[pi-hook] advisory hook failed (${n}): ${e.command}\n${f}`),b({failure:{command:e.command,message:r,reason:`non_zero_exit`}});return}let r=d.trim().split(/\r?\n/).reverse().find(e=>e.startsWith(`{`));if(!r){b();return}try{b({decision:JSON.parse(r)})}catch(n){s?.recordWarning(t.HARNESS_EVENT.hookFailed,n,{"hook.reason":`invalid_json`}),process.stderr.write(`[pi-hook] advisory hook returned invalid JSON: ${e.command}\n`),b({failure:{command:e.command,message:n instanceof Error?n.message:String(n),reason:`invalid_json`}})}}),u.stdin.end(JSON.stringify(n))})}function g(e){return e?.decision===`block`||e?.hookSpecificOutput?.permissionDecision===`deny`}function _(e){return e?.reason??e?.hookSpecificOutput?.reason}function v(e){let t=r.default.readFileSync(e,`utf8`),n=f.get(e);if(n?.source===t)return n.config;let i=JSON.parse(t);return f.set(e,{source:t,config:i}),i}function y(e,t,r){let i=[];for(let a of t.harness.pluginHooks){let o;try{o=v(a.configPath)}catch(e){t.failures.push({command:a.configPath,message:e instanceof Error?e.message:String(e),reason:`plugin_config`});continue}for(let t of o.hooks?.[e]??[])if(!(r&&t.matcher&&!new RegExp(t.matcher).test(n.toClaudeToolName(r))))for(let e of t.hooks??[])i.push({hook:e,root:a.pluginRoot})}return i}function b(e){let t=e.map(e=>`${e.baseDirectory} ${e.text}`).join(` `);if(u===t)return d;let n=new Map,r=0;for(let t of e){let e=(0,a.parse)(t.text)??{};for(let[i,a]of Object.entries(e.groups??{})){let e=[];for(let n of a.hooks??[])r+=1,n.pi&&e.push({...n.pi,event:n.event,order:n.pi.order??0,position:r,groupId:i,core:a.core===!0,baseDirectory:t.baseDirectory});n.set(i,{entries:e})}}let i=[...n.values()].flatMap(e=>e.entries);return i.sort((e,t)=>e.order-t.order||e.position-t.position),u=t,d=i,i}function x(e){let{repoRoot:n,harness:i,telemetry:a}=e,o=(0,s.doomConfigCandidates)(`hooks.yaml`,n),c=o.map(e=>e.filePath).join(` and `);try{let e=i.hookGroups,t=e===void 0?void 0:new Set(e);return b(o.filter(e=>r.default.existsSync(e.filePath)).map(e=>({baseDirectory:e.baseDirectory,text:r.default.readFileSync(e.filePath,`utf8`)}))).filter(e=>e.core||!t||t.has(e.groupId))}catch(n){let r=n instanceof Error?n.message:String(n);return a?.recordError(t.HARNESS_EVENT.hookRegistryReadFailed,n,{"hook.registry.source":`repository`}),process.stderr.write(`[pi-hook] could not read ${c}: ${r}\n`),e.failures.push({command:c,message:r,reason:`registry_read`}),[]}}function S(e,t,r){return x(t).filter(t=>t.event===e).filter(e=>!(e.skipInSubagent&&process.env.PI_SUBAGENT_CHILD)).filter(e=>!r||!e.matcher||new RegExp(e.matcher).test(n.toClaudeToolName(r))).map(e=>({hook:{command:e.command,timeout:e.timeout},root:e.baseDirectory}))}async function C(e,t,n,r,i,a){let o=[];try{for(let[s,c]of e.entries())r.hasUI&&r.ui.setStatus(i,`${a} (${s+1}/${e.length})...`),o.push(await h(c.hook,t,n,c.root))}finally{r.hasUI&&r.ui.setStatus(i,void 0)}return o}function w(e,t,n){return[...S(e,t,n).map(({hook:e,root:t})=>({hook:e,root:t})),...y(e,t,n).map(({hook:e,root:t})=>({hook:e,root:t}))]}function T(e){return e.flatMap(e=>e.decision?[e.decision]:[])}function E(e){return e.map(e=>e.hookSpecificOutput?.additionalContext).filter(e=>!!e)}function D(e,t){return[...e.failures,...t.flatMap(e=>e.failure?[e.failure]:[])]}function O(e){return[`One or more repository hooks did not complete, so their checks were not applied:`,...e.map(e=>`- ${e.command}: ${e.message}`),`Options:`,`- Inspect the hook command or configuration and rerun after correcting it.`,`- Continue only if the missed advisory check is acceptable.`,`- Ask the user before bypassing a hook that may enforce a guardrail.`].join(`
|
|
2
|
+
`)}function k(e,t){t.length!==0&&e.sendMessage({customType:`repository-hook-failure`,content:O(t),display:!0},{deliverAs:`steer`})}function A(e,n=t.createHarnessTelemetry()){e.on(`session_start`,async(t,r)=>{let i=p(r,n),a=r.sessionManager.getSessionId(),o={session_id:a,cwd:i.repoRoot},s=await C(w(l.sessionStart,i),o,i,r,`repository-hooks:${a}:start`,`Running session-start hooks`);k(e,D(i,s));let c=E(T(s)).join(`
|
|
3
|
+
|
|
4
|
+
`);c&&e.sendMessage({customType:`repository-hook-context`,content:c,display:!0},{deliverAs:`steer`})}),e.on(`tool_call`,async(t,r)=>{let i=p(r,n),a=m(t,l.preToolUse,i.repoRoot,r.sessionManager.getSessionId()),o=await C(w(l.preToolUse,i,t.toolName),a,i,r,`repository-hooks:${t.toolCallId}:pre`,`Running pre-tool hooks for ${t.toolName}`),s=T(o);k(e,D(i,o));let c=s.find(g);if(c)return{block:!0,reason:_(c)??`Blocked by repository hook`};let u=E(s).join(`
|
|
5
|
+
|
|
6
|
+
`);if(u)return{block:!0,reason:u}}),e.on(`tool_result`,async(e,t)=>{let r=p(t,n),i=m(e,l.postToolUse,r.repoRoot,t.sessionManager.getSessionId()),a=await C(w(l.postToolUse,r,e.toolName),i,r,t,`repository-hooks:${e.toolCallId}:post`,`Running post-tool hooks for ${e.toolName}`),o=T(a),s=D(r,a),c=o.map(e=>e.hookSpecificOutput?.additionalContext??_(e)).filter(e=>!!e);if(s.length>0&&c.push(O(s)),c.length!==0)return{content:[...e.content,{type:`text`,text:c.join(`
|
|
7
|
+
|
|
8
|
+
`)}],isError:e.isError||o.some(g)}}),e.on(`agent_settled`,async(e,t)=>{let r=p(t,n),i=t.sessionManager.getSessionId(),a={session_id:i,cwd:r.repoRoot};await C(w(l.stop,r),a,r,t,`repository-hooks:${i}:stop`,`Running stop hooks`)}),e.on(`session_shutdown`,async(e,t)=>{let r=p(t,n),i=t.sessionManager.getSessionId(),a={session_id:i,cwd:r.repoRoot};await C(y(l.sessionEnd,r).map(({hook:e,root:t})=>({hook:e,root:t})),a,r,t,`repository-hooks:${i}:end`,`Running session-end hooks`)})}module.exports=A;
|
|
9
|
+
//# sourceMappingURL=repositoryHooks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryHooks.cjs","names":["toClaudeToolName","HARNESS_EVENT","fs","createHarnessTelemetry"],"sources":["../../src/entries/repositoryHooks.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { requireDoomConfigContext, type DoomHarnessContext } from '@agimon-ai/doompi-config';\nimport { doomConfigCandidates } from '@agimon-ai/doompi-config/layeredConfig';\nimport type { ExtensionAPI, ExtensionContext, ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\nimport { parse as parseYaml } from 'yaml';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\n// Imported from the module rather than the utils barrel: Pi loads this file\n// directly, so pulling in the barrel would load module resolution helpers the\n// extension never uses.\nimport { toClaudeToolName } from '../utils/toolNames.ts';\n\nconst HOOKS_FILE = 'hooks.yaml';\nconst HOOK_SHELL = '/bin/bash';\nconst HOOK_SHELL_COMMAND_FLAG = '-c';\nconst HOOK_TERMINATION_GRACE_MS = 2_000;\nconst PROCESS_NOT_FOUND_ERROR = 'ESRCH';\n\n/** Registry event names. Each is used twice per dispatch, so drift would be silent. */\nconst HOOK_EVENT = {\n sessionStart: 'SessionStart',\n preToolUse: 'PreToolUse',\n postToolUse: 'PostToolUse',\n stop: 'Stop',\n sessionEnd: 'SessionEnd',\n} as const;\n\ninterface HookCommand {\n command: string;\n timeout?: number;\n}\n\ninterface RegistryBinding {\n matcher?: string;\n command: string;\n timeout?: number;\n skipInSubagent?: boolean;\n order?: number;\n}\n\ninterface RegistryRow extends RegistryBinding {\n event: string;\n order: number;\n position: number;\n}\n\n/** A registry row plus the group membership used to include or drop it. */\ninterface RegistryEntry extends RegistryRow {\n groupId: string;\n core: boolean;\n /** Root of the config that declared the group, exported as CLAUDE_PLUGIN_ROOT. */\n baseDirectory: string;\n}\n\ninterface HookGroup {\n matcher?: string;\n hooks?: HookCommand[];\n}\n\ninterface PluginHookConfig {\n hooks?: Record<string, HookGroup[]>;\n}\n\ninterface RegistryDocument {\n groups?: Record<string, { core?: boolean; hooks?: Array<{ event: string; pi?: RegistryBinding }> }>;\n}\n\n// Parsing the registry is the most expensive step on the tool-call path, and it\n// runs twice per tool call (once before, once after). Both caches are keyed on\n// file contents rather than mtime, so they stay correct for an in-place rewrite\n// and need no invalidation hook.\nlet cachedRegistrySource: string | undefined;\nlet cachedRegistryEntries: RegistryEntry[] = [];\nconst pluginConfigCache = new Map<string, { source: string; config: PluginHookConfig }>();\n\ninterface HookDecision {\n decision?: string;\n reason?: string;\n hookSpecificOutput?: {\n permissionDecision?: string;\n reason?: string;\n additionalContext?: string;\n };\n}\n\ninterface HookRuntime {\n repoRoot: string;\n harness: DoomHarnessContext;\n telemetry: HarnessTelemetry;\n failures: HookFailure[];\n}\n\ninterface HookFailure {\n command: string;\n message: string;\n reason: 'spawn_failed' | 'non_zero_exit' | 'timeout' | 'invalid_json' | 'registry_read' | 'plugin_config';\n}\n\ninterface HookOutcome {\n decision?: HookDecision;\n failure?: HookFailure;\n}\n\ninterface ResolvedHook {\n hook: HookCommand;\n root?: string;\n}\n\nfunction hookRuntime(ctx: ExtensionContext, telemetry: HarnessTelemetry): HookRuntime {\n const harness = requireDoomConfigContext(ctx).harness;\n return { repoRoot: harness.root ?? ctx.cwd, harness, telemetry, failures: [] };\n}\n\nfunction hookPayload(\n event: ToolCallEvent | ToolResultEvent,\n hookEventName: string,\n repoRoot: string,\n sessionId: string,\n): Record<string, unknown> {\n return {\n session_id: sessionId,\n transcript_path: '',\n cwd: repoRoot,\n hook_event_name: hookEventName,\n tool_name: toClaudeToolName(event.toolName),\n tool_input: event.input,\n ...(event.type === 'tool_result' ? { tool_response: { success: !event.isError, content: event.content } } : {}),\n };\n}\n\nasync function executeHook(\n hook: HookCommand,\n payload: Record<string, unknown>,\n runtime: HookRuntime,\n pluginRoot?: string,\n): Promise<HookOutcome> {\n const { repoRoot, telemetry } = runtime;\n return new Promise((resolve) => {\n const useProcessGroup = process.platform !== 'win32';\n // -c, not -lc. Hooks run on every tool call, and a login shell would source\n // the developer's profile each time: per-call latency plus hook behavior\n // that varies with their dotfiles. The child inherits process.env below, so\n // it keeps the PATH the launcher was started with.\n const child = spawn(HOOK_SHELL, [HOOK_SHELL_COMMAND_FLAG, hook.command], {\n cwd: repoRoot,\n env: {\n ...process.env,\n CLAUDE_PROJECT_DIR: repoRoot,\n CODEX_REPO_ROOT: repoRoot,\n ORIGINAL_REPO_PATH: process.env.ORIGINAL_REPO_PATH ?? repoRoot,\n ...(pluginRoot ? { CLAUDE_PLUGIN_ROOT: pluginRoot } : {}),\n },\n stdio: ['pipe', 'pipe', 'pipe'],\n detached: useProcessGroup,\n });\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n let childExited = false;\n let timeoutExitCode: number | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n\n const signalOwnedProcess = (signal: NodeJS.Signals): void => {\n try {\n if (useProcessGroup && child.pid !== undefined) {\n process.kill(-child.pid, signal);\n return;\n }\n child.kill(signal);\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? error.code : undefined;\n if (code !== PROCESS_NOT_FOUND_ERROR) {\n process.emitWarning(`Could not signal repository hook process: ${String(error)}`);\n }\n }\n };\n\n const ownedProcessIsAlive = (): boolean => {\n if (!useProcessGroup || child.pid === undefined) return !childExited;\n try {\n process.kill(-child.pid, 0);\n return true;\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? error.code : undefined;\n return code !== PROCESS_NOT_FOUND_ERROR;\n }\n };\n\n const finish = (outcome: HookOutcome = {}) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (escalationTimer) clearTimeout(escalationTimer);\n resolve(outcome);\n };\n\n const finishTimeout = (): void => {\n const message = `Hook timed out after ${hook.timeout ?? 10} seconds.`;\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, message, {\n 'hook.reason': 'timeout',\n 'hook.exit_code': timeoutExitCode ?? -1,\n });\n process.stderr.write(`[pi-hook] advisory hook timed out: ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'timeout' } });\n };\n\n const timer = setTimeout(\n () => {\n timedOut = true;\n signalOwnedProcess('SIGTERM');\n escalationTimer = setTimeout(() => {\n if (ownedProcessIsAlive()) signalOwnedProcess('SIGKILL');\n finishTimeout();\n }, HOOK_TERMINATION_GRACE_MS);\n },\n (hook.timeout ?? 10) * 1000,\n );\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (error) => {\n if (timedOut) return;\n // A guardrail that never ran is indistinguishable from one that passed,\n // which is the whole reason these are worth reporting.\n void telemetry?.recordError(HARNESS_EVENT.hookFailed, error, {\n 'hook.reason': 'spawn_failed',\n });\n process.stderr.write(`[pi-hook] advisory hook failed: ${error.message}\\n`);\n finish({ failure: { command: hook.command, message: error.message, reason: 'spawn_failed' } });\n });\n child.once('exit', (code) => {\n childExited = true;\n timeoutExitCode = code;\n if (timedOut) return;\n if (code !== 0) {\n const message = stderr.trim() || `Advisory hook exited with code ${code ?? 'unknown'}`;\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, message, {\n 'hook.reason': 'non_zero_exit',\n 'hook.exit_code': code ?? -1,\n });\n process.stderr.write(`[pi-hook] advisory hook failed (${code}): ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'non_zero_exit' } });\n return;\n }\n const jsonLine = stdout\n .trim()\n .split(/\\r?\\n/)\n .reverse()\n .find((line) => line.startsWith('{'));\n if (!jsonLine) {\n finish();\n return;\n }\n try {\n finish({ decision: JSON.parse(jsonLine) as HookDecision });\n } catch (error) {\n // The hook ran and had an opinion, and it was dropped.\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, error, {\n 'hook.reason': 'invalid_json',\n });\n process.stderr.write(`[pi-hook] advisory hook returned invalid JSON: ${hook.command}\\n`);\n finish({\n failure: {\n command: hook.command,\n message: error instanceof Error ? error.message : String(error),\n reason: 'invalid_json',\n },\n });\n }\n });\n child.stdin.end(JSON.stringify(payload));\n });\n}\n\nfunction isDenied(decision: HookDecision | undefined): boolean {\n return decision?.decision === 'block' || decision?.hookSpecificOutput?.permissionDecision === 'deny';\n}\n\nfunction decisionReason(decision: HookDecision | undefined): string | undefined {\n return decision?.reason ?? decision?.hookSpecificOutput?.reason;\n}\n\n/**\n * Parses a plugin hook config, reusing the last parse of identical content.\n *\n * Reading the file every time is deliberate: it costs almost nothing and keeps\n * an in-place rewrite visible, which an mtime check would miss when two writes\n * land inside the same filesystem timestamp granularity.\n */\nfunction readPluginHookConfig(configPath: string): PluginHookConfig {\n const source = fs.readFileSync(configPath, 'utf8');\n const cached = pluginConfigCache.get(configPath);\n if (cached?.source === source) return cached.config;\n const config = JSON.parse(source) as PluginHookConfig;\n pluginConfigCache.set(configPath, { source, config });\n return config;\n}\n\nfunction pluginHooks(\n eventName: string,\n runtime: HookRuntime,\n toolName?: string,\n): Array<{ hook: HookCommand; root: string }> {\n const matches: Array<{ hook: HookCommand; root: string }> = [];\n for (const source of runtime.harness.pluginHooks) {\n let config: PluginHookConfig;\n try {\n config = readPluginHookConfig(source.configPath);\n } catch (error) {\n runtime.failures.push({\n command: source.configPath,\n message: error instanceof Error ? error.message : String(error),\n reason: 'plugin_config',\n });\n continue;\n }\n for (const group of config.hooks?.[eventName] ?? []) {\n if (toolName && group.matcher && !new RegExp(group.matcher).test(toClaudeToolName(toolName))) continue;\n for (const hook of group.hooks ?? []) matches.push({ hook, root: source.pluginRoot });\n }\n }\n return matches;\n}\n\n// Reads the canonical registry from .doom/hooks.yaml in the global config\n// directory and the repository, keeping only bindings that declare a `pi`\n// frontend. A repository group replaces the global group of the same id. Core\n// groups always load; the rest are gated by DOOMPI_HOOK_GROUPS, which the\n// harness sets from the resolved layers. An unset variable means every group,\n// which is the standalone default.\nfunction parseRegistry(sources: ReadonlyArray<{ baseDirectory: string; text: string }>): RegistryEntry[] {\n // Keyed on the joined contents rather than mtime, so it stays correct for an\n // in-place rewrite. Reading both files is cheap; parsing is what this skips.\n const cacheKey = sources.map((source) => `${source.baseDirectory} ${source.text}`).join(' ');\n if (cachedRegistrySource === cacheKey) return cachedRegistryEntries;\n\n const groups = new Map<string, { entries: RegistryEntry[] }>();\n let position = 0;\n for (const source of sources) {\n const document = (parseYaml(source.text) ?? {}) as RegistryDocument;\n for (const [groupId, group] of Object.entries(document.groups ?? {})) {\n const entries: RegistryEntry[] = [];\n for (const hook of group.hooks ?? []) {\n // Every declared hook advances the position, whether or not it is kept,\n // so the sort tiebreaker stays the order the file declares them in.\n position += 1;\n if (!hook.pi) continue;\n entries.push({\n ...hook.pi,\n event: hook.event,\n order: hook.pi.order ?? 0,\n position,\n groupId,\n core: group.core === true,\n baseDirectory: source.baseDirectory,\n });\n }\n groups.set(groupId, { entries });\n }\n }\n\n const entries = [...groups.values()].flatMap((group) => group.entries);\n entries.sort((left, right) => left.order - right.order || left.position - right.position);\n cachedRegistrySource = cacheKey;\n cachedRegistryEntries = entries;\n return entries;\n}\n\nfunction registryRows(runtime: HookRuntime): RegistryEntry[] {\n const { repoRoot, harness, telemetry } = runtime;\n const candidates = doomConfigCandidates(HOOKS_FILE, repoRoot);\n // Named for the error path only. A registry absent from both locations is a\n // repository with no hooks, not a failure, so only a file that exists and\n // cannot be read or parsed reaches the catch below.\n const registryPath = candidates.map((candidate) => candidate.filePath).join(' and ');\n try {\n // Group selection changes when /major-mode switches mid-session, so inclusion is\n // applied per call instead of being baked into the cached parse.\n const selected = harness.hookGroups;\n const allowed = selected === undefined ? undefined : new Set(selected);\n const sources = candidates\n .filter((candidate) => fs.existsSync(candidate.filePath))\n .map((candidate) => ({\n baseDirectory: candidate.baseDirectory,\n text: fs.readFileSync(candidate.filePath, 'utf8'),\n }));\n return parseRegistry(sources).filter((entry) => entry.core || !allowed || allowed.has(entry.groupId));\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n // This empties the registry for the whole session, so every repository hook\n // silently stops running rather than any one of them failing.\n void telemetry?.recordError(HARNESS_EVENT.hookRegistryReadFailed, error, { 'hook.registry.source': 'repository' });\n process.stderr.write(`[pi-hook] could not read ${registryPath}: ${reason}\\n`);\n runtime.failures.push({ command: registryPath, message: reason, reason: 'registry_read' });\n return [];\n }\n}\n\nfunction registryHooks(\n eventName: string,\n runtime: HookRuntime,\n toolName?: string,\n): Array<{ hook: HookCommand; root: string }> {\n return (\n registryRows(runtime)\n .filter((row) => row.event === eventName)\n .filter((row) => !(row.skipInSubagent && process.env.PI_SUBAGENT_CHILD))\n .filter((row) => !toolName || !row.matcher || new RegExp(row.matcher).test(toClaudeToolName(toolName)))\n // The declaring config's root, so a global hook can reach its own scripts\n // through CLAUDE_PLUGIN_ROOT while still running against this repository.\n .map((row) => ({ hook: { command: row.command, timeout: row.timeout }, root: row.baseDirectory }))\n );\n}\n\nasync function runHooks(\n hooks: ResolvedHook[],\n payload: Record<string, unknown>,\n runtime: HookRuntime,\n ctx: ExtensionContext,\n statusKey: string,\n statusLabel: string,\n): Promise<HookOutcome[]> {\n const outcomes: HookOutcome[] = [];\n try {\n for (const [index, resolved] of hooks.entries()) {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, `${statusLabel} (${index + 1}/${hooks.length})...`);\n outcomes.push(await executeHook(resolved.hook, payload, runtime, resolved.root));\n }\n } finally {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, undefined);\n }\n return outcomes;\n}\n\nfunction resolvedHooks(eventName: string, runtime: HookRuntime, toolName?: string): ResolvedHook[] {\n return [\n ...registryHooks(eventName, runtime, toolName).map(({ hook, root }) => ({ hook, root })),\n ...pluginHooks(eventName, runtime, toolName).map(({ hook, root }) => ({ hook, root })),\n ];\n}\n\nfunction decisionsFrom(outcomes: HookOutcome[]): HookDecision[] {\n return outcomes.flatMap((outcome) => (outcome.decision ? [outcome.decision] : []));\n}\n\nfunction additionalContextsFrom(decisions: HookDecision[]): string[] {\n return decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext)\n .filter((value): value is string => Boolean(value));\n}\n\nfunction failuresFrom(runtime: HookRuntime, outcomes: HookOutcome[]): HookFailure[] {\n return [...runtime.failures, ...outcomes.flatMap((outcome) => (outcome.failure ? [outcome.failure] : []))];\n}\n\nfunction hookFailureMessage(failures: HookFailure[]): string {\n return [\n 'One or more repository hooks did not complete, so their checks were not applied:',\n ...failures.map((failure) => `- ${failure.command}: ${failure.message}`),\n 'Options:',\n '- Inspect the hook command or configuration and rerun after correcting it.',\n '- Continue only if the missed advisory check is acceptable.',\n '- Ask the user before bypassing a hook that may enforce a guardrail.',\n ].join('\\n');\n}\n\nfunction steerHookFailures(pi: ExtensionAPI, failures: HookFailure[]): void {\n if (failures.length === 0) return;\n pi.sendMessage(\n { customType: 'repository-hook-failure', content: hookFailureMessage(failures), display: true },\n { deliverAs: 'steer' },\n );\n}\n\nexport default function repositoryHooks(\n pi: ExtensionAPI,\n hookTelemetry: HarnessTelemetry = createHarnessTelemetry(),\n): void {\n pi.on('session_start', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.sessionStart, runtime),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:start`,\n 'Running session-start hooks',\n );\n steerHookFailures(pi, failuresFrom(runtime, outcomes));\n const context = additionalContextsFrom(decisionsFrom(outcomes)).join('\\n\\n');\n if (context) {\n pi.sendMessage(\n { customType: 'repository-hook-context', content: context, display: true },\n { deliverAs: 'steer' },\n );\n }\n });\n\n pi.on('tool_call', async (event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const payload = hookPayload(event, HOOK_EVENT.preToolUse, runtime.repoRoot, ctx.sessionManager.getSessionId());\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.preToolUse, runtime, event.toolName),\n payload,\n runtime,\n ctx,\n `repository-hooks:${event.toolCallId}:pre`,\n `Running pre-tool hooks for ${event.toolName}`,\n );\n const decisions = decisionsFrom(outcomes);\n steerHookFailures(pi, failuresFrom(runtime, outcomes));\n const denied = decisions.find(isDenied);\n if (denied) return { block: true, reason: decisionReason(denied) ?? 'Blocked by repository hook' };\n const context = additionalContextsFrom(decisions).join('\\n\\n');\n if (context) return { block: true, reason: context };\n return undefined;\n });\n\n pi.on('tool_result', async (event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const payload = hookPayload(event, HOOK_EVENT.postToolUse, runtime.repoRoot, ctx.sessionManager.getSessionId());\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.postToolUse, runtime, event.toolName),\n payload,\n runtime,\n ctx,\n `repository-hooks:${event.toolCallId}:post`,\n `Running post-tool hooks for ${event.toolName}`,\n );\n const decisions = decisionsFrom(outcomes);\n const failures = failuresFrom(runtime, outcomes);\n const messages = decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext ?? decisionReason(decision))\n .filter((value): value is string => Boolean(value));\n if (failures.length > 0) messages.push(hookFailureMessage(failures));\n if (messages.length === 0) return undefined;\n return {\n content: [...event.content, { type: 'text', text: messages.join('\\n\\n') }],\n isError: event.isError || decisions.some(isDenied),\n };\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n // skipInSubagent on the workflow-stop binding keeps subagents from closing\n // the parent's workflow step.\n await runHooks(\n resolvedHooks(HOOK_EVENT.stop, runtime),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:stop`,\n 'Running stop hooks',\n );\n });\n\n pi.on('session_shutdown', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n await runHooks(\n pluginHooks(HOOK_EVENT.sessionEnd, runtime).map(({ hook, root }) => ({ hook, root })),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:end`,\n 'Running session-end hooks',\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.cjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
|
|
4
|
+
//#region src/entries/repositoryHooks.d.ts
|
|
5
|
+
declare function repositoryHooks(pi: ExtensionAPI, hookTelemetry?: HarnessTelemetry): void;
|
|
6
|
+
export = repositoryHooks;
|
|
7
|
+
//# sourceMappingURL=repositoryHooks.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryHooks.d.cts","names":[],"sources":["../../src/entries/repositoryHooks.ts"],"mappings":";;;;iBA8dwB,eAAA,CACtB,EAAA,EAAI,YAAA,EACJ,aAAA,GAAe,gBAAA;AAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HarnessTelemetry } from "../logSinkTelemetry.mjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
|
|
4
|
+
//#region src/entries/repositoryHooks.d.ts
|
|
5
|
+
declare function repositoryHooks(pi: ExtensionAPI, hookTelemetry?: HarnessTelemetry): void;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { repositoryHooks as default };
|
|
8
|
+
//# sourceMappingURL=repositoryHooks.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryHooks.d.mts","names":[],"sources":["../../src/entries/repositoryHooks.ts"],"mappings":";;;;iBA8dwB,eAAA,CACtB,EAAA,EAAI,YAAA,EACJ,aAAA,GAAe,gBAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{HARNESS_EVENT as e,createHarnessTelemetry as t}from"../logSinkTelemetry.mjs";import{toClaudeToolName as n}from"../utils/toolNames.mjs";import r from"node:fs";import{requireDoomConfigContext as i}from"@agimon-ai/doompi-config";import{parse as a}from"yaml";import{spawn as o}from"node:child_process";import{doomConfigCandidates as s}from"@agimon-ai/doompi-config/layeredConfig";const c=`ESRCH`,l={sessionStart:`SessionStart`,preToolUse:`PreToolUse`,postToolUse:`PostToolUse`,stop:`Stop`,sessionEnd:`SessionEnd`};let u,d=[];const f=new Map;function p(e,t){let n=i(e).harness;return{repoRoot:n.root??e.cwd,harness:n,telemetry:t,failures:[]}}function m(e,t,r,i){return{session_id:i,transcript_path:``,cwd:r,hook_event_name:t,tool_name:n(e.toolName),tool_input:e.input,...e.type===`tool_result`?{tool_response:{success:!e.isError,content:e.content}}:{}}}async function h(t,n,r,i){let{repoRoot:a,telemetry:s}=r;return new Promise(r=>{let l=process.platform!==`win32`,u=o(`/bin/bash`,[`-c`,t.command],{cwd:a,env:{...process.env,CLAUDE_PROJECT_DIR:a,CODEX_REPO_ROOT:a,ORIGINAL_REPO_PATH:process.env.ORIGINAL_REPO_PATH??a,...i?{CLAUDE_PLUGIN_ROOT:i}:{}},stdio:[`pipe`,`pipe`,`pipe`],detached:l}),d=``,f=``,p=!1,m=!1,h=!1,g=null,_,v=e=>{try{if(l&&u.pid!==void 0){process.kill(-u.pid,e);return}u.kill(e)}catch(e){(e instanceof Error&&`code`in e?e.code:void 0)!==c&&process.emitWarning(`Could not signal repository hook process: ${String(e)}`)}},y=()=>{if(!l||u.pid===void 0)return!h;try{return process.kill(-u.pid,0),!0}catch(e){return(e instanceof Error&&`code`in e?e.code:void 0)!==c}},b=(e={})=>{p||(p=!0,clearTimeout(S),_&&clearTimeout(_),r(e))},x=()=>{let n=`Hook timed out after ${t.timeout??10} seconds.`;s?.recordWarning(e.hookFailed,n,{"hook.reason":`timeout`,"hook.exit_code":g??-1}),process.stderr.write(`[pi-hook] advisory hook timed out: ${t.command}\n${f}`),b({failure:{command:t.command,message:n,reason:`timeout`}})},S=setTimeout(()=>{m=!0,v(`SIGTERM`),_=setTimeout(()=>{y()&&v(`SIGKILL`),x()},2e3)},(t.timeout??10)*1e3);u.stdout.on(`data`,e=>{d+=e.toString()}),u.stderr.on(`data`,e=>{f+=e.toString()}),u.once(`error`,n=>{m||(s?.recordError(e.hookFailed,n,{"hook.reason":`spawn_failed`}),process.stderr.write(`[pi-hook] advisory hook failed: ${n.message}\n`),b({failure:{command:t.command,message:n.message,reason:`spawn_failed`}}))}),u.once(`exit`,n=>{if(h=!0,g=n,m)return;if(n!==0){let r=f.trim()||`Advisory hook exited with code ${n??`unknown`}`;s?.recordWarning(e.hookFailed,r,{"hook.reason":`non_zero_exit`,"hook.exit_code":n??-1}),process.stderr.write(`[pi-hook] advisory hook failed (${n}): ${t.command}\n${f}`),b({failure:{command:t.command,message:r,reason:`non_zero_exit`}});return}let r=d.trim().split(/\r?\n/).reverse().find(e=>e.startsWith(`{`));if(!r){b();return}try{b({decision:JSON.parse(r)})}catch(n){s?.recordWarning(e.hookFailed,n,{"hook.reason":`invalid_json`}),process.stderr.write(`[pi-hook] advisory hook returned invalid JSON: ${t.command}\n`),b({failure:{command:t.command,message:n instanceof Error?n.message:String(n),reason:`invalid_json`}})}}),u.stdin.end(JSON.stringify(n))})}function g(e){return e?.decision===`block`||e?.hookSpecificOutput?.permissionDecision===`deny`}function _(e){return e?.reason??e?.hookSpecificOutput?.reason}function v(e){let t=r.readFileSync(e,`utf8`),n=f.get(e);if(n?.source===t)return n.config;let i=JSON.parse(t);return f.set(e,{source:t,config:i}),i}function y(e,t,r){let i=[];for(let a of t.harness.pluginHooks){let o;try{o=v(a.configPath)}catch(e){t.failures.push({command:a.configPath,message:e instanceof Error?e.message:String(e),reason:`plugin_config`});continue}for(let t of o.hooks?.[e]??[])if(!(r&&t.matcher&&!new RegExp(t.matcher).test(n(r))))for(let e of t.hooks??[])i.push({hook:e,root:a.pluginRoot})}return i}function b(e){let t=e.map(e=>`${e.baseDirectory} ${e.text}`).join(` `);if(u===t)return d;let n=new Map,r=0;for(let t of e){let e=a(t.text)??{};for(let[i,a]of Object.entries(e.groups??{})){let e=[];for(let n of a.hooks??[])r+=1,n.pi&&e.push({...n.pi,event:n.event,order:n.pi.order??0,position:r,groupId:i,core:a.core===!0,baseDirectory:t.baseDirectory});n.set(i,{entries:e})}}let i=[...n.values()].flatMap(e=>e.entries);return i.sort((e,t)=>e.order-t.order||e.position-t.position),u=t,d=i,i}function x(t){let{repoRoot:n,harness:i,telemetry:a}=t,o=s(`hooks.yaml`,n),c=o.map(e=>e.filePath).join(` and `);try{let e=i.hookGroups,t=e===void 0?void 0:new Set(e);return b(o.filter(e=>r.existsSync(e.filePath)).map(e=>({baseDirectory:e.baseDirectory,text:r.readFileSync(e.filePath,`utf8`)}))).filter(e=>e.core||!t||t.has(e.groupId))}catch(n){let r=n instanceof Error?n.message:String(n);return a?.recordError(e.hookRegistryReadFailed,n,{"hook.registry.source":`repository`}),process.stderr.write(`[pi-hook] could not read ${c}: ${r}\n`),t.failures.push({command:c,message:r,reason:`registry_read`}),[]}}function S(e,t,r){return x(t).filter(t=>t.event===e).filter(e=>!(e.skipInSubagent&&process.env.PI_SUBAGENT_CHILD)).filter(e=>!r||!e.matcher||new RegExp(e.matcher).test(n(r))).map(e=>({hook:{command:e.command,timeout:e.timeout},root:e.baseDirectory}))}async function C(e,t,n,r,i,a){let o=[];try{for(let[s,c]of e.entries())r.hasUI&&r.ui.setStatus(i,`${a} (${s+1}/${e.length})...`),o.push(await h(c.hook,t,n,c.root))}finally{r.hasUI&&r.ui.setStatus(i,void 0)}return o}function w(e,t,n){return[...S(e,t,n).map(({hook:e,root:t})=>({hook:e,root:t})),...y(e,t,n).map(({hook:e,root:t})=>({hook:e,root:t}))]}function T(e){return e.flatMap(e=>e.decision?[e.decision]:[])}function E(e){return e.map(e=>e.hookSpecificOutput?.additionalContext).filter(e=>!!e)}function D(e,t){return[...e.failures,...t.flatMap(e=>e.failure?[e.failure]:[])]}function O(e){return[`One or more repository hooks did not complete, so their checks were not applied:`,...e.map(e=>`- ${e.command}: ${e.message}`),`Options:`,`- Inspect the hook command or configuration and rerun after correcting it.`,`- Continue only if the missed advisory check is acceptable.`,`- Ask the user before bypassing a hook that may enforce a guardrail.`].join(`
|
|
2
|
+
`)}function k(e,t){t.length!==0&&e.sendMessage({customType:`repository-hook-failure`,content:O(t),display:!0},{deliverAs:`steer`})}function A(e,n=t()){e.on(`session_start`,async(t,r)=>{let i=p(r,n),a=r.sessionManager.getSessionId(),o={session_id:a,cwd:i.repoRoot},s=await C(w(l.sessionStart,i),o,i,r,`repository-hooks:${a}:start`,`Running session-start hooks`);k(e,D(i,s));let c=E(T(s)).join(`
|
|
3
|
+
|
|
4
|
+
`);c&&e.sendMessage({customType:`repository-hook-context`,content:c,display:!0},{deliverAs:`steer`})}),e.on(`tool_call`,async(t,r)=>{let i=p(r,n),a=m(t,l.preToolUse,i.repoRoot,r.sessionManager.getSessionId()),o=await C(w(l.preToolUse,i,t.toolName),a,i,r,`repository-hooks:${t.toolCallId}:pre`,`Running pre-tool hooks for ${t.toolName}`),s=T(o);k(e,D(i,o));let c=s.find(g);if(c)return{block:!0,reason:_(c)??`Blocked by repository hook`};let u=E(s).join(`
|
|
5
|
+
|
|
6
|
+
`);if(u)return{block:!0,reason:u}}),e.on(`tool_result`,async(e,t)=>{let r=p(t,n),i=m(e,l.postToolUse,r.repoRoot,t.sessionManager.getSessionId()),a=await C(w(l.postToolUse,r,e.toolName),i,r,t,`repository-hooks:${e.toolCallId}:post`,`Running post-tool hooks for ${e.toolName}`),o=T(a),s=D(r,a),c=o.map(e=>e.hookSpecificOutput?.additionalContext??_(e)).filter(e=>!!e);if(s.length>0&&c.push(O(s)),c.length!==0)return{content:[...e.content,{type:`text`,text:c.join(`
|
|
7
|
+
|
|
8
|
+
`)}],isError:e.isError||o.some(g)}}),e.on(`agent_settled`,async(e,t)=>{let r=p(t,n),i=t.sessionManager.getSessionId(),a={session_id:i,cwd:r.repoRoot};await C(w(l.stop,r),a,r,t,`repository-hooks:${i}:stop`,`Running stop hooks`)}),e.on(`session_shutdown`,async(e,t)=>{let r=p(t,n),i=t.sessionManager.getSessionId(),a={session_id:i,cwd:r.repoRoot};await C(y(l.sessionEnd,r).map(({hook:e,root:t})=>({hook:e,root:t})),a,r,t,`repository-hooks:${i}:end`,`Running session-end hooks`)})}export{A as default};
|
|
9
|
+
//# sourceMappingURL=repositoryHooks.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryHooks.mjs","names":["parseYaml"],"sources":["../../src/entries/repositoryHooks.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { requireDoomConfigContext, type DoomHarnessContext } from '@agimon-ai/doompi-config';\nimport { doomConfigCandidates } from '@agimon-ai/doompi-config/layeredConfig';\nimport type { ExtensionAPI, ExtensionContext, ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\nimport { parse as parseYaml } from 'yaml';\nimport { createHarnessTelemetry, HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\n// Imported from the module rather than the utils barrel: Pi loads this file\n// directly, so pulling in the barrel would load module resolution helpers the\n// extension never uses.\nimport { toClaudeToolName } from '../utils/toolNames.ts';\n\nconst HOOKS_FILE = 'hooks.yaml';\nconst HOOK_SHELL = '/bin/bash';\nconst HOOK_SHELL_COMMAND_FLAG = '-c';\nconst HOOK_TERMINATION_GRACE_MS = 2_000;\nconst PROCESS_NOT_FOUND_ERROR = 'ESRCH';\n\n/** Registry event names. Each is used twice per dispatch, so drift would be silent. */\nconst HOOK_EVENT = {\n sessionStart: 'SessionStart',\n preToolUse: 'PreToolUse',\n postToolUse: 'PostToolUse',\n stop: 'Stop',\n sessionEnd: 'SessionEnd',\n} as const;\n\ninterface HookCommand {\n command: string;\n timeout?: number;\n}\n\ninterface RegistryBinding {\n matcher?: string;\n command: string;\n timeout?: number;\n skipInSubagent?: boolean;\n order?: number;\n}\n\ninterface RegistryRow extends RegistryBinding {\n event: string;\n order: number;\n position: number;\n}\n\n/** A registry row plus the group membership used to include or drop it. */\ninterface RegistryEntry extends RegistryRow {\n groupId: string;\n core: boolean;\n /** Root of the config that declared the group, exported as CLAUDE_PLUGIN_ROOT. */\n baseDirectory: string;\n}\n\ninterface HookGroup {\n matcher?: string;\n hooks?: HookCommand[];\n}\n\ninterface PluginHookConfig {\n hooks?: Record<string, HookGroup[]>;\n}\n\ninterface RegistryDocument {\n groups?: Record<string, { core?: boolean; hooks?: Array<{ event: string; pi?: RegistryBinding }> }>;\n}\n\n// Parsing the registry is the most expensive step on the tool-call path, and it\n// runs twice per tool call (once before, once after). Both caches are keyed on\n// file contents rather than mtime, so they stay correct for an in-place rewrite\n// and need no invalidation hook.\nlet cachedRegistrySource: string | undefined;\nlet cachedRegistryEntries: RegistryEntry[] = [];\nconst pluginConfigCache = new Map<string, { source: string; config: PluginHookConfig }>();\n\ninterface HookDecision {\n decision?: string;\n reason?: string;\n hookSpecificOutput?: {\n permissionDecision?: string;\n reason?: string;\n additionalContext?: string;\n };\n}\n\ninterface HookRuntime {\n repoRoot: string;\n harness: DoomHarnessContext;\n telemetry: HarnessTelemetry;\n failures: HookFailure[];\n}\n\ninterface HookFailure {\n command: string;\n message: string;\n reason: 'spawn_failed' | 'non_zero_exit' | 'timeout' | 'invalid_json' | 'registry_read' | 'plugin_config';\n}\n\ninterface HookOutcome {\n decision?: HookDecision;\n failure?: HookFailure;\n}\n\ninterface ResolvedHook {\n hook: HookCommand;\n root?: string;\n}\n\nfunction hookRuntime(ctx: ExtensionContext, telemetry: HarnessTelemetry): HookRuntime {\n const harness = requireDoomConfigContext(ctx).harness;\n return { repoRoot: harness.root ?? ctx.cwd, harness, telemetry, failures: [] };\n}\n\nfunction hookPayload(\n event: ToolCallEvent | ToolResultEvent,\n hookEventName: string,\n repoRoot: string,\n sessionId: string,\n): Record<string, unknown> {\n return {\n session_id: sessionId,\n transcript_path: '',\n cwd: repoRoot,\n hook_event_name: hookEventName,\n tool_name: toClaudeToolName(event.toolName),\n tool_input: event.input,\n ...(event.type === 'tool_result' ? { tool_response: { success: !event.isError, content: event.content } } : {}),\n };\n}\n\nasync function executeHook(\n hook: HookCommand,\n payload: Record<string, unknown>,\n runtime: HookRuntime,\n pluginRoot?: string,\n): Promise<HookOutcome> {\n const { repoRoot, telemetry } = runtime;\n return new Promise((resolve) => {\n const useProcessGroup = process.platform !== 'win32';\n // -c, not -lc. Hooks run on every tool call, and a login shell would source\n // the developer's profile each time: per-call latency plus hook behavior\n // that varies with their dotfiles. The child inherits process.env below, so\n // it keeps the PATH the launcher was started with.\n const child = spawn(HOOK_SHELL, [HOOK_SHELL_COMMAND_FLAG, hook.command], {\n cwd: repoRoot,\n env: {\n ...process.env,\n CLAUDE_PROJECT_DIR: repoRoot,\n CODEX_REPO_ROOT: repoRoot,\n ORIGINAL_REPO_PATH: process.env.ORIGINAL_REPO_PATH ?? repoRoot,\n ...(pluginRoot ? { CLAUDE_PLUGIN_ROOT: pluginRoot } : {}),\n },\n stdio: ['pipe', 'pipe', 'pipe'],\n detached: useProcessGroup,\n });\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n let childExited = false;\n let timeoutExitCode: number | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n\n const signalOwnedProcess = (signal: NodeJS.Signals): void => {\n try {\n if (useProcessGroup && child.pid !== undefined) {\n process.kill(-child.pid, signal);\n return;\n }\n child.kill(signal);\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? error.code : undefined;\n if (code !== PROCESS_NOT_FOUND_ERROR) {\n process.emitWarning(`Could not signal repository hook process: ${String(error)}`);\n }\n }\n };\n\n const ownedProcessIsAlive = (): boolean => {\n if (!useProcessGroup || child.pid === undefined) return !childExited;\n try {\n process.kill(-child.pid, 0);\n return true;\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? error.code : undefined;\n return code !== PROCESS_NOT_FOUND_ERROR;\n }\n };\n\n const finish = (outcome: HookOutcome = {}) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (escalationTimer) clearTimeout(escalationTimer);\n resolve(outcome);\n };\n\n const finishTimeout = (): void => {\n const message = `Hook timed out after ${hook.timeout ?? 10} seconds.`;\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, message, {\n 'hook.reason': 'timeout',\n 'hook.exit_code': timeoutExitCode ?? -1,\n });\n process.stderr.write(`[pi-hook] advisory hook timed out: ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'timeout' } });\n };\n\n const timer = setTimeout(\n () => {\n timedOut = true;\n signalOwnedProcess('SIGTERM');\n escalationTimer = setTimeout(() => {\n if (ownedProcessIsAlive()) signalOwnedProcess('SIGKILL');\n finishTimeout();\n }, HOOK_TERMINATION_GRACE_MS);\n },\n (hook.timeout ?? 10) * 1000,\n );\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (error) => {\n if (timedOut) return;\n // A guardrail that never ran is indistinguishable from one that passed,\n // which is the whole reason these are worth reporting.\n void telemetry?.recordError(HARNESS_EVENT.hookFailed, error, {\n 'hook.reason': 'spawn_failed',\n });\n process.stderr.write(`[pi-hook] advisory hook failed: ${error.message}\\n`);\n finish({ failure: { command: hook.command, message: error.message, reason: 'spawn_failed' } });\n });\n child.once('exit', (code) => {\n childExited = true;\n timeoutExitCode = code;\n if (timedOut) return;\n if (code !== 0) {\n const message = stderr.trim() || `Advisory hook exited with code ${code ?? 'unknown'}`;\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, message, {\n 'hook.reason': 'non_zero_exit',\n 'hook.exit_code': code ?? -1,\n });\n process.stderr.write(`[pi-hook] advisory hook failed (${code}): ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'non_zero_exit' } });\n return;\n }\n const jsonLine = stdout\n .trim()\n .split(/\\r?\\n/)\n .reverse()\n .find((line) => line.startsWith('{'));\n if (!jsonLine) {\n finish();\n return;\n }\n try {\n finish({ decision: JSON.parse(jsonLine) as HookDecision });\n } catch (error) {\n // The hook ran and had an opinion, and it was dropped.\n void telemetry?.recordWarning(HARNESS_EVENT.hookFailed, error, {\n 'hook.reason': 'invalid_json',\n });\n process.stderr.write(`[pi-hook] advisory hook returned invalid JSON: ${hook.command}\\n`);\n finish({\n failure: {\n command: hook.command,\n message: error instanceof Error ? error.message : String(error),\n reason: 'invalid_json',\n },\n });\n }\n });\n child.stdin.end(JSON.stringify(payload));\n });\n}\n\nfunction isDenied(decision: HookDecision | undefined): boolean {\n return decision?.decision === 'block' || decision?.hookSpecificOutput?.permissionDecision === 'deny';\n}\n\nfunction decisionReason(decision: HookDecision | undefined): string | undefined {\n return decision?.reason ?? decision?.hookSpecificOutput?.reason;\n}\n\n/**\n * Parses a plugin hook config, reusing the last parse of identical content.\n *\n * Reading the file every time is deliberate: it costs almost nothing and keeps\n * an in-place rewrite visible, which an mtime check would miss when two writes\n * land inside the same filesystem timestamp granularity.\n */\nfunction readPluginHookConfig(configPath: string): PluginHookConfig {\n const source = fs.readFileSync(configPath, 'utf8');\n const cached = pluginConfigCache.get(configPath);\n if (cached?.source === source) return cached.config;\n const config = JSON.parse(source) as PluginHookConfig;\n pluginConfigCache.set(configPath, { source, config });\n return config;\n}\n\nfunction pluginHooks(\n eventName: string,\n runtime: HookRuntime,\n toolName?: string,\n): Array<{ hook: HookCommand; root: string }> {\n const matches: Array<{ hook: HookCommand; root: string }> = [];\n for (const source of runtime.harness.pluginHooks) {\n let config: PluginHookConfig;\n try {\n config = readPluginHookConfig(source.configPath);\n } catch (error) {\n runtime.failures.push({\n command: source.configPath,\n message: error instanceof Error ? error.message : String(error),\n reason: 'plugin_config',\n });\n continue;\n }\n for (const group of config.hooks?.[eventName] ?? []) {\n if (toolName && group.matcher && !new RegExp(group.matcher).test(toClaudeToolName(toolName))) continue;\n for (const hook of group.hooks ?? []) matches.push({ hook, root: source.pluginRoot });\n }\n }\n return matches;\n}\n\n// Reads the canonical registry from .doom/hooks.yaml in the global config\n// directory and the repository, keeping only bindings that declare a `pi`\n// frontend. A repository group replaces the global group of the same id. Core\n// groups always load; the rest are gated by DOOMPI_HOOK_GROUPS, which the\n// harness sets from the resolved layers. An unset variable means every group,\n// which is the standalone default.\nfunction parseRegistry(sources: ReadonlyArray<{ baseDirectory: string; text: string }>): RegistryEntry[] {\n // Keyed on the joined contents rather than mtime, so it stays correct for an\n // in-place rewrite. Reading both files is cheap; parsing is what this skips.\n const cacheKey = sources.map((source) => `${source.baseDirectory} ${source.text}`).join(' ');\n if (cachedRegistrySource === cacheKey) return cachedRegistryEntries;\n\n const groups = new Map<string, { entries: RegistryEntry[] }>();\n let position = 0;\n for (const source of sources) {\n const document = (parseYaml(source.text) ?? {}) as RegistryDocument;\n for (const [groupId, group] of Object.entries(document.groups ?? {})) {\n const entries: RegistryEntry[] = [];\n for (const hook of group.hooks ?? []) {\n // Every declared hook advances the position, whether or not it is kept,\n // so the sort tiebreaker stays the order the file declares them in.\n position += 1;\n if (!hook.pi) continue;\n entries.push({\n ...hook.pi,\n event: hook.event,\n order: hook.pi.order ?? 0,\n position,\n groupId,\n core: group.core === true,\n baseDirectory: source.baseDirectory,\n });\n }\n groups.set(groupId, { entries });\n }\n }\n\n const entries = [...groups.values()].flatMap((group) => group.entries);\n entries.sort((left, right) => left.order - right.order || left.position - right.position);\n cachedRegistrySource = cacheKey;\n cachedRegistryEntries = entries;\n return entries;\n}\n\nfunction registryRows(runtime: HookRuntime): RegistryEntry[] {\n const { repoRoot, harness, telemetry } = runtime;\n const candidates = doomConfigCandidates(HOOKS_FILE, repoRoot);\n // Named for the error path only. A registry absent from both locations is a\n // repository with no hooks, not a failure, so only a file that exists and\n // cannot be read or parsed reaches the catch below.\n const registryPath = candidates.map((candidate) => candidate.filePath).join(' and ');\n try {\n // Group selection changes when /major-mode switches mid-session, so inclusion is\n // applied per call instead of being baked into the cached parse.\n const selected = harness.hookGroups;\n const allowed = selected === undefined ? undefined : new Set(selected);\n const sources = candidates\n .filter((candidate) => fs.existsSync(candidate.filePath))\n .map((candidate) => ({\n baseDirectory: candidate.baseDirectory,\n text: fs.readFileSync(candidate.filePath, 'utf8'),\n }));\n return parseRegistry(sources).filter((entry) => entry.core || !allowed || allowed.has(entry.groupId));\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n // This empties the registry for the whole session, so every repository hook\n // silently stops running rather than any one of them failing.\n void telemetry?.recordError(HARNESS_EVENT.hookRegistryReadFailed, error, { 'hook.registry.source': 'repository' });\n process.stderr.write(`[pi-hook] could not read ${registryPath}: ${reason}\\n`);\n runtime.failures.push({ command: registryPath, message: reason, reason: 'registry_read' });\n return [];\n }\n}\n\nfunction registryHooks(\n eventName: string,\n runtime: HookRuntime,\n toolName?: string,\n): Array<{ hook: HookCommand; root: string }> {\n return (\n registryRows(runtime)\n .filter((row) => row.event === eventName)\n .filter((row) => !(row.skipInSubagent && process.env.PI_SUBAGENT_CHILD))\n .filter((row) => !toolName || !row.matcher || new RegExp(row.matcher).test(toClaudeToolName(toolName)))\n // The declaring config's root, so a global hook can reach its own scripts\n // through CLAUDE_PLUGIN_ROOT while still running against this repository.\n .map((row) => ({ hook: { command: row.command, timeout: row.timeout }, root: row.baseDirectory }))\n );\n}\n\nasync function runHooks(\n hooks: ResolvedHook[],\n payload: Record<string, unknown>,\n runtime: HookRuntime,\n ctx: ExtensionContext,\n statusKey: string,\n statusLabel: string,\n): Promise<HookOutcome[]> {\n const outcomes: HookOutcome[] = [];\n try {\n for (const [index, resolved] of hooks.entries()) {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, `${statusLabel} (${index + 1}/${hooks.length})...`);\n outcomes.push(await executeHook(resolved.hook, payload, runtime, resolved.root));\n }\n } finally {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, undefined);\n }\n return outcomes;\n}\n\nfunction resolvedHooks(eventName: string, runtime: HookRuntime, toolName?: string): ResolvedHook[] {\n return [\n ...registryHooks(eventName, runtime, toolName).map(({ hook, root }) => ({ hook, root })),\n ...pluginHooks(eventName, runtime, toolName).map(({ hook, root }) => ({ hook, root })),\n ];\n}\n\nfunction decisionsFrom(outcomes: HookOutcome[]): HookDecision[] {\n return outcomes.flatMap((outcome) => (outcome.decision ? [outcome.decision] : []));\n}\n\nfunction additionalContextsFrom(decisions: HookDecision[]): string[] {\n return decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext)\n .filter((value): value is string => Boolean(value));\n}\n\nfunction failuresFrom(runtime: HookRuntime, outcomes: HookOutcome[]): HookFailure[] {\n return [...runtime.failures, ...outcomes.flatMap((outcome) => (outcome.failure ? [outcome.failure] : []))];\n}\n\nfunction hookFailureMessage(failures: HookFailure[]): string {\n return [\n 'One or more repository hooks did not complete, so their checks were not applied:',\n ...failures.map((failure) => `- ${failure.command}: ${failure.message}`),\n 'Options:',\n '- Inspect the hook command or configuration and rerun after correcting it.',\n '- Continue only if the missed advisory check is acceptable.',\n '- Ask the user before bypassing a hook that may enforce a guardrail.',\n ].join('\\n');\n}\n\nfunction steerHookFailures(pi: ExtensionAPI, failures: HookFailure[]): void {\n if (failures.length === 0) return;\n pi.sendMessage(\n { customType: 'repository-hook-failure', content: hookFailureMessage(failures), display: true },\n { deliverAs: 'steer' },\n );\n}\n\nexport default function repositoryHooks(\n pi: ExtensionAPI,\n hookTelemetry: HarnessTelemetry = createHarnessTelemetry(),\n): void {\n pi.on('session_start', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.sessionStart, runtime),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:start`,\n 'Running session-start hooks',\n );\n steerHookFailures(pi, failuresFrom(runtime, outcomes));\n const context = additionalContextsFrom(decisionsFrom(outcomes)).join('\\n\\n');\n if (context) {\n pi.sendMessage(\n { customType: 'repository-hook-context', content: context, display: true },\n { deliverAs: 'steer' },\n );\n }\n });\n\n pi.on('tool_call', async (event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const payload = hookPayload(event, HOOK_EVENT.preToolUse, runtime.repoRoot, ctx.sessionManager.getSessionId());\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.preToolUse, runtime, event.toolName),\n payload,\n runtime,\n ctx,\n `repository-hooks:${event.toolCallId}:pre`,\n `Running pre-tool hooks for ${event.toolName}`,\n );\n const decisions = decisionsFrom(outcomes);\n steerHookFailures(pi, failuresFrom(runtime, outcomes));\n const denied = decisions.find(isDenied);\n if (denied) return { block: true, reason: decisionReason(denied) ?? 'Blocked by repository hook' };\n const context = additionalContextsFrom(decisions).join('\\n\\n');\n if (context) return { block: true, reason: context };\n return undefined;\n });\n\n pi.on('tool_result', async (event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const payload = hookPayload(event, HOOK_EVENT.postToolUse, runtime.repoRoot, ctx.sessionManager.getSessionId());\n const outcomes = await runHooks(\n resolvedHooks(HOOK_EVENT.postToolUse, runtime, event.toolName),\n payload,\n runtime,\n ctx,\n `repository-hooks:${event.toolCallId}:post`,\n `Running post-tool hooks for ${event.toolName}`,\n );\n const decisions = decisionsFrom(outcomes);\n const failures = failuresFrom(runtime, outcomes);\n const messages = decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext ?? decisionReason(decision))\n .filter((value): value is string => Boolean(value));\n if (failures.length > 0) messages.push(hookFailureMessage(failures));\n if (messages.length === 0) return undefined;\n return {\n content: [...event.content, { type: 'text', text: messages.join('\\n\\n') }],\n isError: event.isError || decisions.some(isDenied),\n };\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n // skipInSubagent on the workflow-stop binding keeps subagents from closing\n // the parent's workflow step.\n await runHooks(\n resolvedHooks(HOOK_EVENT.stop, runtime),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:stop`,\n 'Running stop hooks',\n );\n });\n\n pi.on('session_shutdown', async (_event, ctx) => {\n const runtime = hookRuntime(ctx, hookTelemetry);\n const sessionId = ctx.sessionManager.getSessionId();\n const payload = { session_id: sessionId, cwd: runtime.repoRoot };\n await runHooks(\n pluginHooks(HOOK_EVENT.sessionEnd, runtime).map(({ hook, root }) => ({ hook, root })),\n payload,\n runtime,\n ctx,\n `repository-hooks:${sessionId}:end`,\n 'Running session-end hooks',\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}}),require(`../_virtual/_rolldown/runtime.cjs`),require(`../config/harnessState.cjs`);const e=require(`../services/skillCatalog.cjs`),t=require(`./components/skillsOverlay.cjs`),n=require(`../services/skillSources.cjs`);let r=require(`@agimon-ai/doompi-config`),i=require(`@agimon-ai/doompi-ui/leader`);const a=`skills`,o={source:`@agimon-ai/doompi`,bindings:[{id:`skills.browse`,path:[{key:`e`,label:`extension`,order:50},{key:`s`,label:`skills`,detail:`browse catalog`}],command:{name:a}}]};function s(e){return`/skill:${e} `}function c(c){let l=n.provideSkillSources(c);(0,i.registerDoomLeaderContribution)(c,o),c.registerCommand(a,{description:`Browse the skills this session loaded, and what other domains would add`,handler:async(n,i)=>{if(!i.hasUI||i.mode!==`tui`){i.ui.notify(`/skills requires interactive mode`,`error`);return}let a=(0,r.requireDoomConfigContext)(i).harness,o=(0,r.requireHarnessRoot)(a),c=await t.openSkillsOverlay(i,{catalog:await e.buildSkillCatalog({repoRoot:o,activeSkillDirectories:a.skillDirectories,extensionSources:l.list()}),repoRoot:o});if(!c)return;let{skill:u}=c;i.ui.setEditorText(s(u.name)),i.ui.notify(`Loaded ${u.name} into the prompt. Press enter to run it.`,`info`)}})}exports.SKILLS_LEADER_CONTRIBUTION=o,exports.default=c,exports.skillInvocation=s;
|
|
2
|
+
//# sourceMappingURL=skills.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.cjs","names":["provideSkillSources","openSkillsOverlay","buildSkillCatalog"],"sources":["../../src/entries/skills.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config';\nimport { registerDoomLeaderContribution, type DoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { openSkillsOverlay } from './components/skillsOverlay.ts';\nimport { requireHarnessRoot } from '../config/harnessState.ts';\nimport { buildSkillCatalog } from '../services/skillCatalog.ts';\nimport { provideSkillSources } from '../services/skillSources.ts';\n\nconst SKILLS_COMMAND = 'skills';\nconst LEADER_SOURCE = '@agimon-ai/doompi';\nconst INFO = 'info';\nconst ERROR = 'error';\n\nexport const SKILLS_LEADER_CONTRIBUTION = {\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'skills.browse',\n path: [\n // Label and order repeat the core extension group exactly; the registry\n // rejects a contribution whose shared prefix disagrees.\n { key: 'e', label: 'extension', order: 50 },\n { key: 's', label: 'skills', detail: 'browse catalog' },\n ],\n command: { name: SKILLS_COMMAND },\n },\n ],\n} satisfies DoomLeaderContribution;\n\n/**\n * Prefills the draft rather than submitting it.\n *\n * `/skill:<name>` is expanded by Pi inside `prompt()`, which only the editor's\n * own submission path reaches: `sendUserMessage` sets `expandPromptTemplates`\n * false and would deliver the literal text. Leaving the command in the editor\n * keeps the expansion and costs one keystroke.\n */\nexport function skillInvocation(name: string): string {\n return `/skill:${name} `;\n}\n\nexport default function skillsExtension(pi: ExtensionAPI): void {\n const sources = provideSkillSources(pi);\n\n registerDoomLeaderContribution(pi, SKILLS_LEADER_CONTRIBUTION);\n\n pi.registerCommand(SKILLS_COMMAND, {\n description: 'Browse the skills this session loaded, and what other domains would add',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI || ctx.mode !== 'tui') {\n ctx.ui.notify('/skills requires interactive mode', ERROR);\n return;\n }\n const state = requireDoomConfigContext(ctx).harness;\n const repoRoot = requireHarnessRoot(state);\n const catalog = await buildSkillCatalog({\n repoRoot,\n activeSkillDirectories: state.skillDirectories,\n extensionSources: sources.list(),\n });\n\n const result = await openSkillsOverlay(ctx, { catalog, repoRoot });\n if (!result) return;\n const { skill } = result;\n ctx.ui.setEditorText(skillInvocation(skill.name));\n ctx.ui.notify(`Loaded ${skill.name} into the prompt. Press enter to run it.`, INFO);\n },\n });\n}\n"],"mappings":"2YAQA,MAAM,EAAiB,SAKV,EAA6B,CACxC,OAAQ,oBACR,SAAU,CACR,CACE,GAAI,gBACJ,KAAM,CAGJ,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,GAAI,CAC3C,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,iBAAkB,CACxD,CACD,QAAS,CAAE,KAAM,EAAgB,CAClC,CACF,CACF,CAUD,SAAgB,EAAgB,EAAsB,CACpD,MAAO,UAAU,EAAK,GAGxB,SAAwB,EAAgB,EAAwB,CAC9D,IAAM,EAAUA,EAAAA,oBAAoB,EAAG,EAEvC,EAAA,EAAA,gCAA+B,EAAI,EAA2B,CAE9D,EAAG,gBAAgB,EAAgB,CACjC,YAAa,0EACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,OAAS,EAAI,OAAS,MAAO,CACpC,EAAI,GAAG,OAAO,oCAAqC,QAAM,CACzD,OAEF,IAAM,GAAA,EAAA,EAAA,0BAAiC,EAAI,CAAC,QACtC,GAAA,EAAA,EAAA,oBAA8B,EAAM,CAOpC,EAAS,MAAMC,EAAAA,kBAAkB,EAAK,CAAE,QAAA,MANxBC,EAAAA,kBAAkB,CACtC,WACA,uBAAwB,EAAM,iBAC9B,iBAAkB,EAAQ,MAAM,CACjC,CAAC,CAEqD,WAAU,CAAC,CAClE,GAAI,CAAC,EAAQ,OACb,GAAM,CAAE,SAAU,EAClB,EAAI,GAAG,cAAc,EAAgB,EAAM,KAAK,CAAC,CACjD,EAAI,GAAG,OAAO,UAAU,EAAM,KAAK,0CAA2C,OAAK,EAEtF,CAAC"}
|