{"version":3,"file":"skillReadiness.cjs","names":["SKILL_COMMAND_PREFIX","requireDoomConfigContext"],"sources":["../../../../../../../src/extensions/workspaces/sessions/(backend)/_lib/skillReadiness.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/pi-extension';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, Skill } from '@earendil-works/pi-coding-agent';\n\nimport type { DeferredSkillSnapshot } from '../../../../../services/deferredSkills';\nimport type { createActiveHelpSkillView } from '../../../../../services/helpSkills';\nimport { SKILL_COMMAND_PREFIX, SKILL_INVOCATION_PREFIX } from '../../../../../types/skills';\n\nconst WARNING = 'warning';\n\ntype HelpSkillView = ReturnType<typeof createActiveHelpSkillView>;\n\ninterface SkillReadinessGeneration {\n  readonly id: number;\n  readonly ready: Promise<DeferredSkillSnapshot>;\n  diagnosticsShown: boolean;\n}\n\nexport interface SkillReadiness {\n  readonly events: PiEventHandlers;\n  onStop(this: void): void;\n  /** The snapshot for the live generation, or undefined once it is superseded. */\n  current(): Promise<DeferredSkillSnapshot | undefined>;\n}\n\nfunction loadedSkillCommandNames(pi: ExtensionAPI): string[] {\n  if (typeof pi.getCommands !== 'function') return [];\n  return pi\n    .getCommands()\n    .filter((command) => command.source === 'skill' && command.name.startsWith(SKILL_COMMAND_PREFIX))\n    .map((command) => command.name.slice(SKILL_COMMAND_PREFIX.length));\n}\n\nfunction failedSnapshot(cwd: string, error: unknown): DeferredSkillSnapshot {\n  return {\n    skills: [],\n    diagnostics: [`${cwd}: ${error instanceof Error ? error.message : String(error)}`],\n  };\n}\n\n/**\n * Discovery that starts with the session and is awaited only when something\n * needs it.\n *\n * Scanning every skill directory is the slowest thing this package does, so it\n * runs as a generation started on session_start. A reload starts a new one, and\n * a snapshot from a superseded generation is discarded rather than shown.\n */\nexport function createSkillReadiness(\n  pi: ExtensionAPI,\n  helpSkillView: HelpSkillView,\n  loadDeferredSkills: () => Promise<typeof import('../../../../../services/deferredSkills')>,\n  cordisContext: () => Context,\n): SkillReadiness {\n  let generationSequence = 0;\n  let currentGeneration: SkillReadinessGeneration | undefined;\n  let shownHelpDiagnosticKey = '';\n\n  const currentSnapshot = async (generation: SkillReadinessGeneration): Promise<DeferredSkillSnapshot | undefined> => {\n    const snapshot = await generation.ready;\n    return currentGeneration === generation ? snapshot : undefined;\n  };\n\n  return {\n    events: {\n      session_start: (_event, ctx) => {\n        const state = requireDoomConfigContext(cordisContext()).harness;\n        const id = ++generationSequence;\n        const ready = loadDeferredSkills()\n          .then(({ DeferredSkillLoader }) =>\n            new DeferredSkillLoader({ cwd: ctx.cwd, skillPaths: state.skillDirectories }).start(),\n          )\n          .catch((error: unknown) => failedSnapshot(ctx.cwd, error));\n        currentGeneration = { id, ready, diagnosticsShown: false };\n        shownHelpDiagnosticKey = '';\n      },\n      input: async (event) => {\n        if (!event.text.startsWith(SKILL_INVOCATION_PREFIX)) return { action: 'continue' };\n\n        const generation = currentGeneration;\n        if (!generation) return { action: 'continue' };\n        const snapshot = await currentSnapshot(generation);\n        if (!snapshot) return { action: 'continue' };\n\n        const inventory = helpSkillView.merge({\n          normalSkills: [],\n          deferredSkills: snapshot.skills,\n          normalSkillNames: loadedSkillCommandNames(pi),\n        });\n        const { expandDeferredSkillCommand } = await loadDeferredSkills();\n        const text = expandDeferredSkillCommand(event.text, inventory.additionalSkills);\n        return text === event.text ? { action: 'continue' } : { action: 'transform', text, images: event.images };\n      },\n      before_agent_start: async (event, ctx) => {\n        const generation = currentGeneration;\n        if (!generation) return undefined;\n        const snapshot = await currentSnapshot(generation);\n        if (!snapshot) return undefined;\n\n        if (!generation.diagnosticsShown && snapshot.diagnostics.length > 0) {\n          generation.diagnosticsShown = true;\n          ctx.ui.notify(`Skill discovery:\\n${snapshot.diagnostics.join('\\n')}`, WARNING);\n        }\n        const inventory = helpSkillView.merge({\n          normalSkills: event.systemPromptOptions.skills ?? [],\n          deferredSkills: snapshot.skills,\n        });\n        if (inventory.diagnosticKey !== shownHelpDiagnosticKey) {\n          shownHelpDiagnosticKey = inventory.diagnosticKey;\n          if (inventory.diagnostics.length > 0) {\n            ctx.ui.notify(`Package Help:\\n${inventory.diagnostics.join('\\n')}`, WARNING);\n          }\n        }\n        if (inventory.additionalSkills.length === 0) return undefined;\n\n        const { buildPromptWithDeferredSkills } = await loadDeferredSkills();\n        return {\n          systemPrompt: buildPromptWithDeferredSkills(event.systemPrompt, event.systemPromptOptions, [\n            ...inventory.additionalSkills,\n          ]),\n        };\n      },\n    },\n    onStop() {\n      currentGeneration = undefined;\n    },\n    current: async () => (currentGeneration ? currentSnapshot(currentGeneration) : undefined),\n  };\n}\n\n/** The merged skill inventory the /skills catalogue is built from. */\nexport function skillInventory(helpSkillView: HelpSkillView, readiness: SkillReadiness) {\n  return async (ctx: ExtensionContext) => {\n    const snapshot = await readiness.current();\n    const inventory = helpSkillView.merge({\n      // Present on the runtime context; absent from the published ExtensionContext type.\n      normalSkills:\n        (ctx as unknown as { getSystemPromptOptions(): { skills?: Skill[] } }).getSystemPromptOptions().skills ?? [],\n      deferredSkills: snapshot?.skills ?? [],\n    });\n    return { helpSkills: inventory.helpSkills, diagnostics: inventory.diagnostics };\n  };\n}\n"],"mappings":"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"}