skilld 1.7.4 → 2.0.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.
Files changed (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. package/dist/types.mjs +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"agent.mjs","names":["resolve","buildArgs","parseEvent","adapter","buildArgs","parseEvent","adapter","getEnvApiKey","resolve","claudeAdapter","geminiAdapter","codexAdapter","agents","delay"],"sources":["../../src/agent/clis/model-registry.ts","../../src/agent/clis/types.ts","../../src/agent/clis/claude.ts","../../src/agent/clis/codex.ts","../../src/agent/clis/gemini.ts","../../src/agent/clis/pi-ai-auth.ts","../../src/agent/clis/pi-ai-models.ts","../../src/agent/clis/pi-ai-tools.ts","../../src/agent/clis/pi-ai-runner.ts","../../src/agent/clis/clean-output.ts","../../src/agent/clis/cli-progress.ts","../../src/agent/clis/index.ts","../../src/agent/detect-presets.ts","../../src/agent/detect-imports.ts","../../src/agent/clis/cli-cache.ts","../../src/agent/clis/runner.ts","../../src/agent/clis/executors.ts","../../src/agent/llm-enhancer.ts"],"sourcesContent":["/**\n * Model registry: sources display names from @mariozechner/pi-ai's auto-generated\n * model list, so CLI adapters don't have to hand-maintain \"Opus 4.6\" / \"GPT-5.3\" labels.\n *\n * Each adapter declares the CLI flag value it passes (e.g. `opus`, `gpt-5.3-codex`)\n * plus an id pattern; we resolve the latest matching pi-ai entry for the human label.\n */\n\nimport type { KnownProvider, Model } from '@mariozechner/pi-ai'\nimport type { CliModelEntry } from './types.ts'\nimport { getModels } from '@mariozechner/pi-ai'\n\n/** Strip dated aliases (claude-opus-4-5-20251101) and preview tags. */\nfunction isStableId(id: string): boolean {\n if (/-\\d{8}$/.test(id))\n return false\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(id))\n return false\n if (/-preview/.test(id))\n return false\n return true\n}\n\n/**\n * Numeric version comparator on the trailing version chunks of an id\n * (e.g. claude-opus-4-7 > claude-opus-4-6, gpt-5.3 > gpt-5.2).\n */\nfunction compareVersions(a: string, b: string): number {\n const versionOf = (id: string): number[] => {\n const nums = id.match(/\\d+(?:\\.\\d+)?/g) ?? []\n return nums.flatMap(n => n.split('.').map(Number))\n }\n const av = versionOf(a)\n const bv = versionOf(b)\n for (let i = 0; i < Math.max(av.length, bv.length); i++) {\n const x = av[i] ?? 0\n const y = bv[i] ?? 0\n if (x !== y)\n return y - x\n }\n return 0\n}\n\ninterface ResolveOpts {\n provider: KnownProvider\n /** Prefix the id must start with (e.g. `claude-opus-`, `gpt-5.`, `gemini-`). */\n prefix: string\n /** Optional substring filter (e.g. `codex`, `flash`). */\n contains?: string\n /** Skip ids containing any of these substrings. */\n exclude?: string[]\n}\n\nfunction resolve(opts: ResolveOpts): Model<any> | undefined {\n const { provider, prefix, contains, exclude } = opts\n const matches = getModels(provider)\n .filter(m => isStableId(m.id))\n .filter(m => m.id.startsWith(prefix))\n .filter(m => !contains || m.id.includes(contains))\n .filter(m => !exclude?.some(e => m.id.includes(e)))\n .sort((a, b) => compareVersions(a.id, b.id))\n return matches[0]\n}\n\n/**\n * Build a CliModelEntry by looking up the latest matching pi-ai model and using its\n * display name. `model` is the literal value passed to the CLI (alias or id).\n */\nexport function buildModelEntry(opts: ResolveOpts & {\n /** Value passed to the CLI's --model flag. Defaults to the resolved pi-ai id. */\n model?: string\n /** Override for the display name. Defaults to pi-ai's `name`. */\n name?: string\n /** Post-process pi-ai's name (e.g. strip \"Claude \" prefix). */\n nameTransform?: (name: string) => string\n hint: string\n recommended?: boolean\n}): CliModelEntry {\n const found = resolve(opts)\n const piName = found?.name\n const transformed = piName && opts.nameTransform ? opts.nameTransform(piName) : piName\n const name = opts.name ?? transformed ?? opts.model ?? opts.prefix\n const model = opts.model ?? found?.id ?? opts.prefix\n return { model, name, hint: opts.hint, recommended: opts.recommended }\n}\n\n/** Build a Record<id, CliModelEntry> from a list of entry specs, keyed by their `model` field. */\nexport function buildModels(entries: Array<Parameters<typeof buildModelEntry>[0]>): Record<string, CliModelEntry> {\n return Object.fromEntries(entries.map((e) => {\n const entry = buildModelEntry(e)\n return [entry.model, entry]\n }))\n}\n","import type { FeaturesConfig } from '../../core/config.ts'\nimport type { CustomPrompt, SkillSection } from '../prompts/index.ts'\nimport type { AgentType } from '../types.ts'\n\n/** Normalized event emitted by every CliAdapter from a single stream-json line. */\nexport type CliEvent\n = | { kind: 'noop' }\n /** Assistant text — delta (partial streaming) or full (turn-level). */\n | { kind: 'text', delta?: string, full?: string }\n /**\n * Tool invocation. `tool` is the adapter's raw name (e.g. 'Read', 'read_file'); look it up in\n * TOOL_NAMES for display verb + canonical role. `writeContent` carries inline file content\n * the LLM tried to write (fallback path when the host denies the Write tool).\n */\n | { kind: 'tool-call', tool: string, hint?: string, writeContent?: string }\n /** Stream finished cleanly. */\n | { kind: 'done', usage?: { input: number, output: number }, cost?: number, turns?: number }\n /** Stream finished with an error. */\n | { kind: 'error', message?: string }\n\n/**\n * Canonical tool registry — one row per raw name across adapters. Drives display (verb) and\n * semantic role (canonical) without per-CLI switching in the dispatcher.\n */\nexport const TOOL_NAMES: Record<string, { canonical: 'read' | 'search' | 'write' | 'list' | 'shell', verb: string }> = {\n // Claude Code\n Read: { canonical: 'read', verb: 'Reading' },\n Glob: { canonical: 'search', verb: 'Searching' },\n Grep: { canonical: 'search', verb: 'Searching' },\n Write: { canonical: 'write', verb: 'Writing' },\n Bash: { canonical: 'shell', verb: 'Running' },\n // Gemini\n read_file: { canonical: 'read', verb: 'Reading' },\n glob_tool: { canonical: 'search', verb: 'Searching' },\n write_file: { canonical: 'write', verb: 'Writing' },\n list_directory: { canonical: 'list', verb: 'Listing' },\n search_file_content: { canonical: 'search', verb: 'Searching' },\n run_shell_command: { canonical: 'shell', verb: 'Running' },\n}\n\n/**\n * Common keys adapters poke at to extract a useful hint (path, query, command) from a tool's\n * argument object — claude, gemini, codex all use overlapping shapes.\n */\nexport function extractToolHint(input: Record<string, unknown> | undefined | null): string | undefined {\n if (!input)\n return undefined\n for (const k of ['file_path', 'path', 'dir_path', 'pattern', 'query', 'command'] as const) {\n const v = input[k]\n if (typeof v === 'string' && v)\n return v\n }\n return undefined\n}\n\nexport type OptimizeModel\n = | 'opus'\n | 'sonnet'\n | 'haiku'\n | 'gemini-3.1-pro'\n | 'gemini-3-flash'\n | 'gpt-5.3-codex'\n | 'gpt-5.3-codex-spark'\n | 'gpt-5.2-codex'\n // pi-ai direct API models — dynamic from pi-ai's model registry\n | `pi:${string}`\n\nexport interface ModelInfo {\n id: OptimizeModel\n name: string\n hint: string\n recommended?: boolean\n agentId: string\n agentName: string\n /** Grouping key for provider selection (e.g. 'claude-code', 'pi:anthropic') */\n provider: string\n /** Human-readable provider name */\n providerName: string\n /** Normalized vendor name for UI grouping (e.g. 'Anthropic') — merges CLI and API entries */\n vendorGroup: string\n}\n\nexport interface StreamProgress {\n chunk: string\n type: 'reasoning' | 'text'\n text: string\n reasoning: string\n section?: SkillSection\n}\n\nexport interface OptimizeDocsOptions {\n packageName: string\n skillDir: string\n model?: OptimizeModel\n version?: string\n hasGithub?: boolean\n hasReleases?: boolean\n hasChangelog?: string | false\n docFiles?: string[]\n docsType?: 'llms.txt' | 'readme' | 'docs'\n hasShippedDocs?: boolean\n onProgress?: (progress: StreamProgress) => void\n timeout?: number\n verbose?: boolean\n debug?: boolean\n noCache?: boolean\n /** Which sections to generate */\n sections?: SkillSection[]\n /** Custom instructions from the user */\n customPrompt?: CustomPrompt\n /** Resolved feature flags */\n features?: FeaturesConfig\n /** Key files from the package (e.g., dist/pkg.d.ts) */\n pkgFiles?: string[]\n /** Lines consumed by SKILL.md overhead (frontmatter + header + search + footer) */\n overheadLines?: number\n}\n\nexport interface OptimizeResult {\n optimized: string\n wasOptimized: boolean\n error?: string\n warnings?: string[]\n reasoning?: string\n finishReason?: string\n usage?: { inputTokens: number, outputTokens: number, totalTokens: number }\n cost?: number\n debugLogsDir?: string\n}\n\nexport interface SectionResult {\n section: SkillSection\n content: string\n wasOptimized: boolean\n error?: string\n warnings?: ValidationWarning[]\n usage?: { input: number, output: number }\n cost?: number\n}\n\nexport interface ValidationWarning {\n section: string\n warning: string\n}\n\n/** Per-model config without redundant cli/agentId (those come from the CLI file) */\nexport interface CliModelEntry {\n /** Model flag passed to the CLI */\n model: string\n /** Human-readable model name */\n name: string\n /** Short description hint */\n hint: string\n /** Whether this is the recommended model for this CLI */\n recommended?: boolean\n}\n\n/** Full model config (assembled from CLI files + their models) */\nexport interface CliModelConfig extends CliModelEntry {\n cli: CliName\n agentId: AgentType\n}\n\nexport type CliName = 'claude' | 'gemini' | 'codex'\n\n/**\n * Per-CLI integration. Adding a new LLM CLI is one new file exporting one of these — no edits\n * to the dispatcher, the model table, or the provider name table.\n */\nexport interface CliAdapter {\n cli: CliName\n agentId: AgentType\n /** Human-readable LLM provider name (e.g. 'Anthropic', 'OpenAI'). */\n providerName: string\n /** Models this adapter can target, keyed by OptimizeModel id. */\n models: Record<string, CliModelEntry>\n /** Build argv for spawning the CLI process. */\n buildArgs: (model: string, skillDir: string, symlinkDirs: string[]) => string[]\n /** Parse one stream-json line into a normalized event. */\n parseEvent: (line: string) => CliEvent\n}\n","/**\n * Claude Code CLI — token-level streaming via --include-partial-messages.\n *\n * Write permission: Claude Code has hardcoded .claude/ write protection and --allowedTools glob\n * patterns are broken (github.com/anthropics/claude-code/issues/6881). Instead of fighting the\n * permission system, Write is auto-denied in pipe mode and we capture the content via a\n * tool-call event's writeContent.\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { buildModels } from './model-registry.ts'\nimport { extractToolHint } from './types.ts'\n\nconst stripClaude = (n: string): string => n.replace(/^Claude\\s+/, '').replace(/\\s*\\(latest\\)\\s*$/i, '')\n\nfunction buildArgs(model: string, skillDir: string, symlinkDirs: string[]): string[] {\n const allowedTools = [\n // Bare tool names — --add-dir already scopes visibility\n 'Read',\n 'Glob',\n 'Grep',\n 'Bash(*skilld search*)',\n 'Bash(*skilld validate*)',\n // Write intentionally omitted — auto-denied in pipe mode, content captured via writeContent\n ].join(' ')\n return [\n '-p',\n '--model',\n model,\n '--output-format',\n 'stream-json',\n '--verbose',\n '--include-partial-messages',\n '--allowedTools',\n allowedTools,\n '--disallowedTools',\n 'WebSearch WebFetch Task',\n '--add-dir',\n skillDir,\n ...symlinkDirs.flatMap(d => ['--add-dir', d]),\n '--no-session-persistence',\n ]\n}\n\n/**\n * Event types this parses:\n * - stream_event/content_block_delta/text_delta → text delta (token streaming)\n * - assistant message with tool_use content → tool-call (with writeContent for Write)\n * - assistant message with text content → text full (non-streaming fallback)\n * - result → done with usage/cost/turns\n */\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'stream_event') {\n const evt = obj.event\n if (evt?.type === 'content_block_delta' && evt.delta?.type === 'text_delta')\n return { kind: 'text', delta: evt.delta.text }\n return { kind: 'noop' }\n }\n\n if (obj.type === 'assistant' && obj.message?.content) {\n const content = obj.message.content as any[]\n\n const tools = content.filter((c: any) => c.type === 'tool_use')\n if (tools.length) {\n const tool = tools.map((t: any) => t.name).join(', ')\n const hint = tools.map((t: any) => extractToolHint(t.input) ?? '').filter(Boolean).join(', ') || undefined\n const writeTool = tools.find((t: any) => t.name === 'Write' && t.input?.content)\n return { kind: 'tool-call', tool, hint, writeContent: writeTool?.input?.content }\n }\n\n const text = content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('')\n if (text)\n return { kind: 'text', full: text }\n }\n\n if (obj.type === 'result') {\n const u = obj.usage\n return {\n kind: 'done',\n usage: u ? { input: u.input_tokens ?? u.inputTokens ?? 0, output: u.output_tokens ?? u.outputTokens ?? 0 } : undefined,\n cost: obj.total_cost_usd,\n turns: obj.num_turns,\n }\n }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'claude',\n agentId: 'claude-code',\n providerName: 'Anthropic',\n models: buildModels([\n { model: 'opus', provider: 'anthropic', prefix: 'claude-opus-', nameTransform: stripClaude, hint: 'Most capable for complex work' },\n { model: 'sonnet', provider: 'anthropic', prefix: 'claude-sonnet-', nameTransform: stripClaude, hint: 'Best for everyday tasks' },\n { model: 'haiku', provider: 'anthropic', prefix: 'claude-haiku-', nameTransform: stripClaude, hint: 'Fastest for quick answers', recommended: true },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * OpenAI Codex CLI — exec subcommand with JSON output. Prompt passed via stdin (`-` sentinel).\n *\n * Event types:\n * - turn.completed → done with usage\n * - item.started command_execution → tool-call (Bash, in progress)\n * - item.completed agent_message → text full\n * - item.completed command_execution → tool-call (with writeContent if redirected to a file)\n * - item.completed file_change → tool-call (apply_patch wrote a file)\n * - turn.failed / error → done (terminal)\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { buildModels } from './model-registry.ts'\n\nfunction buildArgs(model: string, _skillDir: string, _symlinkDirs: string[]): string[] {\n return [\n 'exec',\n '--json',\n '--ephemeral',\n '--model',\n model,\n // --full-auto = workspace-write sandbox + on-request approval. Writes scoped to CWD\n // (.skilld/, set in spawn), reads unrestricted, network blocked. Shell remains enabled\n // for `skilld` search/validate (Codex has no per-command allowlist).\n // --ephemeral = no session persistence (mirrors Claude's --no-session-persistence).\n '--full-auto',\n '-',\n ]\n}\n\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'item.completed' && obj.item) {\n const item = obj.item\n if (item.type === 'agent_message' && item.text)\n return { kind: 'text', full: item.text }\n if (item.type === 'command_execution' && item.aggregated_output) {\n const cmd = item.command || ''\n const writeContent = (/^cat\\s*>|>/.test(cmd)) ? item.aggregated_output : undefined\n return { kind: 'tool-call', tool: 'Bash', hint: `(${item.aggregated_output.length} chars output)`, writeContent }\n }\n if (item.type === 'file_change' && item.changes?.length) {\n const paths = item.changes.map((c: { path: string, kind: string }) => c.path).join(', ')\n return { kind: 'tool-call', tool: 'Write', hint: paths }\n }\n }\n\n if (obj.type === 'item.started' && obj.item?.type === 'command_execution')\n return { kind: 'tool-call', tool: 'Bash', hint: obj.item.command }\n\n if (obj.type === 'turn.completed' && obj.usage) {\n return {\n kind: 'done',\n usage: { input: obj.usage.input_tokens ?? 0, output: obj.usage.output_tokens ?? 0 },\n }\n }\n\n if (obj.type === 'turn.failed' || obj.type === 'error')\n return { kind: 'error', message: obj.message }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'codex',\n agentId: 'codex',\n providerName: 'OpenAI',\n models: buildModels([\n { provider: 'openai', prefix: 'gpt-', contains: 'codex', exclude: ['spark', 'mini', 'max'], hint: 'Latest frontier Codex model' },\n { provider: 'openai', prefix: 'gpt-', contains: 'codex-spark', hint: 'Faster Codex variant', recommended: true },\n { provider: 'openai', prefix: 'gpt-', contains: 'codex-mini', hint: 'Cheapest Codex variant' },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * Gemini CLI — turn-level streaming via -o stream-json.\n * Write scoping: relies on cwd being set to .skilld/ (no native --writeable-dirs).\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { resolveSkilldCommand } from '../../core/skilld-command.ts'\nimport { buildModels } from './model-registry.ts'\nimport { extractToolHint } from './types.ts'\n\nfunction buildArgs(model: string, skillDir: string, symlinkDirs: string[]): string[] {\n return [\n '-o',\n 'stream-json',\n '-m',\n model,\n '--allowed-tools',\n `read_file,write_file,glob_tool,list_directory,search_file_content,run_shell_command(${resolveSkilldCommand()}),run_shell_command(grep),run_shell_command(head)`,\n '--include-directories',\n skillDir,\n ...symlinkDirs.flatMap(d => ['--include-directories', d]),\n ]\n}\n\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'message' && obj.role === 'assistant' && obj.content) {\n return obj.delta ? { kind: 'text', delta: obj.content } : { kind: 'text', full: obj.content }\n }\n\n if (obj.type === 'tool_use' || obj.type === 'tool_call') {\n const tool = obj.tool_name || obj.name || obj.tool || 'tool'\n const params = obj.parameters || obj.args || obj.input || {}\n const hint = extractToolHint(params)\n const writeContent = tool === 'write_file' && typeof params.content === 'string' ? params.content : undefined\n return { kind: 'tool-call', tool, hint, writeContent }\n }\n\n if (obj.type === 'result') {\n const s = obj.stats\n return {\n kind: 'done',\n usage: s ? { input: s.input_tokens ?? s.input ?? 0, output: s.output_tokens ?? s.output ?? 0 } : undefined,\n turns: s?.tool_calls,\n }\n }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'gemini',\n agentId: 'gemini-cli',\n providerName: 'Google',\n models: buildModels([\n { provider: 'google', prefix: 'gemini-', contains: 'pro', exclude: ['flash', 'live', 'gemma'], hint: 'Most capable' },\n { provider: 'google', prefix: 'gemini-', contains: 'flash', exclude: ['lite', 'live', 'preview'], hint: 'Balanced', recommended: true },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * pi-ai auth — OAuth credentials, env API keys, login/logout flows.\n *\n * OAuth providers known to ban accounts for unauthorized usage are blocked.\n * API key access (env vars) remains supported for those providers.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { getEnvApiKey, getProviders } from '@mariozechner/pi-ai'\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from '@mariozechner/pi-ai/oauth'\nimport { join } from 'pathe'\nimport { CACHE_DIR, PI_AI_AUTH_PATH } from '../../core/paths.ts'\n\n/**\n * Consumer-OAuth providers that ban accounts for unauthorized usage.\n * API-key access remains supported for these.\n */\nexport const BLOCKED_OAUTH_PROVIDERS: ReadonlySet<string> = new Set([\n 'google-antigravity',\n 'google-gemini-cli',\n 'github-copilot',\n 'anthropic',\n 'openai-codex',\n])\n\nconst PI_AGENT_AUTH_PATH = join(\n process.env.PI_CODING_AGENT_DIR || join(homedir(), '.pi', 'agent'),\n 'auth.json',\n)\nconst SKILLD_AUTH_PATH = PI_AI_AUTH_PATH\n\n/**\n * Overrides for model-provider → OAuth-provider mapping. Most providers share\n * the same id in both systems (auto-matched); list only divergences.\n */\nconst OAUTH_PROVIDER_OVERRIDES: Record<string, string> = {\n google: 'google-gemini-cli',\n openai: 'openai-codex',\n}\n\ninterface OAuthCredentials {\n type: 'oauth'\n refresh: string\n access: string\n expires: number\n [key: string]: unknown\n}\n\nfunction readAuthFile(path: string): Record<string, OAuthCredentials> {\n if (!existsSync(path))\n return {}\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n }\n catch { return {} }\n}\n\n/** Load auth from pi coding agent first, then skilld's own. pi agent wins on conflict. */\nexport function loadAuth(): Record<string, OAuthCredentials> {\n const piAuth = readAuthFile(PI_AGENT_AUTH_PATH)\n const skilldAuth = readAuthFile(SKILLD_AUTH_PATH)\n return { ...skilldAuth, ...piAuth }\n}\n\nfunction saveAuth(auth: Record<string, OAuthCredentials>): void {\n mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 })\n writeFileSync(SKILLD_AUTH_PATH, JSON.stringify(auth, null, 2), { mode: 0o600 })\n}\n\n/** Resolve model provider id → OAuth provider id (returns null for blocked providers). */\nexport function resolveOAuthProviderId(modelProvider: string): string | null {\n const oauthId = OAUTH_PROVIDER_OVERRIDES[modelProvider] ?? modelProvider\n if (BLOCKED_OAUTH_PROVIDERS.has(oauthId))\n return null\n if (OAUTH_PROVIDER_OVERRIDES[modelProvider])\n return OAUTH_PROVIDER_OVERRIDES[modelProvider]!\n const oauthIds = new Set((getOAuthProviders() as Array<{ id: string }>).map(p => p.id))\n if (oauthIds.has(modelProvider))\n return modelProvider\n return null\n}\n\n/** Resolve API key for a provider — env vars first, then stored OAuth credentials. */\nexport async function resolveApiKey(provider: string): Promise<string | null> {\n const envKey = getEnvApiKey(provider)\n if (envKey)\n return envKey\n\n const oauthProviderId = resolveOAuthProviderId(provider)\n if (!oauthProviderId)\n return null\n\n const auth = loadAuth()\n if (!auth[oauthProviderId])\n return null\n\n const result = await getOAuthApiKey(oauthProviderId, auth)\n if (!result)\n return null\n\n // Refreshed credentials go to skilld's own file only, never leak pi-agent tokens.\n const skilldAuth = readAuthFile(SKILLD_AUTH_PATH)\n skilldAuth[oauthProviderId] = { type: 'oauth', ...result.newCredentials }\n saveAuth(skilldAuth)\n return result.apiKey\n}\n\nexport interface LoginCallbacks {\n onAuth: (url: string, instructions?: string) => void\n onPrompt: (message: string, placeholder?: string) => Promise<string>\n onProgress?: (message: string) => void\n}\n\nexport function getOAuthProviderList(): Array<{ id: string, name: string, loggedIn: boolean }> {\n const auth = loadAuth()\n const providers = getOAuthProviders() as Array<{ id: string, name: string }>\n return providers\n .filter(p => !BLOCKED_OAUTH_PROVIDERS.has(p.id))\n .map(p => ({ id: p.id, name: p.name ?? p.id, loggedIn: !!auth[p.id] }))\n}\n\nexport async function loginOAuthProvider(providerId: string, callbacks: LoginCallbacks): Promise<boolean> {\n const provider = getOAuthProvider(providerId)\n if (!provider)\n return false\n\n const credentials = await provider.login({\n onAuth: (info: any) => callbacks.onAuth(info.url, info.instructions),\n onPrompt: async (prompt: any) => callbacks.onPrompt(prompt.message, prompt.placeholder),\n onProgress: (msg: string) => callbacks.onProgress?.(msg),\n })\n\n const auth = loadAuth()\n auth[providerId] = { type: 'oauth', ...credentials }\n saveAuth(auth)\n return true\n}\n\nexport function logoutOAuthProvider(providerId: string): void {\n const auth = loadAuth()\n delete auth[providerId]\n saveAuth(auth)\n}\n\n/** Re-export for callers that want pi-ai's provider list without importing from pi-ai directly. */\nexport { getEnvApiKey, getProviders }\n","/**\n * pi-ai model identification + dynamic model enumeration.\n *\n * Models are sourced from pi-ai's registry; legacy generations and tiny\n * context windows are filtered out. A \"recommended\" model is auto-picked\n * per provider for ergonomic defaults.\n */\n\nimport { getEnvApiKey, getModels, getProviders } from '@mariozechner/pi-ai'\nimport { loadAuth, resolveOAuthProviderId } from './pi-ai-auth.ts'\n\nexport function isPiAiModel(model: string): boolean {\n return model.startsWith('pi:')\n}\n\n/** Parse a `pi:provider/model-id` string → `{ provider, modelId }`. */\nexport function parsePiAiModelId(model: string): { provider: string, modelId: string } | null {\n if (!model.startsWith('pi:'))\n return null\n const rest = model.slice(3)\n const slashIdx = rest.indexOf('/')\n if (slashIdx === -1)\n return null\n return { provider: rest.slice(0, slashIdx), modelId: rest.slice(slashIdx + 1) }\n}\n\nconst MIN_CONTEXT_WINDOW = 32_000\n\n/** Old generations that clutter the model list. */\nconst LEGACY_MODEL_PATTERNS = [\n // Anthropic: claude 3.x family\n /^claude-3-/,\n /^claude-3\\.5-/,\n /^claude-3\\.7-/,\n // OpenAI: pre-gpt-5\n /^gpt-4(?!\\.\\d)/, // gpt-4, gpt-4-turbo, gpt-4o but not gpt-4.1\n /^o1/,\n /^o3-mini/,\n // Google: old gemini generations + non-text models\n /^gemini-1\\./,\n /^gemini-2\\.0/,\n /^gemini-live-/,\n // Preview snapshots with date suffixes\n /-preview-\\d{2}-\\d{2,4}$/,\n // Dated model snapshots\n /-\\d{8}$/,\n]\n\nfunction isLegacyModel(modelId: string): boolean {\n return LEGACY_MODEL_PATTERNS.some(p => p.test(modelId))\n}\n\n/** Cheapest reliable option per provider, picked for auto-selection. */\nconst RECOMMENDED_MODELS: Record<string, RegExp> = {\n anthropic: /haiku/,\n google: /flash/,\n openai: /gpt-4\\.1-mini/,\n}\n\nexport interface PiAiModelInfo {\n /** Full model ID: `pi:provider/model-id`. */\n id: string\n name: string\n hint: string\n authSource: 'env' | 'oauth' | 'none'\n recommended: boolean\n}\n\nexport function getAvailablePiAiModels(): PiAiModelInfo[] {\n const providers: string[] = getProviders()\n const auth = loadAuth()\n const available: PiAiModelInfo[] = []\n const recommendedPicked = new Set<string>()\n\n for (const provider of providers) {\n let authSource: 'env' | 'oauth' | 'none' = 'none'\n if (getEnvApiKey(provider)) {\n authSource = 'env'\n }\n else {\n const oauthId = resolveOAuthProviderId(provider)\n if (oauthId && auth[oauthId])\n authSource = 'oauth'\n }\n\n if (authSource === 'none')\n continue\n\n const models: any[] = getModels(provider as any)\n const recPattern = RECOMMENDED_MODELS[provider]\n let recModelId: string | null = null\n if (recPattern) {\n for (const model of models) {\n if (!isLegacyModel(model.id) && recPattern.test(model.id)) {\n recModelId = model.id\n break\n }\n }\n }\n\n for (const model of models) {\n if (model.contextWindow && model.contextWindow < MIN_CONTEXT_WINDOW)\n continue\n if (isLegacyModel(model.id))\n continue\n\n const id = `pi:${provider}/${model.id}`\n const ctx = model.contextWindow ? ` · ${Math.round(model.contextWindow / 1000)}k ctx` : ''\n const cost = model.cost?.input ? ` · $${model.cost.input}/Mtok` : ''\n const isRecommended = model.id === recModelId && !recommendedPicked.has(provider)\n\n if (isRecommended)\n recommendedPicked.add(provider)\n\n available.push({\n id,\n name: model.name || model.id,\n hint: `${authSource === 'oauth' ? 'OAuth' : 'API key'}${ctx}${cost}`,\n authSource,\n recommended: isRecommended,\n })\n }\n }\n\n return available\n}\n","/**\n * Sandboxed tool execution for the pi-ai agentic loop.\n *\n * The model can Read/Glob/Write within `.skilld/` and run a tightly\n * allowlisted set of shell commands. All file operations resolve through\n * `resolveSandboxedPath` which blocks traversal outside `skilldDir`.\n */\n\nimport type { ToolCall } from '@mariozechner/pi-ai'\nimport { execFileSync } from 'node:child_process'\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { join } from 'pathe'\nimport { Type } from 'typebox'\nimport { sanitizeMarkdown } from '../../core/sanitize.ts'\n\nexport const TOOLS = [\n {\n name: 'Read',\n description: 'Read a file. Path is relative to the working directory (e.g. \"./.skilld/docs/api.md\").',\n parameters: Type.Object({ path: Type.String({ description: 'File path to read' }) }),\n },\n {\n name: 'Glob',\n description: 'List files matching a glob pattern (e.g. \"./.skilld/docs/*.md\"). Returns newline-separated paths.',\n parameters: Type.Object({\n pattern: Type.String({ description: 'Glob pattern' }),\n no_ignore: Type.Optional(Type.Boolean({ description: 'Include gitignored files' })),\n }),\n },\n {\n name: 'Write',\n description: 'Write content to a file.',\n parameters: Type.Object({\n path: Type.String({ description: 'File path to write' }),\n content: Type.String({ description: 'File content' }),\n }),\n },\n {\n name: 'Bash',\n description: 'Run a shell command. Use for `skilld search`, `skilld validate`, etc.',\n parameters: Type.Object({ command: Type.String({ description: 'Shell command to run' }) }),\n },\n]\n\nexport const MAX_TOOL_TURNS = 30\n\nconst SAFE_COMMANDS = new Set(['skilld', 'ls', 'cat', 'find'])\nconst SHELL_META_RE = /[;&|`$()<>]/\n\n/** Resolve a path safely within skilldDir, blocking traversal. */\nfunction resolveSandboxedPath(p: string, skilldDir: string): string {\n const cleaned = String(p).replace(/^\\.\\/\\.skilld\\//, './').replace(/^\\.skilld\\//, './').replace(/^\\.\\//, '')\n const resolved = resolve(skilldDir, cleaned)\n if (!resolved.startsWith(`${skilldDir}/`) && resolved !== skilldDir)\n throw new Error(`Path traversal blocked: ${p}`)\n return resolved\n}\n\n/** Match a file path against a glob pattern using simple segment matching (no regex from user input). */\nfunction globMatch(filePath: string, pattern: string): boolean {\n const segments = pattern.split('**')\n if (segments.length === 1) {\n const parts = pattern.split('*')\n if (parts.length === 1)\n return filePath === pattern\n let pos = 0\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n if (!part)\n continue\n const idx = filePath.indexOf(part, pos)\n if (idx === -1)\n return false\n if (i === 0 && idx !== 0)\n return false\n pos = idx + part.length\n }\n if (parts.at(-1) !== '')\n return pos === filePath.length\n return true\n }\n let remaining = filePath\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!\n if (!seg)\n continue\n const segParts = seg.split('*')\n let pos = 0\n let matched = false\n for (let attempt = remaining.indexOf(segParts[0]!, 0); attempt !== -1; attempt = remaining.indexOf(segParts[0]!, attempt + 1)) {\n pos = attempt\n matched = true\n for (const sp of segParts) {\n if (!sp)\n continue\n const idx = remaining.indexOf(sp, pos)\n if (idx === -1) {\n matched = false\n break\n }\n pos = idx + sp.length\n }\n if (matched)\n break\n }\n if (!matched)\n return false\n remaining = remaining.slice(pos)\n }\n return true\n}\n\n/** Execute a tool call against the .skilld/ directory. */\nexport function executeTool(toolCall: ToolCall, skilldDir: string): string {\n const args = toolCall.arguments as Record<string, unknown>\n\n switch (toolCall.name) {\n case 'Read': {\n const filePath = resolveSandboxedPath(args.path as string, skilldDir)\n if (!existsSync(filePath))\n return `Error: file not found: ${args.path}`\n return sanitizeMarkdown(readFileSync(filePath, 'utf-8'))\n }\n case 'Glob': {\n const pattern = String(args.pattern).replace(/^\\.\\/\\.skilld\\//, './').replace(/^\\.skilld\\//, './').replace(/^\\.\\//, '')\n const results: string[] = []\n const walkDir = (dir: string, prefix: string) => {\n if (!existsSync(dir))\n return\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n if (entry.isDirectory())\n walkDir(join(dir, entry.name), relPath)\n else results.push(`./.skilld/${relPath}`)\n }\n }\n const baseDir = pattern.split('*')[0]?.replace(/\\/$/, '') ?? ''\n walkDir(join(skilldDir, baseDir), baseDir)\n const matched = results.filter(r => globMatch(r.replace(/^\\.\\/\\.skilld\\//, ''), pattern))\n return matched.length > 0 ? matched.join('\\n') : `No files matching: ${args.pattern}`\n }\n case 'Write': {\n const filePath = resolveSandboxedPath(args.path as string, skilldDir)\n writeFileSync(filePath, sanitizeMarkdown(String(args.content)))\n return 'File written successfully.'\n }\n case 'Bash': {\n const cmd = String(args.command).trim()\n const parts = cmd.split(/\\s+/)\n const bin = parts[0] ?? ''\n if (!SAFE_COMMANDS.has(bin) || SHELL_META_RE.test(cmd))\n return `Error: command not allowed. Only skilld, ls, cat, find commands are permitted.`\n try {\n return execFileSync(bin, parts.slice(1), { cwd: skilldDir, timeout: 15_000, encoding: 'utf-8', maxBuffer: 512 * 1024 }).trim()\n }\n catch (err) {\n return `Error: ${(err as Error).message}`\n }\n }\n default:\n return `Unknown tool: ${toolCall.name}`\n }\n}\n","/**\n * pi-ai section runner — drives the agentic tool-use loop for a single SKILL.md\n * section. Streams reasoning + text to onProgress; tools are sandboxed to .skilld/.\n */\n\nimport type { AssistantMessage, Message, ToolCall } from '@mariozechner/pi-ai'\nimport type { SkillSection } from '../prompts/index.ts'\nimport type { StreamProgress } from './types.ts'\nimport { getModel, streamSimple } from '@mariozechner/pi-ai'\nimport { skillInternalDir } from '../../core/paths.ts'\nimport { resolveApiKey } from './pi-ai-auth.ts'\nimport { parsePiAiModelId } from './pi-ai-models.ts'\nimport { executeTool, MAX_TOOL_TURNS, TOOLS } from './pi-ai-tools.ts'\n\nexport interface PiAiSectionOptions {\n section: SkillSection\n prompt: string\n skillDir: string\n model: string\n onProgress?: (progress: StreamProgress) => void\n signal?: AbortSignal\n}\n\nexport interface PiAiSectionResult {\n text: string\n /** The raw prompt sent to the model. */\n fullPrompt: string\n usage?: { input: number, output: number }\n cost?: number\n}\n\nconst SYSTEM_PROMPT = 'You are a technical documentation expert generating SKILL.md sections for AI agent skills. Follow the format instructions exactly. Use the provided tools to explore reference files in ./.skilld/ before writing your output.'\n\n/** Optimize a single section using pi-ai agentic API with tool use. */\nexport async function optimizeSectionPiAi(opts: PiAiSectionOptions): Promise<PiAiSectionResult> {\n const parsed = parsePiAiModelId(opts.model)\n if (!parsed)\n throw new Error(`Invalid pi-ai model ID: ${opts.model}. Expected format: pi:provider/model-id`)\n\n const model = getModel(parsed.provider as any, parsed.modelId as any)\n const apiKey = await resolveApiKey(parsed.provider)\n const skilldDir = skillInternalDir(opts.skillDir)\n\n const fullPrompt = opts.prompt\n\n opts.onProgress?.({ chunk: '[starting...]', type: 'reasoning', text: '', reasoning: '', section: opts.section })\n\n const messages: Message[] = [{\n role: 'user' as const,\n content: [{ type: 'text' as const, text: fullPrompt }],\n timestamp: Date.now(),\n }]\n\n let text = ''\n let completed = false\n let totalUsage: { input: number, output: number } | undefined\n let totalCost: number | undefined\n let lastWriteContent = ''\n\n for (let turn = 0; turn < MAX_TOOL_TURNS; turn++) {\n if (opts.signal?.aborted)\n throw new Error('pi-ai request timed out')\n\n const eventStream = streamSimple(model, {\n systemPrompt: SYSTEM_PROMPT,\n messages,\n tools: TOOLS,\n }, {\n reasoning: turn === 0 ? 'medium' : undefined,\n maxTokens: 16_384,\n ...(apiKey ? { apiKey } : {}),\n })\n\n let assistantMessage: AssistantMessage | undefined\n let turnText = ''\n\n for await (const event of eventStream) {\n if (opts.signal?.aborted)\n throw new Error('pi-ai request timed out')\n\n switch (event.type) {\n case 'text_delta':\n turnText += event.delta\n opts.onProgress?.({ chunk: event.delta, type: 'text', text: turnText, reasoning: '', section: opts.section })\n break\n case 'toolcall_end': {\n const tc = event.toolCall\n const hint = tc.name === 'Read' || tc.name === 'Write'\n ? `[${tc.name}: ${tc.arguments.path}]`\n : tc.name === 'Bash'\n ? `[${tc.name}: ${tc.arguments.command}]`\n : `[${tc.name}: ${tc.arguments.pattern}]`\n opts.onProgress?.({ chunk: hint, type: 'reasoning', text: '', reasoning: hint, section: opts.section })\n break\n }\n case 'done':\n assistantMessage = event.message\n break\n case 'error':\n throw new Error(event.error?.errorMessage ?? 'pi-ai stream error')\n }\n }\n\n if (!assistantMessage)\n throw new Error('pi-ai stream ended without a message')\n\n if (assistantMessage.usage) {\n if (totalUsage) {\n totalUsage.input += assistantMessage.usage.input\n totalUsage.output += assistantMessage.usage.output\n }\n else {\n totalUsage = { input: assistantMessage.usage.input, output: assistantMessage.usage.output }\n }\n totalCost = (totalCost ?? 0) + (assistantMessage.usage.cost?.total ?? 0)\n }\n\n messages.push(assistantMessage)\n\n const toolCalls = assistantMessage.content.filter((c): c is ToolCall => c.type === 'toolCall')\n if (toolCalls.length === 0) {\n text = turnText\n completed = true\n break\n }\n\n for (const tc of toolCalls) {\n const result = executeTool(tc, skilldDir)\n if (tc.name === 'Write')\n lastWriteContent = String(tc.arguments.content)\n messages.push({\n role: 'toolResult' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n content: [{ type: 'text' as const, text: result }],\n isError: result.startsWith('Error:'),\n timestamp: Date.now(),\n })\n }\n }\n\n if (!completed)\n throw new Error(`pi-ai exceeded ${MAX_TOOL_TURNS} tool turns without completing`)\n\n // Prefer text output, fall back to last Write content.\n const finalText = text || lastWriteContent\n\n return { text: finalText, fullPrompt, usage: totalUsage, cost: totalCost }\n}\n","import { sanitizeMarkdown } from '../../core/sanitize.ts'\n\n/** Clean a single section's LLM output: strip markdown fences, frontmatter, sanitize */\nexport function cleanSectionOutput(content: string): string {\n let cleaned = content.trim()\n\n // Strip wrapping fences if output is wrapped in ```markdown, ```md, or bare ```\n // Requires matched open+close pair to avoid stripping internal code blocks\n const wrapMatch = cleaned.match(/^```(?:markdown|md)?[^\\S\\n]*\\n([\\s\\S]+)\\n```[^\\S\\n]*$/)\n if (wrapMatch) {\n const inner = wrapMatch[1]!.trim()\n // For bare ``` wrappers (no markdown/md tag), verify inner looks like section output\n const isExplicitWrapper = /^```(?:markdown|md)/.test(cleaned)\n if (isExplicitWrapper || /^##\\s/m.test(inner) || /^- (?:BREAKING|DEPRECATED|NEW): /m.test(inner)) {\n cleaned = inner\n }\n }\n\n // Normalize h1 headers to h2 — LLMs sometimes use # instead of ##\n cleaned = cleaned.replace(/^# (?!#)/gm, '## ')\n\n // Strip accidental frontmatter or leading horizontal rules\n const fmMatch = cleaned.match(/^-{3,}\\n/)\n if (fmMatch) {\n const afterOpen = fmMatch[0].length\n const closeMatch = cleaned.slice(afterOpen).match(/\\n-{3,}/)\n if (closeMatch) {\n cleaned = cleaned.slice(afterOpen + closeMatch.index! + closeMatch[0].length).trim()\n }\n else {\n cleaned = cleaned.slice(afterOpen).trim()\n }\n }\n\n // Strip preamble before first section marker (LLM reasoning, fake tool calls, code dumps)\n // Section markers: ## heading, BREAKING/DEPRECATED/NEW labels\n const firstMarker = cleaned.match(/^(##\\s|- (?:BREAKING|DEPRECATED|NEW): )/m)\n if (firstMarker?.index && firstMarker.index > 0) {\n cleaned = cleaned.slice(firstMarker.index).trim()\n }\n\n // Strip duplicate section headings (LLM echoing the format example before real content)\n // Handles headings separated by blank lines or boilerplate text\n const headingMatch = cleaned.match(/^(## .+)\\n/)\n if (headingMatch) {\n const heading = headingMatch[1]!\n const afterFirst = headingMatch[0].length\n const secondIdx = cleaned.indexOf(heading, afterFirst)\n if (secondIdx !== -1) {\n // Only strip if the gap between duplicates is small (< 200 chars of boilerplate)\n if (secondIdx - afterFirst < 200)\n cleaned = cleaned.slice(secondIdx).trim()\n }\n }\n\n // Normalize citation link text to [source] — LLMs sometimes use the path as link text\n // e.g. [./references/docs/api.md](./references/docs/api.md) or [`./references/...`](...)\n // Also handles paren-wrapped variants: ([`path`](url))\n cleaned = cleaned.replace(\n /\\(?\\[`?\\.\\/(?:\\.skilld\\/|references\\/)[^)\\]]*\\]\\(([^)]+)\\)\\)?/g,\n (match, url: string) => {\n // Only normalize if the URL points to a reference path\n if (/^\\.\\/(?:\\.skilld\\/|references\\/)/.test(url))\n return `[source](${url})`\n return match\n },\n )\n\n // Normalize source link paths: ensure .skilld/ prefix is present\n // LLMs sometimes emit [source](./docs/...) instead of [source](./.skilld/docs/...)\n cleaned = cleaned.replace(\n /\\[source\\]\\(\\.\\/((docs|issues|discussions|releases|pkg|guide)\\/)/g,\n '[source](./.skilld/$1',\n )\n\n cleaned = sanitizeMarkdown(cleaned)\n\n // Reject content that lacks any section structure — likely leaked LLM reasoning/narration\n // Valid sections contain headings (##), API change labels, or source-linked items\n if (!/^##\\s/m.test(cleaned) && !/^- (?:BREAKING|DEPRECATED|NEW): /m.test(cleaned) && !/\\[source\\]/.test(cleaned)) {\n return ''\n }\n\n return cleaned\n}\n","import type { StreamProgress } from './types.ts'\nimport { TOOL_NAMES } from './types.ts'\n\ninterface ToolProgressLog {\n message: (msg: string) => void\n}\n\n/** Create a progress callback that emits one line per tool call, Claude Code style */\nexport function createToolProgress(log: ToolProgressLog): (progress: StreamProgress) => void {\n let lastMsg = ''\n let repeatCount = 0\n /** Per-section timestamp of last \"Writing...\" emission — throttles text_delta spam */\n const lastTextEmit = new Map<string, number>()\n const TEXT_THROTTLE_MS = 2000\n\n function emit(msg: string) {\n if (msg === lastMsg) {\n repeatCount++\n log.message(`${msg} \\x1B[90m(+${repeatCount})\\x1B[0m`)\n }\n else {\n lastMsg = msg\n repeatCount = 0\n log.message(msg)\n }\n }\n\n return ({ type, chunk, text, section }) => {\n if (type === 'text') {\n const key = section ?? ''\n const now = Date.now()\n const last = lastTextEmit.get(key) ?? 0\n if (now - last < TEXT_THROTTLE_MS)\n return\n lastTextEmit.set(key, now)\n const prefix = section ? `\\x1B[90m[${section}]\\x1B[0m ` : ''\n // Count bullet items in accumulated text for meaningful progress\n const items = text ? (text.match(/^- (?:BREAKING|DEPRECATED|NEW|CHANGED|REMOVED|Use |Do |Set |Add |Avoid |Always |Never |Prefer |Check |Ensure )/gm)?.length ?? 0) : 0\n emit(items > 0 ? `${prefix}Writing... \\x1B[90m(${items} items)\\x1B[0m` : `${prefix}Writing...`)\n return\n }\n if (type !== 'reasoning' || !chunk.startsWith('['))\n return\n\n // Handle status messages like [starting...], [retrying...], [cached]\n if (/^\\[(?:starting|retrying|cached)/.test(chunk)) {\n const prefix = section ? `\\x1B[90m[${section}]\\x1B[0m ` : ''\n emit(`${prefix}${chunk.slice(1, -1)}`)\n return\n }\n\n // Parse individual tool names and hints from \"[Read: path]\" or \"[Read, Glob: path1, path2]\"\n const match = chunk.match(/^\\[([^:[\\]]+)(?::\\s(.+))?\\]$/)\n if (!match)\n return\n\n const names = match[1]!.split(',').map(n => n.trim())\n const hints = match[2]?.split(',').map(h => h.trim()) ?? []\n\n for (let i = 0; i < names.length; i++) {\n const rawName = names[i]!\n const hint = hints[i] ?? hints[0] ?? ''\n const verb = TOOL_NAMES[rawName]?.verb ?? rawName\n const prefix = section ? `\\x1B[90m[${section}]\\x1B[0m ` : ''\n\n if ((rawName === 'Bash' || rawName === 'run_shell_command') && hint) {\n const searchMatch = hint.match(/skilld search\\s+\"([^\"]+)\"/)\n if (searchMatch) {\n emit(`${prefix}Searching \\x1B[36m\"${searchMatch[1]}\"\\x1B[0m`)\n }\n else if (hint.includes('skilld validate')) {\n emit(`${prefix}Validating...`)\n }\n else {\n const shortened = shortenCommand(hint)\n emit(`${prefix}Running ${shortened.length > 50 ? `${shortened.slice(0, 47)}...` : shortened}`)\n }\n }\n else {\n const path = shortenPath(hint || '...')\n emit(`${prefix}${verb} \\x1B[90m${path}\\x1B[0m`)\n }\n }\n }\n}\n\n/** Shorten absolute paths for display: /home/user/project/.claude/skills/vue/SKILL.md → .claude/.../SKILL.md */\nfunction shortenPath(p: string): string {\n const refIdx = p.indexOf('.skilld/')\n if (refIdx !== -1)\n return p.slice(refIdx + '.skilld/'.length)\n // Keep just filename for other paths\n const parts = p.split('/')\n return parts.length > 2 ? `.../${parts.slice(-2).join('/')}` : p\n}\n\n/** Replace absolute paths in a command string with shortened versions */\nfunction shortenCommand(cmd: string): string {\n return cmd.replace(/\\/[^\\s\"']+/g, (match) => {\n // Only shorten paths that look like they're inside a project\n if (match.includes('.claude/') || match.includes('.skilld/') || match.includes('node_modules/'))\n return `.../${match.split('/').slice(-2).join('/')}`\n return match\n })\n}\n","/**\n * CLI orchestrator — spawns per-CLI processes for skill generation\n * Each CLI (claude, gemini, codex) has its own buildArgs + parseLine in separate files\n */\n\nimport type { AgentType } from '../types.ts'\nimport type { CliAdapter, CliModelConfig, CliName, OptimizeModel } from './types.ts'\nimport { exec } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { isWindows } from 'std-env'\nimport { detectInstalledAgents } from '../detect.ts'\nimport { agents } from '../registry.ts'\nimport { adapter as claudeAdapter } from './claude.ts'\nimport { adapter as codexAdapter } from './codex.ts'\nimport { adapter as geminiAdapter } from './gemini.ts'\nimport { getAvailablePiAiModels, isPiAiModel, parsePiAiModelId } from './pi-ai.ts'\n\nexport { buildAllSectionPrompts, buildSectionPrompt, SECTION_MERGE_ORDER, SECTION_OUTPUT_FILES } from '../prompts/index.ts'\nexport type { CustomPrompt, SkillSection } from '../prompts/index.ts'\nexport { cleanSectionOutput } from './clean-output.ts'\nexport { createToolProgress } from './cli-progress.ts'\nexport type { CliModelConfig, CliName, ModelInfo, OptimizeDocsOptions, OptimizeModel, OptimizeResult, StreamProgress } from './types.ts'\n\n// ── Per-CLI dispatch ─────────────────────────────────────────────────\n\n/** Single source of truth: adding a new CLI adapter here is the only edit needed in this file. */\nexport const CLI_ADAPTERS: Record<CliName, CliAdapter> = {\n claude: claudeAdapter,\n gemini: geminiAdapter,\n codex: codexAdapter,\n}\n\nconst CLI_PROVIDER_NAMES: Record<string, string> = Object.fromEntries(\n Object.values(CLI_ADAPTERS).map(a => [a.agentId, a.providerName]),\n)\n\nconst PI_PROVIDER_NAMES: Record<string, string> = {\n 'anthropic': 'Anthropic',\n 'google': 'Google',\n 'google-antigravity': 'Antigravity',\n 'google-gemini-cli': 'Google Gemini',\n 'google-vertex': 'Google Vertex',\n 'openai': 'OpenAI',\n 'openai-codex': 'OpenAI Codex',\n 'github-copilot': 'GitHub Copilot',\n 'groq': 'Groq',\n 'mistral': 'Mistral',\n 'xai': 'xAI',\n}\n\n// ── Assemble CLI_MODELS from per-CLI model definitions ───────────────\n\nexport const CLI_MODELS: Partial<Record<OptimizeModel, CliModelConfig>> = Object.fromEntries(\n Object.values(CLI_ADAPTERS).flatMap(adapter =>\n Object.entries(adapter.models).map(([id, entry]) => [\n id,\n { ...entry, cli: adapter.cli, agentId: adapter.agentId },\n ]),\n ),\n)\n\n// ── Model helpers ────────────────────────────────────────────────────\n\nexport function getModelName(id: OptimizeModel): string {\n if (isPiAiModel(id)) {\n const parsed = parsePiAiModelId(id)\n return parsed?.modelId ?? id\n }\n return CLI_MODELS[id]?.name ?? id\n}\n\nexport function getModelLabel(id: OptimizeModel): string {\n if (isPiAiModel(id)) {\n const parsed = parsePiAiModelId(id)\n return parsed ? `${PI_PROVIDER_NAMES[parsed.provider] ?? parsed.provider} · ${parsed.modelId}` : id\n }\n const config = CLI_MODELS[id]\n if (!config)\n return id\n const providerName = CLI_PROVIDER_NAMES[config.agentId] ?? config.cli\n return `${providerName} · ${config.name}`\n}\n\nexport async function getAvailableModels(): Promise<import('./types.ts').ModelInfo[]> {\n const execAsync = promisify(exec)\n const lookupCmd = isWindows ? 'where' : 'which'\n\n const installedAgents = detectInstalledAgents()\n const agentsWithCli = installedAgents.filter(id => agents[id].cli)\n\n const cliChecks = await Promise.all(\n agentsWithCli.map(async (agentId) => {\n const cli = agents[agentId].cli!\n try {\n await execAsync(`${lookupCmd} ${cli}`)\n return agentId\n }\n catch { return null }\n }),\n )\n const availableAgentIds = new Set(cliChecks.filter((id): id is AgentType => id != null))\n\n const cliModels = (Object.entries(CLI_MODELS) as [OptimizeModel, CliModelConfig][])\n .filter(([_, config]) => availableAgentIds.has(config.agentId))\n .map(([id, config]) => {\n const providerName = CLI_PROVIDER_NAMES[config.agentId] ?? agents[config.agentId]?.displayName ?? config.agentId\n return {\n id,\n name: config.name,\n hint: config.hint,\n recommended: config.recommended,\n agentId: config.agentId,\n agentName: providerName,\n provider: config.agentId,\n providerName: `${providerName} (via ${config.cli} CLI)`,\n vendorGroup: providerName,\n }\n })\n\n // Append pi-ai direct API models (providers with auth configured)\n const piAiModels = getAvailablePiAiModels()\n const piAiEntries = piAiModels.map((m) => {\n const parsed = parsePiAiModelId(m.id)\n const piProvider = parsed?.provider ?? 'pi-ai'\n const displayName = PI_PROVIDER_NAMES[piProvider] ?? piProvider\n const authLabel = m.authSource === 'env' ? 'API' : 'OAuth'\n return {\n id: m.id as OptimizeModel,\n name: m.name,\n hint: m.hint,\n recommended: m.recommended,\n agentId: 'pi-ai',\n agentName: `pi-ai (${m.authSource})`,\n provider: `pi:${piProvider}:${m.authSource}`,\n providerName: `${displayName} (${authLabel})`,\n vendorGroup: displayName,\n }\n })\n\n return [...cliModels, ...piAiEntries]\n}\n","/**\n * Detect packages from framework presets (e.g., Nuxt modules in nuxt.config)\n * These are string literals in config arrays, not imports — the import scanner misses them.\n */\n\nimport type { PackageUsage } from './detect-imports.ts'\nimport { readFile } from 'node:fs/promises'\nimport { parseSync } from 'oxc-parser'\nimport { join } from 'pathe'\n\nconst NUXT_CONFIG_FILES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\nconst NUXT_ECOSYSTEM = ['vue', 'nitro', 'h3']\n\nasync function findNuxtConfig(cwd: string): Promise<{ path: string, content: string } | null> {\n for (const name of NUXT_CONFIG_FILES) {\n const path = join(cwd, name)\n const content = await readFile(path, 'utf8').catch(() => null)\n if (content)\n return { path, content }\n }\n return null\n}\n\n/**\n * Walk AST node to find all string values inside a `modules` array property.\n * Handles: defineNuxtConfig({ modules: [...] }) and export default { modules: [...] }\n */\nexport function extractModuleStrings(node: any): string[] {\n if (!node || typeof node !== 'object')\n return []\n\n // Found a Property with key \"modules\" and an ArrayExpression value\n if (node.type === 'Property' && !node.computed\n && (node.key?.type === 'Identifier' && node.key.name === 'modules')\n && node.value?.type === 'ArrayExpression') { return node.value.elements.filter((el: any) => el?.type === 'Literal' && typeof el.value === 'string').map((el: any) => el.value as string) }\n\n // Recurse into arrays and object values\n const results: string[] = []\n if (Array.isArray(node)) {\n for (const child of node)\n results.push(...extractModuleStrings(child))\n }\n else {\n for (const key of Object.keys(node)) {\n if (key === 'start' || key === 'end' || key === 'type')\n continue\n const val = node[key]\n if (val && typeof val === 'object')\n results.push(...extractModuleStrings(val))\n }\n }\n return results\n}\n\n/**\n * Detect Nuxt modules from nuxt.config.{ts,js,mjs}\n */\nexport async function detectNuxtModules(cwd: string): Promise<PackageUsage[]> {\n const config = await findNuxtConfig(cwd)\n if (!config)\n return []\n\n const result = parseSync(config.path, config.content)\n const modules = extractModuleStrings(result.program)\n\n // Dedupe and build results\n const seen = new Set<string>()\n const packages: PackageUsage[] = []\n\n for (const mod of modules) {\n if (!seen.has(mod)) {\n seen.add(mod)\n packages.push({ name: mod, count: 0, source: 'preset' })\n }\n }\n\n // Add core ecosystem packages\n for (const pkg of NUXT_ECOSYSTEM) {\n if (!seen.has(pkg)) {\n seen.add(pkg)\n packages.push({ name: pkg, count: 0, source: 'preset' })\n }\n }\n\n return packages\n}\n\n/**\n * Run all preset detectors and merge results\n */\nexport async function detectPresetPackages(cwd: string): Promise<PackageUsage[]> {\n // Currently only Nuxt, but extensible for other frameworks\n return detectNuxtModules(cwd)\n}\n","/**\n * Detect directly-used npm packages by scanning source files\n * Uses mlly for proper ES module parsing + tinyglobby for file discovery\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { findDynamicImports, findStaticImports } from 'mlly'\nimport { glob } from 'tinyglobby'\nimport { detectPresetPackages } from './detect-presets.ts'\n\nexport interface PackageUsage {\n name: string\n count: number\n source?: 'import' | 'preset'\n}\n\nexport interface DetectResult {\n packages: PackageUsage[]\n error?: string\n}\n\nconst PATTERNS = ['**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}']\nconst IGNORE = ['**/node_modules/**', '**/dist/**', '**/.nuxt/**', '**/.output/**', '**/coverage/**']\n\nfunction addPackage(counts: Map<string, number>, specifier: string | undefined) {\n if (!specifier || specifier.startsWith('.') || specifier.startsWith('/'))\n return\n\n // Extract package name (handle subpaths like 'pkg/subpath')\n const name = specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0]!\n\n if (!isNodeBuiltin(name)) {\n counts.set(name, (counts.get(name) || 0) + 1)\n }\n}\n\n/**\n * Scan source files to detect all directly-imported npm packages\n * Async with gitignore support for proper spinner animation\n */\nexport async function detectImportedPackages(cwd: string = process.cwd()): Promise<DetectResult> {\n try {\n const counts = new Map<string, number>()\n\n const files = await glob(PATTERNS, {\n cwd,\n ignore: IGNORE,\n absolute: true,\n expandDirectories: false,\n })\n\n await Promise.all(files.map(async (file) => {\n const content = await readFile(file, 'utf8')\n\n // Static: import x from 'pkg'\n for (const imp of findStaticImports(content)) {\n addPackage(counts, imp.specifier)\n }\n\n // Dynamic: import('pkg') - expression is the string literal\n for (const imp of findDynamicImports(content)) {\n // expression includes quotes, extract string value\n const match = imp.expression.match(/^['\"]([^'\"]+)['\"]$/)\n if (match)\n addPackage(counts, match[1]!)\n }\n }))\n\n // Sort by usage count (descending), then alphabetically\n const packages: PackageUsage[] = Array.from(counts.entries(), ([name, count]) => ({ name, count, source: 'import' as const }))\n .sort((a, b) => b.count - a.count || a.name.localeCompare(b.name))\n\n // Merge preset-detected packages (imports take priority)\n const presets = await detectPresetPackages(cwd)\n const importNames = new Set(packages.map(p => p.name))\n for (const preset of presets) {\n if (!importNames.has(preset.name))\n packages.push(preset)\n }\n\n return { packages }\n }\n catch (err) {\n return { packages: [], error: String(err) }\n }\n}\n\nconst NODE_BUILTINS = new Set([\n 'assert',\n 'async_hooks',\n 'buffer',\n 'child_process',\n 'cluster',\n 'console',\n 'constants',\n 'crypto',\n 'dgram',\n 'diagnostics_channel',\n 'dns',\n 'domain',\n 'events',\n 'fs',\n 'http',\n 'http2',\n 'https',\n 'inspector',\n 'module',\n 'net',\n 'os',\n 'path',\n 'perf_hooks',\n 'process',\n 'punycode',\n 'querystring',\n 'readline',\n 'repl',\n 'sea',\n 'sqlite',\n 'stream',\n 'string_decoder',\n 'sys',\n 'test',\n 'timers',\n 'tls',\n 'trace_events',\n 'tty',\n 'url',\n 'util',\n 'v8',\n 'vm',\n 'wasi',\n 'worker_threads',\n 'zlib',\n])\n\nfunction isNodeBuiltin(pkg: string): boolean {\n const base = pkg.startsWith('node:') ? pkg.slice(5) : pkg\n return NODE_BUILTINS.has(base.split('/')[0]!)\n}\n","import type { SkillSection } from '../prompts/index.ts'\nimport type { OptimizeModel } from './types.ts'\nimport { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { LLM_CACHE_DIR } from '../../core/paths.ts'\n\nconst DEFAULT_MAX_AGE = 7 * 24 * 60 * 60 * 1000\n\n/** Strip absolute paths from prompt so the hash is project-independent */\nfunction normalizePromptForHash(prompt: string): string {\n return prompt.replace(/\\/[^\\s`]*\\.(?:claude|codex|gemini)\\/skills\\/[^\\s/`]+/g, '<SKILL_DIR>')\n}\n\nfunction hashPrompt(prompt: string, model: OptimizeModel, section: SkillSection): string {\n return createHash('sha256').update(`exec:${model}:${section}:${normalizePromptForHash(prompt)}`).digest('hex').slice(0, 16)\n}\n\nexport function getCached(prompt: string, model: OptimizeModel, section: SkillSection, maxAge = DEFAULT_MAX_AGE): string | null {\n const path = join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`)\n if (!existsSync(path))\n return null\n try {\n const { text, timestamp } = JSON.parse(readFileSync(path, 'utf-8'))\n return Date.now() - timestamp > maxAge ? null : text\n }\n catch { return null }\n}\n\nexport function setCache(prompt: string, model: OptimizeModel, section: SkillSection, text: string): void {\n mkdirSync(LLM_CACHE_DIR, { recursive: true, mode: 0o700 })\n writeFileSync(\n join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`),\n JSON.stringify({ text, model, section, timestamp: Date.now() }),\n { mode: 0o600 },\n )\n}\n","/**\n * Section runner — shared seam for \"run a model and turn output into a SectionResult\".\n *\n * Both the spawn-based CLI path (claude/gemini/codex) and the in-process pi-ai path\n * compose three steps: prepareSection → run model → finalizeSection. The model run\n * itself differs (process vs API call); everything around it is shared here.\n */\n\nimport type { SkillSection } from '../prompts/index.ts'\nimport type { CliAdapter, SectionResult, StreamProgress, ValidationWarning } from './types.ts'\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { isWindows } from 'std-env'\nimport { getSectionValidator, SECTION_OUTPUT_FILES } from '../prompts/index.ts'\nimport { cleanSectionOutput } from './clean-output.ts'\n\n/**\n * Strategy for running one section through a model. Two real adapters today:\n * `cliExecutor` (subprocess via `spawnCliAndStream`) and `piAiExecutor`\n * (in-process agent loop via `optimizeSectionPiAi`). The lifecycle around\n * `run` (prepareSection → run → finalizeSection) is identical for both.\n */\nexport interface SectionExecutor {\n /** When true, finalizeSection runs the prompt-injection cleanup pass. */\n cliCleanup: boolean\n run: (opts: {\n section: SkillSection\n prompt: string\n skillDir: string\n skilldDir: string\n timeout: number\n debug?: boolean\n onProgress?: (progress: StreamProgress) => void\n }) => Promise<RawRunOutput>\n}\n\n/** What a model run produces, before file/cleanup/validation. */\nexport interface RawRunOutput {\n /** Accumulated text from the run (stdout for CLIs, in-memory for pi-ai). */\n text: string\n /** Content the LLM tried to Write (fallback when host blocks Write tool). */\n writeContent?: string\n usage?: { input: number, output: number }\n cost?: number\n /** Stderr from a process run; undefined for in-memory runs. */\n stderr?: string\n /** Process exit code; undefined or 0 for successful in-memory runs. */\n exitCode?: number\n /** Raw stream-json lines for debug logging; CLI only. */\n rawLines?: string[]\n}\n\n/** Clear stale output and write the prompt file for debugging. */\nexport function prepareSection(opts: {\n section: SkillSection\n prompt: string\n outputPath: string\n skilldDir: string\n}): void {\n if (existsSync(opts.outputPath))\n unlinkSync(opts.outputPath)\n writeFileSync(join(opts.skilldDir, `PROMPT_${opts.section}.md`), opts.prompt)\n}\n\n/**\n * Turn a RawRunOutput into a SectionResult: resolve final text (file > writeContent > stdout),\n * clean, validate, and write debug logs. CLI runs additionally pass `cliCleanup` to enforce\n * prompt-injection defense (delete unexpected files in skilldDir).\n */\nexport function finalizeSection(opts: {\n section: SkillSection\n raw: RawRunOutput\n outputFile: string\n outputPath: string\n skilldDir: string\n debug: boolean\n /** When set, runs the prompt-injection file cleanup pass. CLI-only. */\n cliCleanup?: { preExistingFiles: Set<string> }\n}): SectionResult {\n const { section, raw, outputFile, outputPath, skilldDir, debug, cliCleanup } = opts\n\n if (cliCleanup) {\n for (const entry of readdirSync(skilldDir)) {\n if (entry === outputFile || cliCleanup.preExistingFiles.has(entry))\n continue\n if (Object.values(SECTION_OUTPUT_FILES).includes(entry))\n continue\n if (entry.startsWith('PROMPT_') || entry === 'logs')\n continue\n try {\n unlinkSync(join(skilldDir, entry))\n }\n catch {}\n }\n }\n\n const logsDir = join(skilldDir, 'logs')\n const logName = section.toUpperCase().replace(/-/g, '_')\n\n const fileText = existsSync(outputPath) ? readFileSync(outputPath, 'utf-8') : ''\n const text = (fileText || raw.writeContent || raw.text).trim()\n\n const stderr = raw.stderr ?? ''\n const code = raw.exitCode ?? 0\n if (debug || (stderr && (!text || code !== 0))) {\n mkdirSync(logsDir, { recursive: true })\n if (stderr)\n writeFileSync(join(logsDir, `${logName}.stderr.log`), stderr)\n }\n if (debug) {\n mkdirSync(logsDir, { recursive: true })\n if (raw.rawLines?.length)\n writeFileSync(join(logsDir, `${logName}.jsonl`), raw.rawLines.join('\\n'))\n if (text)\n writeFileSync(join(logsDir, `${logName}.md`), text)\n }\n\n if (!text && code !== 0) {\n return { section, content: '', wasOptimized: false, error: stderr.trim() || `CLI exited with code ${code}` }\n }\n\n const content = text ? cleanSectionOutput(text) : ''\n if (content)\n writeFileSync(outputPath, content)\n\n const validator = getSectionValidator(section)\n const rawWarnings = content && validator ? validator(content) : []\n const warnings: ValidationWarning[] = rawWarnings.map(w => ({ section, warning: w.warning }))\n\n return {\n section,\n content,\n wasOptimized: !!content,\n warnings: warnings.length ? warnings : undefined,\n usage: raw.usage,\n cost: raw.cost,\n }\n}\n\n/**\n * Spawn a CLI process, stream stream-json from stdout, parse via the adapter, and resolve\n * with raw run output. The stdin prompt, env, cwd, timeout, and event dispatch all live here;\n * adapters only declare argv shape and event parsing.\n */\nexport function spawnCliAndStream(opts: {\n adapter: CliAdapter\n cliModel: string\n prompt: string\n skillDir: string\n skilldDir: string\n symlinkDirs: string[]\n timeout: number\n debug?: boolean\n section: SkillSection\n onProgress?: (progress: StreamProgress) => void\n}): Promise<RawRunOutput> {\n const { adapter, cliModel, prompt, skillDir, skilldDir, symlinkDirs, timeout, debug, section, onProgress } = opts\n const args = adapter.buildArgs(cliModel, skillDir, symlinkDirs)\n const parseEvent = adapter.parseEvent\n\n return new Promise<RawRunOutput>((resolve) => {\n const proc = spawn(adapter.cli, args, {\n cwd: skilldDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout,\n env: { ...process.env, NO_COLOR: '1' },\n shell: isWindows,\n })\n\n let buffer = ''\n let accumulatedText = ''\n let lastWriteContent = ''\n let usage: { input: number, output: number } | undefined\n let cost: number | undefined\n const rawLines: string[] = []\n\n onProgress?.({ chunk: '[starting...]', type: 'reasoning', text: '', reasoning: '', section })\n\n proc.stdin.write(prompt)\n proc.stdin.end()\n\n function applyEvent(evt: ReturnType<typeof parseEvent>): void {\n switch (evt.kind) {\n case 'text':\n if (evt.delta)\n accumulatedText += evt.delta\n if (evt.full !== undefined)\n accumulatedText = evt.full\n break\n case 'tool-call': {\n if (evt.writeContent)\n lastWriteContent = evt.writeContent\n const chunk = evt.hint ? `[${evt.tool}: ${evt.hint}]` : `[${evt.tool}]`\n onProgress?.({ chunk, type: 'reasoning', text: '', reasoning: chunk, section })\n break\n }\n case 'done':\n if (evt.usage)\n usage = evt.usage\n if (evt.cost != null)\n cost = evt.cost\n break\n case 'error':\n case 'noop':\n break\n }\n }\n\n proc.stdout.on('data', (chunk: Buffer) => {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n for (const line of lines) {\n if (!line.trim())\n continue\n if (debug)\n rawLines.push(line)\n applyEvent(parseEvent(line))\n }\n })\n\n let stderr = ''\n proc.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n\n proc.on('close', (code) => {\n if (buffer.trim())\n applyEvent(parseEvent(buffer))\n resolve({\n text: accumulatedText,\n writeContent: lastWriteContent || undefined,\n usage,\n cost,\n stderr,\n exitCode: code ?? 0,\n rawLines: debug ? rawLines : undefined,\n })\n })\n\n proc.on('error', (err) => {\n resolve({ text: '', stderr: err.message, exitCode: 1 })\n })\n })\n}\n","/**\n * Section executors — concrete `SectionExecutor` impls and model→executor selection.\n *\n * Two adapters today:\n * - `cliExecutor` wraps `spawnCliAndStream` (claude/codex/gemini subprocess)\n * - `piAiExecutor` wraps `optimizeSectionPiAi` (in-process agent loop)\n *\n * Adding a new executor (e.g. raw Anthropic SDK) is a new factory plus a branch in\n * `selectExecutor`. The lifecycle in `llm-enhancer.optimizeSection` does not change.\n */\n\nimport type { SectionExecutor } from './runner.ts'\nimport type { OptimizeModel } from './types.ts'\nimport { getSkillReferenceDirs } from '../../cache/index.ts'\nimport { CLI_ADAPTERS, CLI_MODELS } from './index.ts'\nimport { getAvailablePiAiModels, isPiAiModel, optimizeSectionPiAi } from './pi-ai.ts'\nimport { spawnCliAndStream } from './runner.ts'\n\nfunction cliExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n const cliConfig = CLI_MODELS[model]\n if (!cliConfig)\n return { error: `No CLI mapping for model: ${model}` }\n const adapter = CLI_ADAPTERS[cliConfig.cli]\n return {\n cliCleanup: true,\n run: ({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress }) => spawnCliAndStream({\n adapter,\n cliModel: cliConfig.model,\n prompt,\n skillDir,\n skilldDir,\n symlinkDirs: getSkillReferenceDirs(skillDir),\n timeout,\n debug,\n section,\n onProgress,\n }),\n }\n}\n\nfunction piAiExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n const available = new Set(getAvailablePiAiModels().map(m => m.id as OptimizeModel))\n if (!available.has(model))\n return { error: `Pi model unavailable or not authenticated: ${model}` }\n\n return {\n cliCleanup: false,\n run: async ({ section, prompt, skillDir, timeout, onProgress }) => {\n const ac = new AbortController()\n const timer = setTimeout(() => ac.abort(), timeout)\n try {\n const result = await optimizeSectionPiAi({ section, prompt, skillDir, model, onProgress, signal: ac.signal })\n return { text: result.text.trim(), usage: result.usage, cost: result.cost }\n }\n catch (err) {\n return { text: '', stderr: (err as Error).message, exitCode: 1 }\n }\n finally {\n clearTimeout(timer)\n }\n },\n }\n}\n\n/** Resolve `model` to an executor, or an error if the model is unavailable/unmapped. */\nexport function selectExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n return isPiAiModel(model) ? piAiExecutor(model) : cliExecutor(model)\n}\n","/**\n * LLM enhancer — drives CLI adapters (and pi-ai) to generate SKILL.md sections.\n *\n * Owns the section-level lifecycle: cache lookup (references-dir + prompt-hash),\n * parallel spawn with stagger, rate-limit-aware retry, and merge-order assembly.\n * Per-CLI concerns (argv, stream parsing, model registry) live in `./clis/`.\n */\n\nimport type { SectionExecutor } from './clis/runner.ts'\nimport type { OptimizeDocsOptions, OptimizeResult, SectionResult, StreamProgress } from './clis/types.ts'\nimport type { SkillSection } from './prompts/index.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync } from 'node:fs'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { join } from 'pathe'\nimport { createReferenceCache } from '../cache/index.ts'\nimport { skillInternalDir, skillLogDir } from '../core/paths.ts'\nimport { getCached, setCache } from './clis/cli-cache.ts'\nimport { selectExecutor } from './clis/executors.ts'\nimport { finalizeSection, prepareSection } from './clis/runner.ts'\nimport { buildAllSectionPrompts, SECTION_MERGE_ORDER, SECTION_OUTPUT_FILES, wrapSection } from './prompts/index.ts'\n\n// ── Per-section run ──────────────────────────────────────────────────\n\ninterface OptimizeSectionOptions {\n section: SkillSection\n prompt: string\n outputFile: string\n skillDir: string\n executor: SectionExecutor\n onProgress?: (progress: StreamProgress) => void\n timeout: number\n debug?: boolean\n preExistingFiles: Set<string>\n}\n\n/** prepareSection → executor.run → finalizeSection. One linear flow per section. */\nasync function optimizeSection(opts: OptimizeSectionOptions): Promise<SectionResult> {\n const { section, prompt, outputFile, skillDir, executor, onProgress, timeout, debug, preExistingFiles } = opts\n const skilldDir = skillInternalDir(skillDir)\n const outputPath = join(skilldDir, outputFile)\n\n prepareSection({ section, prompt, outputPath, skilldDir })\n\n const raw = await executor.run({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress })\n\n return finalizeSection({\n section,\n raw,\n outputFile,\n outputPath,\n skilldDir,\n debug: !!debug,\n cliCleanup: executor.cliCleanup ? { preExistingFiles } : undefined,\n })\n}\n\n// ── Main orchestrator ────────────────────────────────────────────────\n\nexport async function optimizeDocs(opts: OptimizeDocsOptions): Promise<OptimizeResult> {\n const { packageName, skillDir, model = 'sonnet', version, hasGithub, hasReleases, hasChangelog, docFiles, docsType, hasShippedDocs, onProgress, timeout = 180000, debug, noCache, sections, customPrompt, features, pkgFiles, overheadLines } = opts\n const cache = createReferenceCache(packageName, version)\n\n const selectedSections = sections ?? ['api-changes', 'best-practices'] as SkillSection[]\n\n const sectionPrompts = buildAllSectionPrompts({\n packageName,\n skillDir,\n version,\n hasIssues: hasGithub,\n hasDiscussions: hasGithub,\n hasReleases,\n hasChangelog,\n docFiles,\n docsType,\n hasShippedDocs,\n customPrompt,\n features,\n pkgFiles,\n overheadLines,\n sections: selectedSections,\n })\n\n if (sectionPrompts.size === 0) {\n return { optimized: '', wasOptimized: false, error: 'No valid sections to generate' }\n }\n\n const executorOrError = selectExecutor(model)\n if ('error' in executorOrError)\n return { optimized: '', wasOptimized: false, error: executorOrError.error }\n const executor = executorOrError\n\n // Check per-section cache: references dir first (version-keyed), then LLM cache (prompt-hashed)\n const cachedResults: SectionResult[] = []\n const uncachedSections: Array<{ section: SkillSection, prompt: string }> = []\n\n for (const [section, prompt] of sectionPrompts) {\n if (!noCache) {\n if (version) {\n const outputFile = SECTION_OUTPUT_FILES[section]\n const refCached = cache.readSection(outputFile)\n if (refCached) {\n onProgress?.({ chunk: `[${section}: cached]`, type: 'text', text: refCached, reasoning: '', section })\n cachedResults.push({ section, content: refCached, wasOptimized: true })\n continue\n }\n }\n\n const cached = getCached(prompt, model, section)\n if (cached) {\n onProgress?.({ chunk: `[${section}: cached]`, type: 'text', text: cached, reasoning: '', section })\n cachedResults.push({ section, content: cached, wasOptimized: true })\n continue\n }\n }\n uncachedSections.push({ section, prompt })\n }\n\n const skilldDir = skillInternalDir(skillDir)\n mkdirSync(skilldDir, { recursive: true })\n\n // Pre-flight: warn about broken symlinks in .skilld/ (avoids wasting tokens on missing refs)\n for (const entry of readdirSync(skilldDir)) {\n const entryPath = join(skilldDir, entry)\n try {\n if (lstatSync(entryPath).isSymbolicLink() && !existsSync(entryPath))\n onProgress?.({ chunk: `[warn: broken symlink .skilld/${entry}]`, type: 'reasoning', text: '', reasoning: '' })\n }\n catch {}\n }\n\n const preExistingFiles = new Set(readdirSync(skilldDir))\n\n // Spawn uncached sections with staggered starts to avoid rate-limit collisions\n const STAGGER_MS = 3000\n const spawnResults = uncachedSections.length > 0\n ? await Promise.allSettled(\n uncachedSections.map(({ section, prompt }, i) => {\n const outputFile = SECTION_OUTPUT_FILES[section]\n const run = () => optimizeSection({\n section,\n prompt,\n outputFile,\n skillDir,\n executor,\n onProgress,\n timeout,\n debug,\n preExistingFiles,\n })\n if (i === 0)\n return run()\n return delay(i * STAGGER_MS).then(run)\n }),\n )\n : []\n\n const allResults: SectionResult[] = [...cachedResults]\n let totalUsage: { input: number, output: number } | undefined\n let totalCost = 0\n const retryQueue: Array<{ index: number, section: SkillSection, prompt: string }> = []\n\n for (let i = 0; i < spawnResults.length; i++) {\n const r = spawnResults[i]!\n const { section, prompt } = uncachedSections[i]!\n if (r.status === 'fulfilled' && r.value.wasOptimized) {\n allResults.push(r.value)\n if (r.value.usage) {\n totalUsage = totalUsage ?? { input: 0, output: 0 }\n totalUsage.input += r.value.usage.input\n totalUsage.output += r.value.usage.output\n }\n if (r.value.cost != null)\n totalCost += r.value.cost\n if (!noCache)\n setCache(prompt, model, section, r.value.content)\n }\n else {\n retryQueue.push({ index: i, section, prompt })\n }\n }\n\n // Retry failed sections (sequential, with rate-limit aware backoff)\n for (const { index, section, prompt } of retryQueue) {\n const prevError = getRetryError(spawnResults[index]!)\n const rateLimitDelay = parseRateLimitDelay(prevError)\n\n if (rateLimitDelay != null) {\n const waitSec = Math.max(rateLimitDelay, 5)\n onProgress?.({ chunk: `[${section}] Rate limited, waiting ${waitSec}s...`, type: 'reasoning', text: '', reasoning: '', section })\n await delay(waitSec * 1000)\n }\n else {\n onProgress?.({ chunk: `[${section}: retrying...]`, type: 'reasoning', text: '', reasoning: '', section })\n await delay(STAGGER_MS)\n }\n\n const result = await optimizeSection({\n section,\n prompt,\n outputFile: SECTION_OUTPUT_FILES[section],\n skillDir,\n executor,\n onProgress,\n timeout,\n debug,\n preExistingFiles,\n }).catch((err: Error) => ({ section, content: '', wasOptimized: false, error: err.message }) as SectionResult)\n\n allResults.push(result)\n if (result.wasOptimized && !noCache)\n setCache(prompt, model, section, result.content)\n if (result.usage) {\n totalUsage = totalUsage ?? { input: 0, output: 0 }\n totalUsage.input += result.usage.input\n totalUsage.output += result.usage.output\n }\n if (result.cost != null)\n totalCost += result.cost\n }\n\n // Write successful sections to global references dir for cross-project reuse\n if (version) {\n const sectionFiles = allResults\n .filter(r => r.wasOptimized && r.content)\n .map(r => ({ file: SECTION_OUTPUT_FILES[r.section], content: r.content }))\n if (sectionFiles.length > 0) {\n cache.writeSections(sectionFiles)\n }\n }\n\n // Merge results in SECTION_MERGE_ORDER, wrapped with comment markers\n const mergedParts: string[] = []\n for (const section of SECTION_MERGE_ORDER) {\n const result = allResults.find(r => r.section === section)\n if (result?.wasOptimized && result.content) {\n mergedParts.push(wrapSection(section, result.content))\n }\n }\n\n const optimized = mergedParts.join('\\n\\n')\n const wasOptimized = mergedParts.length > 0\n\n const usageResult = totalUsage\n ? { inputTokens: totalUsage.input, outputTokens: totalUsage.output, totalTokens: totalUsage.input + totalUsage.output }\n : undefined\n\n const errors = allResults.filter(r => r.error).map(r => `${r.section}: ${r.error}`)\n const warnings = allResults.flatMap(r => r.warnings ?? []).map(w => `${w.section}: ${w.warning}`)\n\n const debugLogsDir = debug && uncachedSections.length > 0\n ? skillLogDir(skillDir)\n : undefined\n\n return {\n optimized,\n wasOptimized,\n error: errors.length > 0 ? errors.join('; ') : undefined,\n warnings: warnings.length > 0 ? warnings : undefined,\n finishReason: wasOptimized ? 'stop' : 'error',\n usage: usageResult,\n cost: totalCost || undefined,\n debugLogsDir,\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction isRateLimitError(error: string | undefined): boolean {\n if (!error)\n return false\n return /\\b429\\b/.test(error)\n || /rate.?limit/i.test(error)\n || /exhausted.*capacity/i.test(error)\n || /quota.*reset/i.test(error)\n}\n\nfunction parseRateLimitDelay(error: string | undefined): number | undefined {\n if (!error || !isRateLimitError(error))\n return undefined\n const match = error.match(/reset\\s+after\\s+(\\d+)s/i)\n return match ? Number(match[1]) : 10\n}\n\nfunction getRetryError(result: PromiseSettledResult<SectionResult>): string | undefined {\n if (result.status === 'rejected')\n return String(result.reason)\n return result.value.error\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent.mjs","names":["STATIC_REGEX_1","STATIC_REGEX_2","STATIC_REGEX_3","resolve","STATIC_REGEX_1","STATIC_REGEX_2","buildArgs","parseEvent","adapter","STATIC_REGEX_1","buildArgs","parseEvent","adapter","getEnvApiKey","STATIC_REGEX_1","STATIC_REGEX_2","STATIC_REGEX_3","STATIC_REGEX_5","resolve","STATIC_REGEX_1","STATIC_REGEX_2","STATIC_REGEX_5","STATIC_REGEX_1","STATIC_REGEX_2","STATIC_REGEX_3","claudeAdapter","geminiAdapter","codexAdapter","agents","delay"],"sources":["../../src/agent/clis/model-registry.ts","../../src/agent/clis/types.ts","../../src/agent/clis/claude.ts","../../src/agent/clis/codex.ts","../../src/agent/clis/gemini.ts","../../src/agent/clis/pi-ai-auth.ts","../../src/agent/clis/pi-ai-models.ts","../../src/agent/clis/pi-ai-tools.ts","../../src/agent/clis/pi-ai-runner.ts","../../src/agent/clis/clean-output.ts","../../src/agent/clis/cli-progress.ts","../../src/agent/clis/index.ts","../../src/agent/detect-presets.ts","../../src/agent/detect-imports.ts","../../src/agent/clis/cli-cache.ts","../../src/agent/clis/runner.ts","../../src/agent/clis/executors.ts","../../src/agent/llm-enhancer.ts"],"sourcesContent":["/**\n * Model registry: sources display names from @earendil-works/pi-ai's auto-generated\n * model list, so CLI adapters don't have to hand-maintain \"Opus 4.6\" / \"GPT-5.3\" labels.\n *\n * Each adapter declares the CLI flag value it passes (e.g. `opus`, `gpt-5.3-codex`)\n * plus an id pattern; we resolve the latest matching pi-ai entry for the human label.\n */\n\nimport type { KnownProvider, Model } from '@earendil-works/pi-ai'\nimport type { CliModelEntry } from './types.ts'\nimport { getModels } from '@earendil-works/pi-ai'\n\nconst STATIC_REGEX_1 = /-\\d{8}$/\nconst STATIC_REGEX_2 = /-\\d{4}-\\d{2}-\\d{2}$/\nconst STATIC_REGEX_3 = /-preview/\n\n/** Strip dated aliases (claude-opus-4-5-20251101) and preview tags. */\nfunction isStableId(id: string): boolean {\n if (STATIC_REGEX_1.test(id))\n return false\n if (STATIC_REGEX_2.test(id))\n return false\n if (STATIC_REGEX_3.test(id))\n return false\n return true\n}\n\n/**\n * Numeric version comparator on the trailing version chunks of an id\n * (e.g. claude-opus-4-7 > claude-opus-4-6, gpt-5.3 > gpt-5.2).\n */\nfunction compareVersions(a: string, b: string): number {\n const versionOf = (id: string): number[] => {\n const nums = id.match(/\\d+(?:\\.\\d+)?/g) ?? []\n return nums.flatMap(n => n.split('.').map(Number))\n }\n const av = versionOf(a)\n const bv = versionOf(b)\n for (let i = 0; i < Math.max(av.length, bv.length); i++) {\n const x = av[i] ?? 0\n const y = bv[i] ?? 0\n if (x !== y)\n return y - x\n }\n return 0\n}\n\ninterface ResolveOpts {\n provider: KnownProvider\n /** Prefix the id must start with (e.g. `claude-opus-`, `gpt-5.`, `gemini-`). */\n prefix: string\n /** Optional substring filter (e.g. `codex`, `flash`). */\n contains?: string\n /** Skip ids containing any of these substrings. */\n exclude?: string[]\n}\n\nfunction resolve(opts: ResolveOpts): Model<any> | undefined {\n const { provider, prefix, contains, exclude } = opts\n const matches = getModels(provider)\n .filter(m => isStableId(m.id))\n .filter(m => m.id.startsWith(prefix))\n .filter(m => !contains || m.id.includes(contains))\n .filter(m => !exclude?.some(e => m.id.includes(e)))\n .sort((a, b) => compareVersions(a.id, b.id))\n return matches[0]\n}\n\n/**\n * Build a CliModelEntry by looking up the latest matching pi-ai model and using its\n * display name. `model` is the literal value passed to the CLI (alias or id).\n */\nexport function buildModelEntry(opts: ResolveOpts & {\n /** Value passed to the CLI's --model flag. Defaults to the resolved pi-ai id. */\n model?: string\n /** Override for the display name. Defaults to pi-ai's `name`. */\n name?: string\n /** Post-process pi-ai's name (e.g. strip \"Claude \" prefix). */\n nameTransform?: (name: string) => string\n hint: string\n recommended?: boolean\n}): CliModelEntry {\n const found = resolve(opts)\n const piName = found?.name\n const transformed = piName && opts.nameTransform ? opts.nameTransform(piName) : piName\n const name = opts.name ?? transformed ?? opts.model ?? opts.prefix\n const model = opts.model ?? found?.id ?? opts.prefix\n return { model, name, hint: opts.hint, recommended: opts.recommended }\n}\n\n/** Build a Record<id, CliModelEntry> from a list of entry specs, keyed by their `model` field. */\nexport function buildModels(entries: Array<Parameters<typeof buildModelEntry>[0]>): Record<string, CliModelEntry> {\n return Object.fromEntries(entries.map((e) => {\n const entry = buildModelEntry(e)\n return [entry.model, entry]\n }))\n}\n","import type { FeaturesConfig } from '../../core/config.ts'\nimport type { CustomPrompt, SkillSection } from '../prompts/index.ts'\nimport type { AgentType } from '../types.ts'\n\n/** Normalized event emitted by every CliAdapter from a single stream-json line. */\nexport type CliEvent\n = | { kind: 'noop' }\n /** Assistant text — delta (partial streaming) or full (turn-level). */\n | { kind: 'text', delta?: string, full?: string }\n /**\n * Tool invocation. `tool` is the adapter's raw name (e.g. 'Read', 'read_file'); look it up in\n * TOOL_NAMES for display verb + canonical role. `writeContent` carries inline file content\n * the LLM tried to write (fallback path when the host denies the Write tool).\n */\n | { kind: 'tool-call', tool: string, hint?: string, writeContent?: string }\n /** Stream finished cleanly. */\n | { kind: 'done', usage?: { input: number, output: number }, cost?: number, turns?: number }\n /** Stream finished with an error. */\n | { kind: 'error', message?: string }\n\n/**\n * Canonical tool registry — one row per raw name across adapters. Drives display (verb) and\n * semantic role (canonical) without per-CLI switching in the dispatcher.\n */\nexport const TOOL_NAMES: Record<string, { canonical: 'read' | 'search' | 'write' | 'list' | 'shell', verb: string }> = {\n // Claude Code\n Read: { canonical: 'read', verb: 'Reading' },\n Glob: { canonical: 'search', verb: 'Searching' },\n Grep: { canonical: 'search', verb: 'Searching' },\n Write: { canonical: 'write', verb: 'Writing' },\n Bash: { canonical: 'shell', verb: 'Running' },\n // Gemini\n read_file: { canonical: 'read', verb: 'Reading' },\n glob_tool: { canonical: 'search', verb: 'Searching' },\n write_file: { canonical: 'write', verb: 'Writing' },\n list_directory: { canonical: 'list', verb: 'Listing' },\n search_file_content: { canonical: 'search', verb: 'Searching' },\n run_shell_command: { canonical: 'shell', verb: 'Running' },\n}\n\n/**\n * Common keys adapters poke at to extract a useful hint (path, query, command) from a tool's\n * argument object — claude, gemini, codex all use overlapping shapes.\n */\nexport function extractToolHint(input: Record<string, unknown> | undefined | null): string | undefined {\n if (!input)\n return undefined\n for (const k of ['file_path', 'path', 'dir_path', 'pattern', 'query', 'command'] as const) {\n const v = input[k]\n if (typeof v === 'string' && v)\n return v\n }\n return undefined\n}\n\nexport type OptimizeModel\n = | 'opus'\n | 'sonnet'\n | 'haiku'\n | 'gemini-3.1-pro'\n | 'gemini-3-flash'\n | 'gpt-5.3-codex'\n | 'gpt-5.3-codex-spark'\n | 'gpt-5.2-codex'\n // pi-ai direct API models — dynamic from pi-ai's model registry\n | `pi:${string}`\n\nexport interface ModelInfo {\n id: OptimizeModel\n name: string\n hint: string\n recommended?: boolean\n agentId: string\n agentName: string\n /** Grouping key for provider selection (e.g. 'claude-code', 'pi:anthropic') */\n provider: string\n /** Human-readable provider name */\n providerName: string\n /** Normalized vendor name for UI grouping (e.g. 'Anthropic') — merges CLI and API entries */\n vendorGroup: string\n}\n\nexport interface StreamProgress {\n chunk: string\n type: 'reasoning' | 'text'\n text: string\n reasoning: string\n section?: SkillSection\n}\n\nexport interface OptimizeDocsOptions {\n packageName: string\n skillDir: string\n model?: OptimizeModel\n version?: string\n hasGithub?: boolean\n hasReleases?: boolean\n hasChangelog?: string | false\n docFiles?: string[]\n docsType?: 'llms.txt' | 'readme' | 'docs'\n hasShippedDocs?: boolean\n onProgress?: (progress: StreamProgress) => void\n timeout?: number\n verbose?: boolean\n debug?: boolean\n noCache?: boolean\n /** Which sections to generate */\n sections?: SkillSection[]\n /** Custom instructions from the user */\n customPrompt?: CustomPrompt\n /** Resolved feature flags */\n features?: FeaturesConfig\n /** Key files from the package (e.g., dist/pkg.d.ts) */\n pkgFiles?: string[]\n /** Lines consumed by SKILL.md overhead (frontmatter + header + search + footer) */\n overheadLines?: number\n}\n\nexport interface OptimizeResult {\n optimized: string\n wasOptimized: boolean\n error?: string\n warnings?: string[]\n reasoning?: string\n finishReason?: string\n usage?: { inputTokens: number, outputTokens: number, totalTokens: number }\n cost?: number\n debugLogsDir?: string\n}\n\nexport interface SectionResult {\n section: SkillSection\n content: string\n wasOptimized: boolean\n error?: string\n warnings?: ValidationWarning[]\n usage?: { input: number, output: number }\n cost?: number\n}\n\nexport interface ValidationWarning {\n section: string\n warning: string\n}\n\n/** Per-model config without redundant cli/agentId (those come from the CLI file) */\nexport interface CliModelEntry {\n /** Model flag passed to the CLI */\n model: string\n /** Human-readable model name */\n name: string\n /** Short description hint */\n hint: string\n /** Whether this is the recommended model for this CLI */\n recommended?: boolean\n}\n\n/** Full model config (assembled from CLI files + their models) */\nexport interface CliModelConfig extends CliModelEntry {\n cli: CliName\n agentId: AgentType\n}\n\nexport type CliName = 'claude' | 'gemini' | 'codex'\n\n/**\n * Per-CLI integration. Adding a new LLM CLI is one new file exporting one of these — no edits\n * to the dispatcher, the model table, or the provider name table.\n */\nexport interface CliAdapter {\n cli: CliName\n agentId: AgentType\n /** Human-readable LLM provider name (e.g. 'Anthropic', 'OpenAI'). */\n providerName: string\n /** Models this adapter can target, keyed by OptimizeModel id. */\n models: Record<string, CliModelEntry>\n /** Build argv for spawning the CLI process. */\n buildArgs: (model: string, skillDir: string, symlinkDirs: string[]) => string[]\n /** Parse one stream-json line into a normalized event. */\n parseEvent: (line: string) => CliEvent\n}\n","/**\n * Claude Code CLI — token-level streaming via --include-partial-messages.\n *\n * Write permission: Claude Code has hardcoded .claude/ write protection and --allowedTools glob\n * patterns are broken (github.com/anthropics/claude-code/issues/6881). Instead of fighting the\n * permission system, Write is auto-denied in pipe mode and we capture the content via a\n * tool-call event's writeContent.\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { buildModels } from './model-registry.ts'\nimport { extractToolHint } from './types.ts'\n\nconst STATIC_REGEX_1 = /^Claude\\s+/\nconst STATIC_REGEX_2 = /\\s*\\(latest\\)\\s*$/i\n\nconst stripClaude = (n: string): string => n.replace(STATIC_REGEX_1, '').replace(STATIC_REGEX_2, '')\n\nfunction buildArgs(model: string, skillDir: string, symlinkDirs: string[]): string[] {\n const allowedTools = [\n // Bare tool names — --add-dir already scopes visibility\n 'Read',\n 'Glob',\n 'Grep',\n 'Bash(*skilld search*)',\n 'Bash(*skilld validate*)',\n // Write intentionally omitted — auto-denied in pipe mode, content captured via writeContent\n ].join(' ')\n return [\n '-p',\n '--model',\n model,\n '--output-format',\n 'stream-json',\n '--verbose',\n '--include-partial-messages',\n '--allowedTools',\n allowedTools,\n '--disallowedTools',\n 'WebSearch WebFetch Task',\n '--add-dir',\n skillDir,\n ...symlinkDirs.flatMap(d => ['--add-dir', d]),\n '--no-session-persistence',\n ]\n}\n\n/**\n * Event types this parses:\n * - stream_event/content_block_delta/text_delta → text delta (token streaming)\n * - assistant message with tool_use content → tool-call (with writeContent for Write)\n * - assistant message with text content → text full (non-streaming fallback)\n * - result → done with usage/cost/turns\n */\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'stream_event') {\n const evt = obj.event\n if (evt?.type === 'content_block_delta' && evt.delta?.type === 'text_delta')\n return { kind: 'text', delta: evt.delta.text }\n return { kind: 'noop' }\n }\n\n if (obj.type === 'assistant' && obj.message?.content) {\n const content = obj.message.content as any[]\n\n const tools = content.filter((c: any) => c.type === 'tool_use')\n if (tools.length) {\n const tool = tools.map((t: any) => t.name).join(', ')\n const hint = tools.map((t: any) => extractToolHint(t.input) ?? '').filter(Boolean).join(', ') || undefined\n const writeTool = tools.find((t: any) => t.name === 'Write' && t.input?.content)\n return { kind: 'tool-call', tool, hint, writeContent: writeTool?.input?.content }\n }\n\n const text = content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('')\n if (text)\n return { kind: 'text', full: text }\n }\n\n if (obj.type === 'result') {\n const u = obj.usage\n return {\n kind: 'done',\n usage: u ? { input: u.input_tokens ?? u.inputTokens ?? 0, output: u.output_tokens ?? u.outputTokens ?? 0 } : undefined,\n cost: obj.total_cost_usd,\n turns: obj.num_turns,\n }\n }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'claude',\n agentId: 'claude-code',\n providerName: 'Anthropic',\n models: buildModels([\n { model: 'opus', provider: 'anthropic', prefix: 'claude-opus-', nameTransform: stripClaude, hint: 'Most capable for complex work' },\n { model: 'sonnet', provider: 'anthropic', prefix: 'claude-sonnet-', nameTransform: stripClaude, hint: 'Best for everyday tasks' },\n { model: 'haiku', provider: 'anthropic', prefix: 'claude-haiku-', nameTransform: stripClaude, hint: 'Fastest for quick answers', recommended: true },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * OpenAI Codex CLI — exec subcommand with JSON output. Prompt passed via stdin (`-` sentinel).\n *\n * Event types:\n * - turn.completed → done with usage\n * - item.started command_execution → tool-call (Bash, in progress)\n * - item.completed agent_message → text full\n * - item.completed command_execution → tool-call (with writeContent if redirected to a file)\n * - item.completed file_change → tool-call (apply_patch wrote a file)\n * - turn.failed / error → done (terminal)\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { buildModels } from './model-registry.ts'\n\nconst STATIC_REGEX_1 = /^cat\\s*>|>/\n\nfunction buildArgs(model: string, _skillDir: string, _symlinkDirs: string[]): string[] {\n return [\n 'exec',\n '--json',\n '--ephemeral',\n '--model',\n model,\n // --full-auto = workspace-write sandbox + on-request approval. Writes scoped to CWD\n // (.skilld/, set in spawn), reads unrestricted, network blocked. Shell remains enabled\n // for `skilld` search/validate (Codex has no per-command allowlist).\n // --ephemeral = no session persistence (mirrors Claude's --no-session-persistence).\n '--full-auto',\n '-',\n ]\n}\n\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'item.completed' && obj.item) {\n const item = obj.item\n if (item.type === 'agent_message' && item.text)\n return { kind: 'text', full: item.text }\n if (item.type === 'command_execution' && item.aggregated_output) {\n const cmd = item.command || ''\n const writeContent = (STATIC_REGEX_1.test(cmd)) ? item.aggregated_output : undefined\n return { kind: 'tool-call', tool: 'Bash', hint: `(${item.aggregated_output.length} chars output)`, writeContent }\n }\n if (item.type === 'file_change' && item.changes?.length) {\n const paths = item.changes.map((c: { path: string, kind: string }) => c.path).join(', ')\n return { kind: 'tool-call', tool: 'Write', hint: paths }\n }\n }\n\n if (obj.type === 'item.started' && obj.item?.type === 'command_execution')\n return { kind: 'tool-call', tool: 'Bash', hint: obj.item.command }\n\n if (obj.type === 'turn.completed' && obj.usage) {\n return {\n kind: 'done',\n usage: { input: obj.usage.input_tokens ?? 0, output: obj.usage.output_tokens ?? 0 },\n }\n }\n\n if (obj.type === 'turn.failed' || obj.type === 'error')\n return { kind: 'error', message: obj.message }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'codex',\n agentId: 'codex',\n providerName: 'OpenAI',\n models: buildModels([\n { provider: 'openai', prefix: 'gpt-', contains: 'codex', exclude: ['spark', 'mini', 'max'], hint: 'Latest frontier Codex model' },\n { provider: 'openai', prefix: 'gpt-', contains: 'codex-spark', hint: 'Faster Codex variant', recommended: true },\n { provider: 'openai', prefix: 'gpt-', contains: 'codex-mini', hint: 'Cheapest Codex variant' },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * Gemini CLI — turn-level streaming via -o stream-json.\n * Write scoping: relies on cwd being set to .skilld/ (no native --writeable-dirs).\n */\n\nimport type { CliAdapter, CliEvent } from './types.ts'\nimport { resolveSkilldCommand } from '../../core/skilld-command.ts'\nimport { buildModels } from './model-registry.ts'\nimport { extractToolHint } from './types.ts'\n\nfunction buildArgs(model: string, skillDir: string, symlinkDirs: string[]): string[] {\n return [\n '-o',\n 'stream-json',\n '-m',\n model,\n '--allowed-tools',\n `read_file,write_file,glob_tool,list_directory,search_file_content,run_shell_command(${resolveSkilldCommand()}),run_shell_command(grep),run_shell_command(head)`,\n '--include-directories',\n skillDir,\n ...symlinkDirs.flatMap(d => ['--include-directories', d]),\n ]\n}\n\nfunction parseEvent(line: string): CliEvent {\n try {\n const obj = JSON.parse(line)\n\n if (obj.type === 'message' && obj.role === 'assistant' && obj.content) {\n return obj.delta ? { kind: 'text', delta: obj.content } : { kind: 'text', full: obj.content }\n }\n\n if (obj.type === 'tool_use' || obj.type === 'tool_call') {\n const tool = obj.tool_name || obj.name || obj.tool || 'tool'\n const params = obj.parameters || obj.args || obj.input || {}\n const hint = extractToolHint(params)\n const writeContent = tool === 'write_file' && typeof params.content === 'string' ? params.content : undefined\n return { kind: 'tool-call', tool, hint, writeContent }\n }\n\n if (obj.type === 'result') {\n const s = obj.stats\n return {\n kind: 'done',\n usage: s ? { input: s.input_tokens ?? s.input ?? 0, output: s.output_tokens ?? s.output ?? 0 } : undefined,\n turns: s?.tool_calls,\n }\n }\n }\n catch {}\n return { kind: 'noop' }\n}\n\nexport const adapter: CliAdapter = {\n cli: 'gemini',\n agentId: 'gemini-cli',\n providerName: 'Google',\n models: buildModels([\n { provider: 'google', prefix: 'gemini-', contains: 'pro', exclude: ['flash', 'live', 'gemma'], hint: 'Most capable' },\n { provider: 'google', prefix: 'gemini-', contains: 'flash', exclude: ['lite', 'live', 'preview'], hint: 'Balanced', recommended: true },\n ]),\n buildArgs,\n parseEvent,\n}\n","/**\n * pi-ai auth — OAuth credentials, env API keys, login/logout flows.\n *\n * OAuth providers known to ban accounts for unauthorized usage are blocked.\n * API key access (env vars) remains supported for those providers.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { getEnvApiKey, getProviders } from '@earendil-works/pi-ai'\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from '@earendil-works/pi-ai/oauth'\nimport { join } from 'pathe'\nimport { CACHE_DIR, PI_AI_AUTH_PATH } from '../../core/paths.ts'\n\n/**\n * Consumer-OAuth providers that ban accounts for unauthorized usage.\n * API-key access remains supported for these.\n */\nexport const BLOCKED_OAUTH_PROVIDERS: ReadonlySet<string> = new Set([\n 'google-antigravity',\n 'google-gemini-cli',\n 'github-copilot',\n 'anthropic',\n 'openai-codex',\n])\n\nconst PI_AGENT_AUTH_PATH = join(\n process.env.PI_CODING_AGENT_DIR || join(homedir(), '.pi', 'agent'),\n 'auth.json',\n)\nconst SKILLD_AUTH_PATH = PI_AI_AUTH_PATH\n\n/**\n * Overrides for model-provider → OAuth-provider mapping. Most providers share\n * the same id in both systems (auto-matched); list only divergences.\n */\nconst OAUTH_PROVIDER_OVERRIDES: Record<string, string> = {\n google: 'google-gemini-cli',\n openai: 'openai-codex',\n}\n\ninterface OAuthCredentials {\n type: 'oauth'\n refresh: string\n access: string\n expires: number\n [key: string]: unknown\n}\n\nfunction readAuthFile(path: string): Record<string, OAuthCredentials> {\n if (!existsSync(path))\n return {}\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n }\n catch { return {} }\n}\n\n/** Load auth from pi coding agent first, then skilld's own. pi agent wins on conflict. */\nexport function loadAuth(): Record<string, OAuthCredentials> {\n const piAuth = readAuthFile(PI_AGENT_AUTH_PATH)\n const skilldAuth = readAuthFile(SKILLD_AUTH_PATH)\n return { ...skilldAuth, ...piAuth }\n}\n\nfunction saveAuth(auth: Record<string, OAuthCredentials>): void {\n mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 })\n writeFileSync(SKILLD_AUTH_PATH, JSON.stringify(auth, null, 2), { mode: 0o600 })\n}\n\n/** Resolve model provider id → OAuth provider id (returns null for blocked providers). */\nexport function resolveOAuthProviderId(modelProvider: string): string | null {\n const oauthId = OAUTH_PROVIDER_OVERRIDES[modelProvider] ?? modelProvider\n if (BLOCKED_OAUTH_PROVIDERS.has(oauthId))\n return null\n if (OAUTH_PROVIDER_OVERRIDES[modelProvider])\n return OAUTH_PROVIDER_OVERRIDES[modelProvider]!\n const oauthIds = new Set((getOAuthProviders() as Array<{ id: string }>).map(p => p.id))\n if (oauthIds.has(modelProvider))\n return modelProvider\n return null\n}\n\n/** Resolve API key for a provider — env vars first, then stored OAuth credentials. */\nexport async function resolveApiKey(provider: string): Promise<string | null> {\n const envKey = getEnvApiKey(provider)\n if (envKey)\n return envKey\n\n const oauthProviderId = resolveOAuthProviderId(provider)\n if (!oauthProviderId)\n return null\n\n const auth = loadAuth()\n if (!auth[oauthProviderId])\n return null\n\n const result = await getOAuthApiKey(oauthProviderId, auth)\n if (!result)\n return null\n\n // Refreshed credentials go to skilld's own file only, never leak pi-agent tokens.\n const skilldAuth = readAuthFile(SKILLD_AUTH_PATH)\n skilldAuth[oauthProviderId] = { type: 'oauth', ...result.newCredentials }\n saveAuth(skilldAuth)\n return result.apiKey\n}\n\nexport interface LoginCallbacks {\n onAuth: (url: string, instructions?: string) => void\n onPrompt: (message: string, placeholder?: string) => Promise<string>\n onProgress?: (message: string) => void\n}\n\nexport function getOAuthProviderList(): Array<{ id: string, name: string, loggedIn: boolean }> {\n const auth = loadAuth()\n const providers = getOAuthProviders() as Array<{ id: string, name: string }>\n return providers\n .filter(p => !BLOCKED_OAUTH_PROVIDERS.has(p.id))\n .map(p => ({ id: p.id, name: p.name ?? p.id, loggedIn: !!auth[p.id] }))\n}\n\nexport async function loginOAuthProvider(providerId: string, callbacks: LoginCallbacks): Promise<boolean> {\n const provider = getOAuthProvider(providerId)\n if (!provider)\n return false\n\n const credentials = await provider.login({\n onAuth: (info: any) => callbacks.onAuth(info.url, info.instructions),\n onPrompt: async (prompt: any) => callbacks.onPrompt(prompt.message, prompt.placeholder),\n onProgress: (msg: string) => callbacks.onProgress?.(msg),\n })\n\n const auth = loadAuth()\n auth[providerId] = { type: 'oauth', ...credentials }\n saveAuth(auth)\n return true\n}\n\nexport function logoutOAuthProvider(providerId: string): void {\n const auth = loadAuth()\n delete auth[providerId]\n saveAuth(auth)\n}\n\n/** Re-export for callers that want pi-ai's provider list without importing from pi-ai directly. */\nexport { getEnvApiKey, getProviders }\n","/**\n * pi-ai model identification + dynamic model enumeration.\n *\n * Models are sourced from pi-ai's registry; legacy generations and tiny\n * context windows are filtered out. A \"recommended\" model is auto-picked\n * per provider for ergonomic defaults.\n */\n\nimport { getEnvApiKey, getModels, getProviders } from '@earendil-works/pi-ai'\nimport { loadAuth, resolveOAuthProviderId } from './pi-ai-auth.ts'\n\nexport function isPiAiModel(model: string): boolean {\n return model.startsWith('pi:')\n}\n\n/** Parse a `pi:provider/model-id` string → `{ provider, modelId }`. */\nexport function parsePiAiModelId(model: string): { provider: string, modelId: string } | null {\n if (!model.startsWith('pi:'))\n return null\n const rest = model.slice(3)\n const slashIdx = rest.indexOf('/')\n if (slashIdx === -1)\n return null\n return { provider: rest.slice(0, slashIdx), modelId: rest.slice(slashIdx + 1) }\n}\n\nconst MIN_CONTEXT_WINDOW = 32_000\n\n/** Old generations that clutter the model list. */\nconst LEGACY_MODEL_PATTERNS = [\n // Anthropic: claude 3.x family\n /^claude-3-/,\n /^claude-3\\.5-/,\n /^claude-3\\.7-/,\n // OpenAI: pre-gpt-5\n /^gpt-4(?!\\.\\d)/, // gpt-4, gpt-4-turbo, gpt-4o but not gpt-4.1\n /^o1/,\n /^o3-mini/,\n // Google: old gemini generations + non-text models\n /^gemini-1\\./,\n /^gemini-2\\.0/,\n /^gemini-live-/,\n // Preview snapshots with date suffixes\n /-preview-\\d{2}-\\d{2,4}$/,\n // Dated model snapshots\n /-\\d{8}$/,\n]\n\nfunction isLegacyModel(modelId: string): boolean {\n return LEGACY_MODEL_PATTERNS.some(p => p.test(modelId))\n}\n\n/** Cheapest reliable option per provider, picked for auto-selection. */\nconst RECOMMENDED_MODELS: Record<string, RegExp> = {\n anthropic: /haiku/,\n google: /flash/,\n openai: /gpt-4\\.1-mini/,\n}\n\nexport interface PiAiModelInfo {\n /** Full model ID: `pi:provider/model-id`. */\n id: string\n name: string\n hint: string\n authSource: 'env' | 'oauth' | 'none'\n recommended: boolean\n}\n\nexport function getAvailablePiAiModels(): PiAiModelInfo[] {\n const providers: string[] = getProviders()\n const auth = loadAuth()\n const available: PiAiModelInfo[] = []\n const recommendedPicked = new Set<string>()\n\n for (const provider of providers) {\n let authSource: 'env' | 'oauth' | 'none' = 'none'\n if (getEnvApiKey(provider)) {\n authSource = 'env'\n }\n else {\n const oauthId = resolveOAuthProviderId(provider)\n if (oauthId && auth[oauthId])\n authSource = 'oauth'\n }\n\n if (authSource === 'none')\n continue\n\n const models: any[] = getModels(provider as any)\n const recPattern = RECOMMENDED_MODELS[provider]\n let recModelId: string | null = null\n if (recPattern) {\n for (const model of models) {\n if (!isLegacyModel(model.id) && recPattern.test(model.id)) {\n recModelId = model.id\n break\n }\n }\n }\n\n for (const model of models) {\n if (model.contextWindow && model.contextWindow < MIN_CONTEXT_WINDOW)\n continue\n if (isLegacyModel(model.id))\n continue\n\n const id = `pi:${provider}/${model.id}`\n const ctx = model.contextWindow ? ` · ${Math.round(model.contextWindow / 1000)}k ctx` : ''\n const cost = model.cost?.input ? ` · $${model.cost.input}/Mtok` : ''\n const isRecommended = model.id === recModelId && !recommendedPicked.has(provider)\n\n if (isRecommended)\n recommendedPicked.add(provider)\n\n available.push({\n id,\n name: model.name || model.id,\n hint: `${authSource === 'oauth' ? 'OAuth' : 'API key'}${ctx}${cost}`,\n authSource,\n recommended: isRecommended,\n })\n }\n }\n\n return available\n}\n","/**\n * Sandboxed tool execution for the pi-ai agentic loop.\n *\n * The model can Read/Glob/Write within `.skilld/` and run a tightly\n * allowlisted set of shell commands. All file operations resolve through\n * `resolveSandboxedPath` which blocks traversal outside `skilldDir`.\n */\n\nimport type { ToolCall } from '@earendil-works/pi-ai'\nimport { execFileSync } from 'node:child_process'\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { join } from 'pathe'\nimport { Type } from 'typebox'\nimport { TRAILING_SLASH_RE } from '../../core/regex.ts'\nimport { sanitizeMarkdown } from '../../core/sanitize.ts'\n\nconst STATIC_REGEX_1 = /^\\.\\/\\.skilld\\//\nconst STATIC_REGEX_2 = /^\\.skilld\\//\nconst STATIC_REGEX_3 = /^\\.\\//\nconst STATIC_REGEX_5 = /\\s+/\n\nexport const TOOLS = [\n {\n name: 'Read',\n description: 'Read a file. Path is relative to the working directory (e.g. \"./.skilld/docs/api.md\").',\n parameters: Type.Object({ path: Type.String({ description: 'File path to read' }) }),\n },\n {\n name: 'Glob',\n description: 'List files matching a glob pattern (e.g. \"./.skilld/docs/*.md\"). Returns newline-separated paths.',\n parameters: Type.Object({\n pattern: Type.String({ description: 'Glob pattern' }),\n no_ignore: Type.Optional(Type.Boolean({ description: 'Include gitignored files' })),\n }),\n },\n {\n name: 'Write',\n description: 'Write content to a file.',\n parameters: Type.Object({\n path: Type.String({ description: 'File path to write' }),\n content: Type.String({ description: 'File content' }),\n }),\n },\n {\n name: 'Bash',\n description: 'Run a shell command. Use for `skilld search`, `skilld validate`, etc.',\n parameters: Type.Object({ command: Type.String({ description: 'Shell command to run' }) }),\n },\n]\n\nexport const MAX_TOOL_TURNS = 30\n\nconst SAFE_COMMANDS = new Set(['skilld', 'ls', 'cat', 'find'])\nconst SHELL_META_RE = /[;&|`$()<>]/\n\n/** Resolve a path safely within skilldDir, blocking traversal. */\nfunction resolveSandboxedPath(p: string, skilldDir: string): string {\n const cleaned = String(p).replace(STATIC_REGEX_1, './').replace(STATIC_REGEX_2, './').replace(STATIC_REGEX_3, '')\n const resolved = resolve(skilldDir, cleaned)\n if (!resolved.startsWith(`${skilldDir}/`) && resolved !== skilldDir)\n throw new Error(`Path traversal blocked: ${p}`)\n return resolved\n}\n\n/** Match a file path against a glob pattern using simple segment matching (no regex from user input). */\nfunction globMatch(filePath: string, pattern: string): boolean {\n const segments = pattern.split('**')\n if (segments.length === 1) {\n const parts = pattern.split('*')\n if (parts.length === 1)\n return filePath === pattern\n let pos = 0\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n if (!part)\n continue\n const idx = filePath.indexOf(part, pos)\n if (idx === -1)\n return false\n if (i === 0 && idx !== 0)\n return false\n pos = idx + part.length\n }\n if (parts.at(-1) !== '')\n return pos === filePath.length\n return true\n }\n let remaining = filePath\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!\n if (!seg)\n continue\n const segParts = seg.split('*')\n let pos = 0\n let matched = false\n for (let attempt = remaining.indexOf(segParts[0]!, 0); attempt !== -1; attempt = remaining.indexOf(segParts[0]!, attempt + 1)) {\n pos = attempt\n matched = true\n for (const sp of segParts) {\n if (!sp)\n continue\n const idx = remaining.indexOf(sp, pos)\n if (idx === -1) {\n matched = false\n break\n }\n pos = idx + sp.length\n }\n if (matched)\n break\n }\n if (!matched)\n return false\n remaining = remaining.slice(pos)\n }\n return true\n}\n\n/** Execute a tool call against the .skilld/ directory. */\nexport function executeTool(toolCall: ToolCall, skilldDir: string): string {\n const args = toolCall.arguments as Record<string, unknown>\n\n switch (toolCall.name) {\n case 'Read': {\n const filePath = resolveSandboxedPath(args.path as string, skilldDir)\n if (!existsSync(filePath))\n return `Error: file not found: ${args.path}`\n return sanitizeMarkdown(readFileSync(filePath, 'utf-8'))\n }\n case 'Glob': {\n const pattern = String(args.pattern).replace(STATIC_REGEX_1, './').replace(STATIC_REGEX_2, './').replace(STATIC_REGEX_3, '')\n const results: string[] = []\n const walkDir = (dir: string, prefix: string) => {\n if (!existsSync(dir))\n return\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n if (entry.isDirectory())\n walkDir(join(dir, entry.name), relPath)\n else results.push(`./.skilld/${relPath}`)\n }\n }\n const baseDir = pattern.split('*')[0]?.replace(TRAILING_SLASH_RE, '') ?? ''\n walkDir(join(skilldDir, baseDir), baseDir)\n const matched = results.filter(r => globMatch(r.replace(STATIC_REGEX_1, ''), pattern))\n return matched.length > 0 ? matched.join('\\n') : `No files matching: ${args.pattern}`\n }\n case 'Write': {\n const filePath = resolveSandboxedPath(args.path as string, skilldDir)\n writeFileSync(filePath, sanitizeMarkdown(String(args.content)))\n return 'File written successfully.'\n }\n case 'Bash': {\n const cmd = String(args.command).trim()\n const parts = cmd.split(STATIC_REGEX_5)\n const bin = parts[0] ?? ''\n if (!SAFE_COMMANDS.has(bin) || SHELL_META_RE.test(cmd))\n return `Error: command not allowed. Only skilld, ls, cat, find commands are permitted.`\n try {\n return execFileSync(bin, parts.slice(1), { cwd: skilldDir, timeout: 15_000, encoding: 'utf-8', maxBuffer: 512 * 1024 }).trim()\n }\n catch (err) {\n return `Error: ${(err as Error).message}`\n }\n }\n default:\n return `Unknown tool: ${toolCall.name}`\n }\n}\n","/**\n * pi-ai section runner — drives the agentic tool-use loop for a single SKILL.md\n * section. Streams reasoning + text to onProgress; tools are sandboxed to .skilld/.\n */\n\nimport type { AssistantMessage, Message, ToolCall } from '@earendil-works/pi-ai'\nimport type { SkillSection } from '../prompts/index.ts'\nimport type { StreamProgress } from './types.ts'\nimport { getModel, streamSimple } from '@earendil-works/pi-ai'\nimport { skillInternalDir } from '../../core/paths.ts'\nimport { resolveApiKey } from './pi-ai-auth.ts'\nimport { parsePiAiModelId } from './pi-ai-models.ts'\nimport { executeTool, MAX_TOOL_TURNS, TOOLS } from './pi-ai-tools.ts'\n\nexport interface PiAiSectionOptions {\n section: SkillSection\n prompt: string\n skillDir: string\n model: string\n onProgress?: (progress: StreamProgress) => void\n signal?: AbortSignal\n}\n\nexport interface PiAiSectionResult {\n text: string\n /** The raw prompt sent to the model. */\n fullPrompt: string\n usage?: { input: number, output: number }\n cost?: number\n}\n\nconst SYSTEM_PROMPT = 'You are a technical documentation expert generating SKILL.md sections for AI agent skills. Follow the format instructions exactly. Use the provided tools to explore reference files in ./.skilld/ before writing your output.'\n\n/** Optimize a single section using pi-ai agentic API with tool use. */\nexport async function optimizeSectionPiAi(opts: PiAiSectionOptions): Promise<PiAiSectionResult> {\n const parsed = parsePiAiModelId(opts.model)\n if (!parsed)\n throw new Error(`Invalid pi-ai model ID: ${opts.model}. Expected format: pi:provider/model-id`)\n\n const model = getModel(parsed.provider as any, parsed.modelId as any)\n const apiKey = await resolveApiKey(parsed.provider)\n const skilldDir = skillInternalDir(opts.skillDir)\n\n const fullPrompt = opts.prompt\n\n opts.onProgress?.({ chunk: '[starting...]', type: 'reasoning', text: '', reasoning: '', section: opts.section })\n\n const messages: Message[] = [{\n role: 'user' as const,\n content: [{ type: 'text' as const, text: fullPrompt }],\n timestamp: Date.now(),\n }]\n\n let text = ''\n let completed = false\n let totalUsage: { input: number, output: number } | undefined\n let totalCost: number | undefined\n let lastWriteContent = ''\n\n for (let turn = 0; turn < MAX_TOOL_TURNS; turn++) {\n if (opts.signal?.aborted)\n throw new Error('pi-ai request timed out')\n\n const eventStream = streamSimple(model, {\n systemPrompt: SYSTEM_PROMPT,\n messages,\n tools: TOOLS,\n }, {\n reasoning: turn === 0 ? 'medium' : undefined,\n maxTokens: 16_384,\n ...(apiKey ? { apiKey } : {}),\n })\n\n let assistantMessage: AssistantMessage | undefined\n let turnText = ''\n\n for await (const event of eventStream) {\n if (opts.signal?.aborted)\n throw new Error('pi-ai request timed out')\n\n switch (event.type) {\n case 'text_delta':\n turnText += event.delta\n opts.onProgress?.({ chunk: event.delta, type: 'text', text: turnText, reasoning: '', section: opts.section })\n break\n case 'toolcall_end': {\n const tc = event.toolCall\n const hint = tc.name === 'Read' || tc.name === 'Write'\n ? `[${tc.name}: ${tc.arguments.path}]`\n : tc.name === 'Bash'\n ? `[${tc.name}: ${tc.arguments.command}]`\n : `[${tc.name}: ${tc.arguments.pattern}]`\n opts.onProgress?.({ chunk: hint, type: 'reasoning', text: '', reasoning: hint, section: opts.section })\n break\n }\n case 'done':\n assistantMessage = event.message\n break\n case 'error':\n throw new Error(event.error?.errorMessage ?? 'pi-ai stream error')\n }\n }\n\n if (!assistantMessage)\n throw new Error('pi-ai stream ended without a message')\n\n if (assistantMessage.usage) {\n if (totalUsage) {\n totalUsage.input += assistantMessage.usage.input\n totalUsage.output += assistantMessage.usage.output\n }\n else {\n totalUsage = { input: assistantMessage.usage.input, output: assistantMessage.usage.output }\n }\n totalCost = (totalCost ?? 0) + (assistantMessage.usage.cost?.total ?? 0)\n }\n\n messages.push(assistantMessage)\n\n const toolCalls = assistantMessage.content.filter((c): c is ToolCall => c.type === 'toolCall')\n if (toolCalls.length === 0) {\n text = turnText\n completed = true\n break\n }\n\n for (const tc of toolCalls) {\n const result = executeTool(tc, skilldDir)\n if (tc.name === 'Write')\n lastWriteContent = String(tc.arguments.content)\n messages.push({\n role: 'toolResult' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n content: [{ type: 'text' as const, text: result }],\n isError: result.startsWith('Error:'),\n timestamp: Date.now(),\n })\n }\n }\n\n if (!completed)\n throw new Error(`pi-ai exceeded ${MAX_TOOL_TURNS} tool turns without completing`)\n\n // Prefer text output, fall back to last Write content.\n const finalText = text || lastWriteContent\n\n return { text: finalText, fullPrompt, usage: totalUsage, cost: totalCost }\n}\n","import { API_CHANGE_BULLET_RE, SECTION_HEADING_RE, SOURCE_LINK_RE } from '../../core/regex.ts'\nimport { sanitizeMarkdown } from '../../core/sanitize.ts'\n\nconst STATIC_REGEX_1 = /^```(?:markdown|md)?[^\\S\\n]*\\n([\\s\\S]+)\\n```[^\\S\\n]*$/\nconst STATIC_REGEX_2 = /^```(?:markdown|md)/\nconst STATIC_REGEX_5 = /^-{3,}\\n/\nconst STATIC_REGEX_6 = /\\n-{3,}/\nconst STATIC_REGEX_7 = /^(##\\s|- (?:BREAKING|DEPRECATED|NEW): )/m\nconst STATIC_REGEX_8 = /^(## .+)\\n/\nconst STATIC_REGEX_9 = /^\\.\\/(?:\\.skilld\\/|references\\/)/\n\n/** Clean a single section's LLM output: strip markdown fences, frontmatter, sanitize */\nexport function cleanSectionOutput(content: string): string {\n let cleaned = content.trim()\n\n // Strip wrapping fences if output is wrapped in ```markdown, ```md, or bare ```\n // Requires matched open+close pair to avoid stripping internal code blocks\n const wrapMatch = cleaned.match(STATIC_REGEX_1)\n if (wrapMatch) {\n const inner = wrapMatch[1]!.trim()\n // For bare ``` wrappers (no markdown/md tag), verify inner looks like section output\n const isExplicitWrapper = STATIC_REGEX_2.test(cleaned)\n if (isExplicitWrapper || SECTION_HEADING_RE.test(inner) || API_CHANGE_BULLET_RE.test(inner)) {\n cleaned = inner\n }\n }\n\n // Normalize h1 headers to h2 — LLMs sometimes use # instead of ##\n cleaned = cleaned.replace(/^# (?!#)/gm, '## ')\n\n // Strip accidental frontmatter or leading horizontal rules\n const fmMatch = cleaned.match(STATIC_REGEX_5)\n if (fmMatch) {\n const afterOpen = fmMatch[0].length\n const closeMatch = cleaned.slice(afterOpen).match(STATIC_REGEX_6)\n if (closeMatch) {\n cleaned = cleaned.slice(afterOpen + closeMatch.index! + closeMatch[0].length).trim()\n }\n else {\n cleaned = cleaned.slice(afterOpen).trim()\n }\n }\n\n // Strip preamble before first section marker (LLM reasoning, fake tool calls, code dumps)\n // Section markers: ## heading, BREAKING/DEPRECATED/NEW labels\n const firstMarker = cleaned.match(STATIC_REGEX_7)\n if (firstMarker?.index && firstMarker.index > 0) {\n cleaned = cleaned.slice(firstMarker.index).trim()\n }\n\n // Strip duplicate section headings (LLM echoing the format example before real content)\n // Handles headings separated by blank lines or boilerplate text\n const headingMatch = cleaned.match(STATIC_REGEX_8)\n if (headingMatch) {\n const heading = headingMatch[1]!\n const afterFirst = headingMatch[0].length\n const secondIdx = cleaned.indexOf(heading, afterFirst)\n if (secondIdx !== -1) {\n // Only strip if the gap between duplicates is small (< 200 chars of boilerplate)\n if (secondIdx - afterFirst < 200)\n cleaned = cleaned.slice(secondIdx).trim()\n }\n }\n\n // Normalize citation link text to [source] — LLMs sometimes use the path as link text\n // e.g. [./references/docs/api.md](./references/docs/api.md) or [`./references/...`](...)\n // Also handles paren-wrapped variants: ([`path`](url))\n cleaned = cleaned.replace(\n /\\(?\\[`?\\.\\/(?:\\.skilld\\/|references\\/)[^)\\]]*\\]\\(([^)]+)\\)\\)?/g,\n (match, url: string) => {\n // Only normalize if the URL points to a reference path\n if (STATIC_REGEX_9.test(url))\n return `[source](${url})`\n return match\n },\n )\n\n // Normalize source link paths: ensure .skilld/ prefix is present\n // LLMs sometimes emit [source](./docs/...) instead of [source](./.skilld/docs/...)\n cleaned = cleaned.replace(\n /\\[source\\]\\(\\.\\/((docs|issues|discussions|releases|pkg|guide)\\/)/g,\n '[source](./.skilld/$1',\n )\n\n cleaned = sanitizeMarkdown(cleaned)\n\n // Reject content that lacks any section structure — likely leaked LLM reasoning/narration\n // Valid sections contain headings (##), API change labels, or source-linked items\n if (!SECTION_HEADING_RE.test(cleaned) && !API_CHANGE_BULLET_RE.test(cleaned) && !SOURCE_LINK_RE.test(cleaned)) {\n return ''\n }\n\n return cleaned\n}\n","import type { StreamProgress } from './types.ts'\nimport { styleText } from 'node:util'\nimport { TOOL_NAMES } from './types.ts'\n\nconst STATIC_REGEX_1 = /^\\[(?:starting|retrying|cached)/\nconst STATIC_REGEX_2 = /^\\[([^:[\\]]+)(?::\\s(.+))?\\]$/\nconst STATIC_REGEX_3 = /skilld search\\s+\"([^\"]+)\"/\n\ninterface ToolProgressLog {\n message: (msg: string) => void\n}\n\n/** Create a progress callback that emits one line per tool call, Claude Code style */\nexport function createToolProgress(log: ToolProgressLog): (progress: StreamProgress) => void {\n let lastMsg = ''\n let repeatCount = 0\n /** Per-section timestamp of last \"Writing...\" emission — throttles text_delta spam */\n const lastTextEmit = new Map<string, number>()\n const TEXT_THROTTLE_MS = 2000\n\n function emit(msg: string) {\n if (msg === lastMsg) {\n repeatCount++\n log.message(`${msg} ${styleText('gray', `(+${repeatCount})`)}`)\n }\n else {\n lastMsg = msg\n repeatCount = 0\n log.message(msg)\n }\n }\n\n return ({ type, chunk, text, section }) => {\n if (type === 'text') {\n const key = section ?? ''\n const now = Date.now()\n const last = lastTextEmit.get(key) ?? 0\n if (now - last < TEXT_THROTTLE_MS)\n return\n lastTextEmit.set(key, now)\n const prefix = section ? `${styleText('gray', `[${section}]`)} ` : ''\n // Count bullet items in accumulated text for meaningful progress\n const items = text ? (text.match(/^- (?:BREAKING|DEPRECATED|NEW|CHANGED|REMOVED|Use |Do |Set |Add |Avoid |Always |Never |Prefer |Check |Ensure )/gm)?.length ?? 0) : 0\n emit(items > 0 ? `${prefix}Writing... ${styleText('gray', `(${items} items)`)}` : `${prefix}Writing...`)\n return\n }\n if (type !== 'reasoning' || !chunk.startsWith('['))\n return\n\n // Handle status messages like [starting...], [retrying...], [cached]\n if (STATIC_REGEX_1.test(chunk)) {\n const prefix = section ? `${styleText('gray', `[${section}]`)} ` : ''\n emit(`${prefix}${chunk.slice(1, -1)}`)\n return\n }\n\n // Parse individual tool names and hints from \"[Read: path]\" or \"[Read, Glob: path1, path2]\"\n const match = chunk.match(STATIC_REGEX_2)\n if (!match)\n return\n\n const names = match[1]!.split(',').map(n => n.trim())\n const hints = match[2]?.split(',').map(h => h.trim()) ?? []\n\n for (let i = 0; i < names.length; i++) {\n const rawName = names[i]!\n const hint = hints[i] ?? hints[0] ?? ''\n const verb = TOOL_NAMES[rawName]?.verb ?? rawName\n const prefix = section ? `${styleText('gray', `[${section}]`)} ` : ''\n\n if ((rawName === 'Bash' || rawName === 'run_shell_command') && hint) {\n const searchMatch = hint.match(STATIC_REGEX_3)\n if (searchMatch) {\n emit(`${prefix}Searching ${styleText('cyan', `\"${searchMatch[1]}\"`)}`)\n }\n else if (hint.includes('skilld validate')) {\n emit(`${prefix}Validating...`)\n }\n else {\n const shortened = shortenCommand(hint)\n emit(`${prefix}Running ${shortened.length > 50 ? `${shortened.slice(0, 47)}...` : shortened}`)\n }\n }\n else {\n const path = shortenPath(hint || '...')\n emit(`${prefix}${verb} ${styleText('gray', path)}`)\n }\n }\n }\n}\n\n/** Shorten absolute paths for display: /home/user/project/.claude/skills/vue/SKILL.md → .claude/.../SKILL.md */\nfunction shortenPath(p: string): string {\n const refIdx = p.indexOf('.skilld/')\n if (refIdx !== -1)\n return p.slice(refIdx + '.skilld/'.length)\n // Keep just filename for other paths\n const parts = p.split('/')\n return parts.length > 2 ? `.../${parts.slice(-2).join('/')}` : p\n}\n\n/** Replace absolute paths in a command string with shortened versions */\nfunction shortenCommand(cmd: string): string {\n return cmd.replace(/\\/[^\\s\"']+/g, (match) => {\n // Only shorten paths that look like they're inside a project\n if (match.includes('.claude/') || match.includes('.skilld/') || match.includes('node_modules/'))\n return `.../${match.split('/').slice(-2).join('/')}`\n return match\n })\n}\n","/**\n * CLI orchestrator — spawns per-CLI processes for skill generation\n * Each CLI (claude, gemini, codex) has its own buildArgs + parseLine in separate files\n */\n\nimport type { AgentType } from '../types.ts'\nimport type { CliAdapter, CliModelConfig, CliName, OptimizeModel } from './types.ts'\nimport { exec } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { isWindows } from 'std-env'\nimport { detectInstalledAgents } from '../detect.ts'\nimport { agents } from '../targets/index.ts'\nimport { adapter as claudeAdapter } from './claude.ts'\nimport { adapter as codexAdapter } from './codex.ts'\nimport { adapter as geminiAdapter } from './gemini.ts'\nimport { getAvailablePiAiModels, isPiAiModel, parsePiAiModelId } from './pi-ai.ts'\n\nexport { buildAllSectionPrompts, buildSectionPrompt, SECTION_MERGE_ORDER, SECTION_OUTPUT_FILES } from '../prompts/index.ts'\nexport type { CustomPrompt, SkillSection } from '../prompts/index.ts'\nexport { cleanSectionOutput } from './clean-output.ts'\nexport { createToolProgress } from './cli-progress.ts'\nexport type { CliModelConfig, CliName, ModelInfo, OptimizeDocsOptions, OptimizeModel, OptimizeResult, StreamProgress } from './types.ts'\n\n// ── Per-CLI dispatch ─────────────────────────────────────────────────\n\n/** Single source of truth: adding a new CLI adapter here is the only edit needed in this file. */\nexport const CLI_ADAPTERS: Record<CliName, CliAdapter> = {\n claude: claudeAdapter,\n gemini: geminiAdapter,\n codex: codexAdapter,\n}\n\nconst CLI_PROVIDER_NAMES: Record<string, string> = Object.fromEntries(\n Object.values(CLI_ADAPTERS).map(a => [a.agentId, a.providerName]),\n)\n\nconst PI_PROVIDER_NAMES: Record<string, string> = {\n 'anthropic': 'Anthropic',\n 'google': 'Google',\n 'google-antigravity': 'Antigravity',\n 'google-gemini-cli': 'Google Gemini',\n 'google-vertex': 'Google Vertex',\n 'openai': 'OpenAI',\n 'openai-codex': 'OpenAI Codex',\n 'github-copilot': 'GitHub Copilot',\n 'groq': 'Groq',\n 'mistral': 'Mistral',\n 'xai': 'xAI',\n}\n\n// ── Assemble CLI_MODELS from per-CLI model definitions ───────────────\n\nexport const CLI_MODELS: Partial<Record<OptimizeModel, CliModelConfig>> = Object.fromEntries(\n Object.values(CLI_ADAPTERS).flatMap(adapter =>\n Object.entries(adapter.models).map(([id, entry]) => [\n id,\n { ...entry, cli: adapter.cli, agentId: adapter.agentId },\n ]),\n ),\n)\n\n// ── Model helpers ────────────────────────────────────────────────────\n\nexport function getModelName(id: OptimizeModel): string {\n if (isPiAiModel(id)) {\n const parsed = parsePiAiModelId(id)\n return parsed?.modelId ?? id\n }\n return CLI_MODELS[id]?.name ?? id\n}\n\nexport function getModelLabel(id: OptimizeModel): string {\n if (isPiAiModel(id)) {\n const parsed = parsePiAiModelId(id)\n return parsed ? `${PI_PROVIDER_NAMES[parsed.provider] ?? parsed.provider} · ${parsed.modelId}` : id\n }\n const config = CLI_MODELS[id]\n if (!config)\n return id\n const providerName = CLI_PROVIDER_NAMES[config.agentId] ?? config.cli\n return `${providerName} · ${config.name}`\n}\n\nexport async function getAvailableModels(): Promise<import('./types.ts').ModelInfo[]> {\n const execAsync = promisify(exec)\n const lookupCmd = isWindows ? 'where' : 'which'\n\n const installedAgents = detectInstalledAgents()\n const agentsWithCli = installedAgents.filter(id => agents[id].cli)\n\n const cliChecks = await Promise.all(\n agentsWithCli.map(async (agentId) => {\n const cli = agents[agentId].cli!\n try {\n await execAsync(`${lookupCmd} ${cli}`)\n return agentId\n }\n catch { return null }\n }),\n )\n const availableAgentIds = new Set(cliChecks.filter((id): id is AgentType => id != null))\n\n const cliModels = (Object.entries(CLI_MODELS) as [OptimizeModel, CliModelConfig][])\n .filter(([_, config]) => availableAgentIds.has(config.agentId))\n .map(([id, config]) => {\n const providerName = CLI_PROVIDER_NAMES[config.agentId] ?? agents[config.agentId]?.displayName ?? config.agentId\n return {\n id,\n name: config.name,\n hint: config.hint,\n recommended: config.recommended,\n agentId: config.agentId,\n agentName: providerName,\n provider: config.agentId,\n providerName: `${providerName} (via ${config.cli} CLI)`,\n vendorGroup: providerName,\n }\n })\n\n // Append pi-ai direct API models (providers with auth configured)\n const piAiModels = getAvailablePiAiModels()\n const piAiEntries = piAiModels.map((m) => {\n const parsed = parsePiAiModelId(m.id)\n const piProvider = parsed?.provider ?? 'pi-ai'\n const displayName = PI_PROVIDER_NAMES[piProvider] ?? piProvider\n const authLabel = m.authSource === 'env' ? 'API' : 'OAuth'\n return {\n id: m.id as OptimizeModel,\n name: m.name,\n hint: m.hint,\n recommended: m.recommended,\n agentId: 'pi-ai',\n agentName: `pi-ai (${m.authSource})`,\n provider: `pi:${piProvider}:${m.authSource}`,\n providerName: `${displayName} (${authLabel})`,\n vendorGroup: displayName,\n }\n })\n\n return [...cliModels, ...piAiEntries]\n}\n","/**\n * Detect packages from framework presets (e.g., Nuxt modules in nuxt.config)\n * These are string literals in config arrays, not imports — the import scanner misses them.\n */\n\nimport type { PackageUsage } from './detect-imports.ts'\nimport { readFile } from 'node:fs/promises'\nimport { parseSync } from 'oxc-parser'\nimport { join } from 'pathe'\n\nconst NUXT_CONFIG_FILES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\nconst NUXT_ECOSYSTEM = ['vue', 'nitro', 'h3']\n\nasync function findNuxtConfig(cwd: string): Promise<{ path: string, content: string } | null> {\n for (const name of NUXT_CONFIG_FILES) {\n const path = join(cwd, name)\n const content = await readFile(path, 'utf8').catch(() => null)\n if (content)\n return { path, content }\n }\n return null\n}\n\n/**\n * Walk AST node to find all string values inside a `modules` array property.\n * Handles: defineNuxtConfig({ modules: [...] }) and export default { modules: [...] }\n */\nexport function extractModuleStrings(node: any): string[] {\n if (!node || typeof node !== 'object')\n return []\n\n // Found a Property with key \"modules\" and an ArrayExpression value\n if (node.type === 'Property' && !node.computed\n && (node.key?.type === 'Identifier' && node.key.name === 'modules')\n && node.value?.type === 'ArrayExpression') { return node.value.elements.filter((el: any) => el?.type === 'Literal' && typeof el.value === 'string').map((el: any) => el.value as string) }\n\n // Recurse into arrays and object values\n const results: string[] = []\n if (Array.isArray(node)) {\n for (const child of node)\n results.push(...extractModuleStrings(child))\n }\n else {\n for (const key of Object.keys(node)) {\n if (key === 'start' || key === 'end' || key === 'type')\n continue\n const val = node[key]\n if (val && typeof val === 'object')\n results.push(...extractModuleStrings(val))\n }\n }\n return results\n}\n\n/**\n * Detect Nuxt modules from nuxt.config.{ts,js,mjs}\n */\nexport async function detectNuxtModules(cwd: string): Promise<PackageUsage[]> {\n const config = await findNuxtConfig(cwd)\n if (!config)\n return []\n\n const result = parseSync(config.path, config.content)\n const modules = extractModuleStrings(result.program)\n\n // Dedupe and build results\n const seen = new Set<string>()\n const packages: PackageUsage[] = []\n\n for (const mod of modules) {\n if (!seen.has(mod)) {\n seen.add(mod)\n packages.push({ name: mod, count: 0, source: 'preset' })\n }\n }\n\n // Add core ecosystem packages\n for (const pkg of NUXT_ECOSYSTEM) {\n if (!seen.has(pkg)) {\n seen.add(pkg)\n packages.push({ name: pkg, count: 0, source: 'preset' })\n }\n }\n\n return packages\n}\n\n/**\n * Run all preset detectors and merge results\n */\nexport async function detectPresetPackages(cwd: string): Promise<PackageUsage[]> {\n // Currently only Nuxt, but extensible for other frameworks\n return detectNuxtModules(cwd)\n}\n","/**\n * Detect directly-used npm packages by scanning source files\n */\n\nimport { glob, readFile } from 'node:fs/promises'\nimport { join } from 'pathe'\nimport { detectPresetPackages } from './detect-presets.ts'\n\n// Static: import x from '...' | export ... from '...'\nconst FROM_STATIC_IMPORT_RE = /\\bfrom\\s*['\"]([^'\"\\n]+)['\"]/g\n// Side-effect: import '...'\nconst SIDE_EFFECT_IMPORT_RE = /\\bimport\\s*['\"]([^'\"\\n]+)['\"]/g\n// Dynamic: import('...')\nconst DYNAMIC_IMPORT_RE = /\\bimport\\s*\\(\\s*['\"]([^'\"\\n]+)['\"]\\s*\\)/g\n\nexport interface PackageUsage {\n name: string\n count: number\n source?: 'import' | 'preset'\n}\n\nexport interface DetectResult {\n packages: PackageUsage[]\n error?: string\n}\n\nconst PATTERNS = ['**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}']\nconst IGNORE_DIRS = ['node_modules', 'dist', '.nuxt', '.output', 'coverage']\n\nfunction addPackage(counts: Map<string, number>, specifier: string | undefined) {\n if (!specifier || specifier.startsWith('.') || specifier.startsWith('/'))\n return\n\n // Extract package name (handle subpaths like 'pkg/subpath')\n const name = specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0]!\n\n if (!isNodeBuiltin(name)) {\n counts.set(name, (counts.get(name) || 0) + 1)\n }\n}\n\n/**\n * Scan source files to detect all directly-imported npm packages\n * Async with gitignore support for proper spinner animation\n */\nexport async function detectImportedPackages(cwd: string = process.cwd()): Promise<DetectResult> {\n try {\n const counts = new Map<string, number>()\n\n const files: string[] = []\n for await (const file of glob(PATTERNS, {\n cwd,\n exclude: (p: string) => IGNORE_DIRS.some(dir => p === dir || p.endsWith(`/${dir}`)),\n })) {\n files.push(join(cwd, file))\n }\n\n await Promise.all(files.map(async (file) => {\n const content = await readFile(file, 'utf8')\n\n for (const m of content.matchAll(FROM_STATIC_IMPORT_RE))\n addPackage(counts, m[1])\n\n for (const m of content.matchAll(SIDE_EFFECT_IMPORT_RE))\n addPackage(counts, m[1])\n\n for (const m of content.matchAll(DYNAMIC_IMPORT_RE))\n addPackage(counts, m[1])\n }))\n\n // Sort by usage count (descending), then alphabetically\n const packages: PackageUsage[] = Array.from(counts.entries(), ([name, count]) => ({ name, count, source: 'import' as const }))\n .sort((a, b) => b.count - a.count || a.name.localeCompare(b.name))\n\n // Merge preset-detected packages (imports take priority)\n const presets = await detectPresetPackages(cwd)\n const importNames = new Set(packages.map(p => p.name))\n for (const preset of presets) {\n if (!importNames.has(preset.name))\n packages.push(preset)\n }\n\n return { packages }\n }\n catch (err) {\n return { packages: [], error: String(err) }\n }\n}\n\nconst NODE_BUILTINS = new Set([\n 'assert',\n 'async_hooks',\n 'buffer',\n 'child_process',\n 'cluster',\n 'console',\n 'constants',\n 'crypto',\n 'dgram',\n 'diagnostics_channel',\n 'dns',\n 'domain',\n 'events',\n 'fs',\n 'http',\n 'http2',\n 'https',\n 'inspector',\n 'module',\n 'net',\n 'os',\n 'path',\n 'perf_hooks',\n 'process',\n 'punycode',\n 'querystring',\n 'readline',\n 'repl',\n 'sea',\n 'sqlite',\n 'stream',\n 'string_decoder',\n 'sys',\n 'test',\n 'timers',\n 'tls',\n 'trace_events',\n 'tty',\n 'url',\n 'util',\n 'v8',\n 'vm',\n 'wasi',\n 'worker_threads',\n 'zlib',\n])\n\nfunction isNodeBuiltin(pkg: string): boolean {\n const base = pkg.startsWith('node:') ? pkg.slice(5) : pkg\n return NODE_BUILTINS.has(base.split('/')[0]!)\n}\n","import type { SkillSection } from '../prompts/index.ts'\nimport type { OptimizeModel } from './types.ts'\nimport { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { LLM_CACHE_DIR } from '../../core/paths.ts'\n\nconst DEFAULT_MAX_AGE = 7 * 24 * 60 * 60 * 1000\n\n/** Strip absolute paths from prompt so the hash is project-independent */\nfunction normalizePromptForHash(prompt: string): string {\n return prompt.replace(/\\/[^\\s`]*\\.(?:claude|codex|gemini)\\/skills\\/[^\\s/`]+/g, '<SKILL_DIR>')\n}\n\nfunction hashPrompt(prompt: string, model: OptimizeModel, section: SkillSection): string {\n return createHash('sha256').update(`exec:${model}:${section}:${normalizePromptForHash(prompt)}`).digest('hex').slice(0, 16)\n}\n\nexport function getCached(prompt: string, model: OptimizeModel, section: SkillSection, maxAge = DEFAULT_MAX_AGE): string | null {\n const path = join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`)\n if (!existsSync(path))\n return null\n try {\n const { text, timestamp } = JSON.parse(readFileSync(path, 'utf-8'))\n return Date.now() - timestamp > maxAge ? null : text\n }\n catch { return null }\n}\n\nexport function setCache(prompt: string, model: OptimizeModel, section: SkillSection, text: string): void {\n mkdirSync(LLM_CACHE_DIR, { recursive: true, mode: 0o700 })\n writeFileSync(\n join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`),\n JSON.stringify({ text, model, section, timestamp: Date.now() }),\n { mode: 0o600 },\n )\n}\n","/**\n * Section runner — shared seam for \"run a model and turn output into a SectionResult\".\n *\n * Both the spawn-based CLI path (claude/gemini/codex) and the in-process pi-ai path\n * compose three steps: prepareSection → run model → finalizeSection. The model run\n * itself differs (process vs API call); everything around it is shared here.\n */\n\nimport type { SkillSection } from '../prompts/index.ts'\nimport type { CliAdapter, SectionResult, StreamProgress, ValidationWarning } from './types.ts'\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { isWindows } from 'std-env'\nimport { getSectionValidator, SECTION_OUTPUT_FILES } from '../prompts/index.ts'\nimport { cleanSectionOutput } from './clean-output.ts'\n\n/**\n * Strategy for running one section through a model. Two real adapters today:\n * `cliExecutor` (subprocess via `spawnCliAndStream`) and `piAiExecutor`\n * (in-process agent loop via `optimizeSectionPiAi`). The lifecycle around\n * `run` (prepareSection → run → finalizeSection) is identical for both.\n */\nexport interface SectionExecutor {\n /** When true, finalizeSection runs the prompt-injection cleanup pass. */\n cliCleanup: boolean\n run: (opts: {\n section: SkillSection\n prompt: string\n skillDir: string\n skilldDir: string\n timeout: number\n debug?: boolean\n onProgress?: (progress: StreamProgress) => void\n }) => Promise<RawRunOutput>\n}\n\n/** What a model run produces, before file/cleanup/validation. */\nexport interface RawRunOutput {\n /** Accumulated text from the run (stdout for CLIs, in-memory for pi-ai). */\n text: string\n /** Content the LLM tried to Write (fallback when host blocks Write tool). */\n writeContent?: string\n usage?: { input: number, output: number }\n cost?: number\n /** Stderr from a process run; undefined for in-memory runs. */\n stderr?: string\n /** Process exit code; undefined or 0 for successful in-memory runs. */\n exitCode?: number\n /** Raw stream-json lines for debug logging; CLI only. */\n rawLines?: string[]\n}\n\n/** Clear stale output and write the prompt file for debugging. */\nexport function prepareSection(opts: {\n section: SkillSection\n prompt: string\n outputPath: string\n skilldDir: string\n}): void {\n if (existsSync(opts.outputPath))\n unlinkSync(opts.outputPath)\n writeFileSync(join(opts.skilldDir, `PROMPT_${opts.section}.md`), opts.prompt)\n}\n\n/**\n * Turn a RawRunOutput into a SectionResult: resolve final text (file > writeContent > stdout),\n * clean, validate, and write debug logs. CLI runs additionally pass `cliCleanup` to enforce\n * prompt-injection defense (delete unexpected files in skilldDir).\n */\nexport function finalizeSection(opts: {\n section: SkillSection\n raw: RawRunOutput\n outputFile: string\n outputPath: string\n skilldDir: string\n debug: boolean\n /** When set, runs the prompt-injection file cleanup pass. CLI-only. */\n cliCleanup?: { preExistingFiles: Set<string> }\n}): SectionResult {\n const { section, raw, outputFile, outputPath, skilldDir, debug, cliCleanup } = opts\n\n if (cliCleanup) {\n for (const entry of readdirSync(skilldDir)) {\n if (entry === outputFile || cliCleanup.preExistingFiles.has(entry))\n continue\n if (Object.values(SECTION_OUTPUT_FILES).includes(entry))\n continue\n if (entry.startsWith('PROMPT_') || entry === 'logs')\n continue\n try {\n unlinkSync(join(skilldDir, entry))\n }\n catch {}\n }\n }\n\n const logsDir = join(skilldDir, 'logs')\n const logName = section.toUpperCase().replace(/-/g, '_')\n\n const fileText = existsSync(outputPath) ? readFileSync(outputPath, 'utf-8') : ''\n const text = (fileText || raw.writeContent || raw.text).trim()\n\n const stderr = raw.stderr ?? ''\n const code = raw.exitCode ?? 0\n if (debug || (stderr && (!text || code !== 0))) {\n mkdirSync(logsDir, { recursive: true })\n if (stderr)\n writeFileSync(join(logsDir, `${logName}.stderr.log`), stderr)\n }\n if (debug) {\n mkdirSync(logsDir, { recursive: true })\n if (raw.rawLines?.length)\n writeFileSync(join(logsDir, `${logName}.jsonl`), raw.rawLines.join('\\n'))\n if (text)\n writeFileSync(join(logsDir, `${logName}.md`), text)\n }\n\n if (!text && code !== 0) {\n return { section, content: '', wasOptimized: false, error: stderr.trim() || `CLI exited with code ${code}` }\n }\n\n const content = text ? cleanSectionOutput(text) : ''\n if (content)\n writeFileSync(outputPath, content)\n\n const validator = getSectionValidator(section)\n const rawWarnings = content && validator ? validator(content) : []\n const warnings: ValidationWarning[] = rawWarnings.map(w => ({ section, warning: w.warning }))\n\n return {\n section,\n content,\n wasOptimized: !!content,\n warnings: warnings.length ? warnings : undefined,\n usage: raw.usage,\n cost: raw.cost,\n }\n}\n\n/**\n * Spawn a CLI process, stream stream-json from stdout, parse via the adapter, and resolve\n * with raw run output. The stdin prompt, env, cwd, timeout, and event dispatch all live here;\n * adapters only declare argv shape and event parsing.\n */\nexport function spawnCliAndStream(opts: {\n adapter: CliAdapter\n cliModel: string\n prompt: string\n skillDir: string\n skilldDir: string\n symlinkDirs: string[]\n timeout: number\n debug?: boolean\n section: SkillSection\n onProgress?: (progress: StreamProgress) => void\n}): Promise<RawRunOutput> {\n const { adapter, cliModel, prompt, skillDir, skilldDir, symlinkDirs, timeout, debug, section, onProgress } = opts\n const args = adapter.buildArgs(cliModel, skillDir, symlinkDirs)\n const parseEvent = adapter.parseEvent\n\n return new Promise<RawRunOutput>((resolve) => {\n const proc = spawn(adapter.cli, args, {\n cwd: skilldDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout,\n env: { ...process.env, NO_COLOR: '1' },\n shell: isWindows,\n })\n\n let buffer = ''\n let accumulatedText = ''\n let lastWriteContent = ''\n let usage: { input: number, output: number } | undefined\n let cost: number | undefined\n const rawLines: string[] = []\n\n onProgress?.({ chunk: '[starting...]', type: 'reasoning', text: '', reasoning: '', section })\n\n proc.stdin.write(prompt)\n proc.stdin.end()\n\n function applyEvent(evt: ReturnType<typeof parseEvent>): void {\n switch (evt.kind) {\n case 'text':\n if (evt.delta)\n accumulatedText += evt.delta\n if (evt.full !== undefined)\n accumulatedText = evt.full\n break\n case 'tool-call': {\n if (evt.writeContent)\n lastWriteContent = evt.writeContent\n const chunk = evt.hint ? `[${evt.tool}: ${evt.hint}]` : `[${evt.tool}]`\n onProgress?.({ chunk, type: 'reasoning', text: '', reasoning: chunk, section })\n break\n }\n case 'done':\n if (evt.usage)\n usage = evt.usage\n if (evt.cost != null)\n cost = evt.cost\n break\n case 'error':\n case 'noop':\n break\n }\n }\n\n proc.stdout.on('data', (chunk: Buffer) => {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n for (const line of lines) {\n if (!line.trim())\n continue\n if (debug)\n rawLines.push(line)\n applyEvent(parseEvent(line))\n }\n })\n\n let stderr = ''\n proc.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n\n proc.on('close', (code) => {\n if (buffer.trim())\n applyEvent(parseEvent(buffer))\n resolve({\n text: accumulatedText,\n writeContent: lastWriteContent || undefined,\n usage,\n cost,\n stderr,\n exitCode: code ?? 0,\n rawLines: debug ? rawLines : undefined,\n })\n })\n\n proc.on('error', (err) => {\n resolve({ text: '', stderr: err.message, exitCode: 1 })\n })\n })\n}\n","/**\n * Section executors — concrete `SectionExecutor` impls and model→executor selection.\n *\n * Two adapters today:\n * - `cliExecutor` wraps `spawnCliAndStream` (claude/codex/gemini subprocess)\n * - `piAiExecutor` wraps `optimizeSectionPiAi` (in-process agent loop)\n *\n * Adding a new executor (e.g. raw Anthropic SDK) is a new factory plus a branch in\n * `selectExecutor`. The lifecycle in `llm-enhancer.optimizeSection` does not change.\n */\n\nimport type { SectionExecutor } from './runner.ts'\nimport type { OptimizeModel } from './types.ts'\nimport { getSkillReferenceDirs } from '../../cache/index.ts'\nimport { CLI_ADAPTERS, CLI_MODELS } from './index.ts'\nimport { getAvailablePiAiModels, isPiAiModel, optimizeSectionPiAi } from './pi-ai.ts'\nimport { spawnCliAndStream } from './runner.ts'\n\nfunction cliExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n const cliConfig = CLI_MODELS[model]\n if (!cliConfig)\n return { error: `No CLI mapping for model: ${model}` }\n const adapter = CLI_ADAPTERS[cliConfig.cli]\n return {\n cliCleanup: true,\n run: ({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress }) => spawnCliAndStream({\n adapter,\n cliModel: cliConfig.model,\n prompt,\n skillDir,\n skilldDir,\n symlinkDirs: getSkillReferenceDirs(skillDir),\n timeout,\n debug,\n section,\n onProgress,\n }),\n }\n}\n\nfunction piAiExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n const available = new Set(getAvailablePiAiModels().map(m => m.id as OptimizeModel))\n if (!available.has(model))\n return { error: `Pi model unavailable or not authenticated: ${model}` }\n\n return {\n cliCleanup: false,\n run: async ({ section, prompt, skillDir, timeout, onProgress }) => {\n const ac = new AbortController()\n const timer = setTimeout(() => ac.abort(), timeout)\n try {\n const result = await optimizeSectionPiAi({ section, prompt, skillDir, model, onProgress, signal: ac.signal })\n return { text: result.text.trim(), usage: result.usage, cost: result.cost }\n }\n catch (err) {\n return { text: '', stderr: (err as Error).message, exitCode: 1 }\n }\n finally {\n clearTimeout(timer)\n }\n },\n }\n}\n\n/** Resolve `model` to an executor, or an error if the model is unavailable/unmapped. */\nexport function selectExecutor(model: OptimizeModel): SectionExecutor | { error: string } {\n return isPiAiModel(model) ? piAiExecutor(model) : cliExecutor(model)\n}\n","/**\n * LLM enhancer — drives CLI adapters (and pi-ai) to generate SKILL.md sections.\n *\n * Owns the section-level lifecycle: cache lookup (references-dir + prompt-hash),\n * parallel spawn with stagger, rate-limit-aware retry, and merge-order assembly.\n * Per-CLI concerns (argv, stream parsing, model registry) live in `./clis/`.\n */\n\nimport type { SectionExecutor } from './clis/runner.ts'\nimport type { OptimizeDocsOptions, OptimizeResult, SectionResult, StreamProgress } from './clis/types.ts'\nimport type { SkillSection } from './prompts/index.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync } from 'node:fs'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { join } from 'pathe'\nimport { createReferenceCache } from '../cache/index.ts'\nimport { skillInternalDir, skillLogDir } from '../core/paths.ts'\nimport { getCached, setCache } from './clis/cli-cache.ts'\nimport { selectExecutor } from './clis/executors.ts'\nimport { finalizeSection, prepareSection } from './clis/runner.ts'\nimport { buildAllSectionPrompts, SECTION_MERGE_ORDER, SECTION_OUTPUT_FILES, wrapSection } from './prompts/index.ts'\n\nconst STATIC_REGEX_1 = /\\b429\\b/\nconst STATIC_REGEX_2 = /rate.?limit/i\nconst STATIC_REGEX_3 = /exhausted.*capacity/i\nconst STATIC_REGEX_4 = /quota.*reset/i\nconst STATIC_REGEX_5 = /reset\\s+after\\s+(\\d+)s/i\n\n// ── Per-section run ──────────────────────────────────────────────────\n\ninterface OptimizeSectionOptions {\n section: SkillSection\n prompt: string\n outputFile: string\n skillDir: string\n executor: SectionExecutor\n onProgress?: (progress: StreamProgress) => void\n timeout: number\n debug?: boolean\n preExistingFiles: Set<string>\n}\n\n/** prepareSection → executor.run → finalizeSection. One linear flow per section. */\nasync function optimizeSection(opts: OptimizeSectionOptions): Promise<SectionResult> {\n const { section, prompt, outputFile, skillDir, executor, onProgress, timeout, debug, preExistingFiles } = opts\n const skilldDir = skillInternalDir(skillDir)\n const outputPath = join(skilldDir, outputFile)\n\n prepareSection({ section, prompt, outputPath, skilldDir })\n\n const raw = await executor.run({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress })\n\n return finalizeSection({\n section,\n raw,\n outputFile,\n outputPath,\n skilldDir,\n debug: !!debug,\n cliCleanup: executor.cliCleanup ? { preExistingFiles } : undefined,\n })\n}\n\n// ── Main orchestrator ────────────────────────────────────────────────\n\nexport async function optimizeDocs(opts: OptimizeDocsOptions): Promise<OptimizeResult> {\n const { packageName, skillDir, model = 'sonnet', version, hasGithub, hasReleases, hasChangelog, docFiles, docsType, hasShippedDocs, onProgress, timeout = 180000, debug, noCache, sections, customPrompt, features, pkgFiles, overheadLines } = opts\n const cache = createReferenceCache(packageName, version)\n\n const selectedSections = sections ?? ['api-changes', 'best-practices'] as SkillSection[]\n\n const sectionPrompts = buildAllSectionPrompts({\n packageName,\n skillDir,\n version,\n hasIssues: hasGithub,\n hasDiscussions: hasGithub,\n hasReleases,\n hasChangelog,\n docFiles,\n docsType,\n hasShippedDocs,\n customPrompt,\n features,\n pkgFiles,\n overheadLines,\n sections: selectedSections,\n })\n\n if (sectionPrompts.size === 0) {\n return { optimized: '', wasOptimized: false, error: 'No valid sections to generate' }\n }\n\n const executorOrError = selectExecutor(model)\n if ('error' in executorOrError)\n return { optimized: '', wasOptimized: false, error: executorOrError.error }\n const executor = executorOrError\n\n // Check per-section cache: references dir first (version-keyed), then LLM cache (prompt-hashed)\n const cachedResults: SectionResult[] = []\n const uncachedSections: Array<{ section: SkillSection, prompt: string }> = []\n\n for (const [section, prompt] of sectionPrompts) {\n if (!noCache) {\n if (version) {\n const outputFile = SECTION_OUTPUT_FILES[section]\n const refCached = cache.readSection(outputFile)\n if (refCached) {\n onProgress?.({ chunk: `[${section}: cached]`, type: 'text', text: refCached, reasoning: '', section })\n cachedResults.push({ section, content: refCached, wasOptimized: true })\n continue\n }\n }\n\n const cached = getCached(prompt, model, section)\n if (cached) {\n onProgress?.({ chunk: `[${section}: cached]`, type: 'text', text: cached, reasoning: '', section })\n cachedResults.push({ section, content: cached, wasOptimized: true })\n continue\n }\n }\n uncachedSections.push({ section, prompt })\n }\n\n const skilldDir = skillInternalDir(skillDir)\n mkdirSync(skilldDir, { recursive: true })\n\n // Pre-flight: warn about broken symlinks in .skilld/ (avoids wasting tokens on missing refs)\n for (const entry of readdirSync(skilldDir)) {\n const entryPath = join(skilldDir, entry)\n try {\n if (lstatSync(entryPath).isSymbolicLink() && !existsSync(entryPath))\n onProgress?.({ chunk: `[warn: broken symlink .skilld/${entry}]`, type: 'reasoning', text: '', reasoning: '' })\n }\n catch {}\n }\n\n const preExistingFiles = new Set(readdirSync(skilldDir))\n\n // Spawn uncached sections with staggered starts to avoid rate-limit collisions\n const STAGGER_MS = 3000\n const spawnResults = uncachedSections.length > 0\n ? await Promise.allSettled(\n uncachedSections.map(({ section, prompt }, i) => {\n const outputFile = SECTION_OUTPUT_FILES[section]\n const run = () => optimizeSection({\n section,\n prompt,\n outputFile,\n skillDir,\n executor,\n onProgress,\n timeout,\n debug,\n preExistingFiles,\n })\n if (i === 0)\n return run()\n return delay(i * STAGGER_MS).then(run)\n }),\n )\n : []\n\n const allResults: SectionResult[] = [...cachedResults]\n let totalUsage: { input: number, output: number } | undefined\n let totalCost = 0\n const retryQueue: Array<{ index: number, section: SkillSection, prompt: string }> = []\n\n for (let i = 0; i < spawnResults.length; i++) {\n const r = spawnResults[i]!\n const { section, prompt } = uncachedSections[i]!\n if (r.status === 'fulfilled' && r.value.wasOptimized) {\n allResults.push(r.value)\n if (r.value.usage) {\n totalUsage = totalUsage ?? { input: 0, output: 0 }\n totalUsage.input += r.value.usage.input\n totalUsage.output += r.value.usage.output\n }\n if (r.value.cost != null)\n totalCost += r.value.cost\n if (!noCache)\n setCache(prompt, model, section, r.value.content)\n }\n else {\n retryQueue.push({ index: i, section, prompt })\n }\n }\n\n // Retry failed sections (sequential, with rate-limit aware backoff)\n for (const { index, section, prompt } of retryQueue) {\n const prevError = getRetryError(spawnResults[index]!)\n const rateLimitDelay = parseRateLimitDelay(prevError)\n\n if (rateLimitDelay != null) {\n const waitSec = Math.max(rateLimitDelay, 5)\n onProgress?.({ chunk: `[${section}] Rate limited, waiting ${waitSec}s...`, type: 'reasoning', text: '', reasoning: '', section })\n await delay(waitSec * 1000)\n }\n else {\n onProgress?.({ chunk: `[${section}: retrying...]`, type: 'reasoning', text: '', reasoning: '', section })\n await delay(STAGGER_MS)\n }\n\n const result = await optimizeSection({\n section,\n prompt,\n outputFile: SECTION_OUTPUT_FILES[section],\n skillDir,\n executor,\n onProgress,\n timeout,\n debug,\n preExistingFiles,\n }).catch((err: Error) => ({ section, content: '', wasOptimized: false, error: err.message }) as SectionResult)\n\n allResults.push(result)\n if (result.wasOptimized && !noCache)\n setCache(prompt, model, section, result.content)\n if (result.usage) {\n totalUsage = totalUsage ?? { input: 0, output: 0 }\n totalUsage.input += result.usage.input\n totalUsage.output += result.usage.output\n }\n if (result.cost != null)\n totalCost += result.cost\n }\n\n // Write successful sections to global references dir for cross-project reuse\n if (version) {\n const sectionFiles = allResults\n .filter(r => r.wasOptimized && r.content)\n .map(r => ({ file: SECTION_OUTPUT_FILES[r.section], content: r.content }))\n if (sectionFiles.length > 0) {\n cache.writeSections(sectionFiles)\n }\n }\n\n // Merge results in SECTION_MERGE_ORDER, wrapped with comment markers\n const mergedParts: string[] = []\n for (const section of SECTION_MERGE_ORDER) {\n const result = allResults.find(r => r.section === section)\n if (result?.wasOptimized && result.content) {\n mergedParts.push(wrapSection(section, result.content))\n }\n }\n\n const optimized = mergedParts.join('\\n\\n')\n const wasOptimized = mergedParts.length > 0\n\n const usageResult = totalUsage\n ? { inputTokens: totalUsage.input, outputTokens: totalUsage.output, totalTokens: totalUsage.input + totalUsage.output }\n : undefined\n\n const errors = allResults.filter(r => r.error).map(r => `${r.section}: ${r.error}`)\n const warnings = allResults.flatMap(r => r.warnings ?? []).map(w => `${w.section}: ${w.warning}`)\n\n const debugLogsDir = debug && uncachedSections.length > 0\n ? skillLogDir(skillDir)\n : undefined\n\n return {\n optimized,\n wasOptimized,\n error: errors.length > 0 ? errors.join('; ') : undefined,\n warnings: warnings.length > 0 ? warnings : undefined,\n finishReason: wasOptimized ? 'stop' : 'error',\n usage: usageResult,\n cost: totalCost || undefined,\n debugLogsDir,\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction isRateLimitError(error: string | undefined): boolean {\n if (!error)\n return false\n return STATIC_REGEX_1.test(error)\n || STATIC_REGEX_2.test(error)\n || STATIC_REGEX_3.test(error)\n || STATIC_REGEX_4.test(error)\n}\n\nfunction parseRateLimitDelay(error: string | undefined): number | undefined {\n if (!error || !isRateLimitError(error))\n return undefined\n const match = error.match(STATIC_REGEX_5)\n return match ? Number(match[1]) : 10\n}\n\nfunction getRetryError(result: PromiseSettledResult<SectionResult>): string | undefined {\n if (result.status === 'rejected')\n return String(result.reason)\n return result.value.error\n}\n"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { a as targets } from "./detect.mjs";
2
+ import "./agent.mjs";
3
+ const sharedArgs = {
4
+ global: {
5
+ type: "boolean",
6
+ alias: "g",
7
+ description: "Install globally to ~/<agent>/skills",
8
+ default: false
9
+ },
10
+ agent: {
11
+ type: "enum",
12
+ options: Object.keys(targets),
13
+ alias: "a",
14
+ description: "Target agent — where skills are installed"
15
+ },
16
+ model: {
17
+ type: "string",
18
+ alias: "m",
19
+ description: "Enhancement model for SKILL.md generation",
20
+ valueHint: "id"
21
+ },
22
+ yes: {
23
+ type: "boolean",
24
+ alias: "y",
25
+ description: "Skip prompts, use defaults",
26
+ default: false
27
+ },
28
+ force: {
29
+ type: "boolean",
30
+ alias: "f",
31
+ description: "Ignore all caches, re-fetch docs and regenerate",
32
+ default: false
33
+ },
34
+ debug: {
35
+ type: "boolean",
36
+ description: "Save raw enhancement output to logs/ for each section",
37
+ default: false
38
+ }
39
+ };
40
+ export { sharedArgs as t };
41
+
42
+ //# sourceMappingURL=args.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.mjs","names":["agents"],"sources":["../../src/cli/args.ts"],"sourcesContent":["import { agents } from '../agent/index.ts'\n\nexport const sharedArgs = {\n global: {\n type: 'boolean' as const,\n alias: 'g',\n description: 'Install globally to ~/<agent>/skills',\n default: false,\n },\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent — where skills are installed',\n },\n model: {\n type: 'string' as const,\n alias: 'm',\n description: 'Enhancement model for SKILL.md generation',\n valueHint: 'id',\n },\n yes: {\n type: 'boolean' as const,\n alias: 'y',\n description: 'Skip prompts, use defaults',\n default: false,\n },\n force: {\n type: 'boolean' as const,\n alias: 'f',\n description: 'Ignore all caches, re-fetch docs and regenerate',\n default: false,\n },\n debug: {\n type: 'boolean' as const,\n description: 'Save raw enhancement output to logs/ for each section',\n default: false,\n },\n}\n"],"mappings":";;AAEA,MAAa,aAAa;CACxB,QAAQ;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,SAAS;EACV;CACD,OAAO;EACL,MAAM;EACN,SAAS,OAAO,KAAKA,QAAO;EAC5B,OAAO;EACP,aAAa;EACd;CACD,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,WAAW;EACZ;CACD,KAAK;EACH,MAAM;EACN,OAAO;EACP,aAAa;EACb,SAAS;EACV;CACD,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,SAAS;EACV;CACD,OAAO;EACL,MAAM;EACN,aAAa;EACb,SAAS;EACV;CACF"}