my-pi 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -5
- package/dist/api-B6KnhtN9.js +1893 -0
- package/dist/api-B6KnhtN9.js.map +1 -0
- package/dist/api.js +1 -49
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/extensions/config.test.ts +88 -0
- package/src/extensions/config.ts +189 -0
- package/src/extensions/extensions.ts +366 -0
- package/src/extensions/recall.ts +29 -226
- package/src/extensions/skills.ts +496 -75
- package/src/skills/importer.test.ts +301 -0
- package/src/skills/importer.ts +221 -0
- package/src/skills/manager.ts +129 -30
- package/src/skills/scanner.ts +172 -72
- package/dist/api.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-B6KnhtN9.js","names":["DEFAULT_CONFIG","ENABLED","DISABLED","to_setting_item","sets_equal","#config","#proc","#buffer","#pending","#request","#send","#nextId","mcp_extension","skills_extension","chain_extension","filter_output_extension","handoff_extension","recall_extension"],"sources":["../src/extensions/chain.ts","../src/extensions/config.ts","../src/extensions/extensions.ts","../src/extensions/filter-output.ts","../src/extensions/handoff.ts","../src/mcp/client.ts","../src/mcp/config.ts","../src/extensions/mcp.ts","../src/extensions/recall.ts","../src/skills/config.ts","../src/skills/scanner.ts","../src/skills/importer.ts","../src/skills/manager.ts","../src/extensions/skills.ts","../src/api.ts"],"sourcesContent":["// Agent chain extension — sequential pipeline orchestrator\n// Inspired by https://github.com/disler/pi-vs-claude-code/blob/main/extensions/agent-chain.ts\n\nimport {\n\ttype ExtensionAPI,\n\tdefineTool,\n\tparseFrontmatter,\n} from '@mariozechner/pi-coding-agent';\nimport { Type } from '@sinclair/typebox';\nimport { spawn } from 'node:child_process';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\n// ── Types ───────────────────────────────────────\n\ninterface ChainStep {\n\tagent: string;\n\tprompt: string;\n}\n\ninterface ChainDef {\n\tname: string;\n\tdescription: string;\n\tsteps: ChainStep[];\n}\n\ninterface AgentDef {\n\tname: string;\n\tdescription: string;\n\ttools: string;\n\tsystemPrompt: string;\n}\n\n// ── YAML parser (minimal, no dep) ──────────────\n\nfunction parse_chain_yaml(raw: string): ChainDef[] {\n\tconst chains: ChainDef[] = [];\n\tlet current: ChainDef | null = null;\n\tlet current_step: ChainStep | null = null;\n\n\tfor (const line of raw.split('\\n')) {\n\t\tconst chain_match = line.match(/^(\\S[^:]*):$/);\n\t\tif (chain_match) {\n\t\t\tif (current && current_step) {\n\t\t\t\tcurrent.steps.push(current_step);\n\t\t\t\tcurrent_step = null;\n\t\t\t}\n\t\t\tcurrent = {\n\t\t\t\tname: chain_match[1].trim(),\n\t\t\t\tdescription: '',\n\t\t\t\tsteps: [],\n\t\t\t};\n\t\t\tchains.push(current);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst desc_match = line.match(/^\\s+description:\\s+(.+)$/);\n\t\tif (desc_match && current && !current_step) {\n\t\t\tlet desc = desc_match[1].trim();\n\t\t\tif (\n\t\t\t\t(desc.startsWith('\"') && desc.endsWith('\"')) ||\n\t\t\t\t(desc.startsWith(\"'\") && desc.endsWith(\"'\"))\n\t\t\t) {\n\t\t\t\tdesc = desc.slice(1, -1);\n\t\t\t}\n\t\t\tcurrent.description = desc;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.match(/^\\s+steps:\\s*$/) && current) continue;\n\n\t\tconst agent_match = line.match(/^\\s+-\\s+agent:\\s+(.+)$/);\n\t\tif (agent_match && current) {\n\t\t\tif (current_step) current.steps.push(current_step);\n\t\t\tcurrent_step = {\n\t\t\t\tagent: agent_match[1].trim(),\n\t\t\t\tprompt: '',\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prompt_match = line.match(/^\\s+prompt:\\s+(.+)$/);\n\t\tif (prompt_match && current_step) {\n\t\t\tlet prompt = prompt_match[1].trim();\n\t\t\tif (\n\t\t\t\t(prompt.startsWith('\"') && prompt.endsWith('\"')) ||\n\t\t\t\t(prompt.startsWith(\"'\") && prompt.endsWith(\"'\"))\n\t\t\t) {\n\t\t\t\tprompt = prompt.slice(1, -1);\n\t\t\t}\n\t\t\tprompt = prompt.replace(/\\\\n/g, '\\n');\n\t\t\tcurrent_step.prompt = prompt;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tif (current && current_step) {\n\t\tcurrent.steps.push(current_step);\n\t}\n\n\treturn chains;\n}\n\n// ── Agent file parser ──────────────────────────\n\nfunction parse_agent_file(filePath: string): AgentDef | null {\n\ttry {\n\t\tconst raw = readFileSync(filePath, 'utf-8');\n\t\tconst { frontmatter, body } = parseFrontmatter<{\n\t\t\tname?: string;\n\t\t\tdescription?: string;\n\t\t\ttools?: string;\n\t\t}>(raw);\n\n\t\tif (!frontmatter?.name) return null;\n\n\t\treturn {\n\t\t\tname: frontmatter.name,\n\t\t\tdescription: frontmatter.description || '',\n\t\t\ttools: frontmatter.tools || 'read,grep,find,ls',\n\t\t\tsystemPrompt: body.trim(),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction scan_agent_dirs(cwd: string): Map<string, AgentDef> {\n\tconst dirs = [\n\t\tjoin(cwd, 'agents'),\n\t\tjoin(cwd, '.claude', 'agents'),\n\t\tjoin(cwd, '.pi', 'agents'),\n\t];\n\n\tconst agents = new Map<string, AgentDef>();\n\n\tfor (const dir of dirs) {\n\t\tif (!existsSync(dir)) continue;\n\t\ttry {\n\t\t\tfor (const file of readdirSync(dir)) {\n\t\t\t\tif (!file.endsWith('.md')) continue;\n\t\t\t\tconst def = parse_agent_file(resolve(dir, file));\n\t\t\t\tif (def && !agents.has(def.name.toLowerCase())) {\n\t\t\t\t\tagents.set(def.name.toLowerCase(), def);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// skip inaccessible dirs\n\t\t}\n\t}\n\n\treturn agents;\n}\n\n// ── Run a single agent step via my-pi print mode ─\n\nfunction run_agent_step(\n\tagent_def: AgentDef,\n\ttask: string,\n): Promise<{ output: string; exitCode: number }> {\n\t// Use the current process (my-pi) in print mode\n\tconst bin = process.argv[1];\n\tconst args = ['--no-builtin', '-P', task];\n\n\tconst chunks: string[] = [];\n\n\treturn new Promise((res) => {\n\t\tconst proc = spawn(process.execPath, [bin, ...args], {\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tMY_PI_AGENT_SYSTEM_PROMPT: agent_def.systemPrompt,\n\t\t\t},\n\t\t});\n\n\t\tproc.stdout!.setEncoding('utf-8');\n\t\tproc.stdout!.on('data', (chunk: string) => {\n\t\t\tchunks.push(chunk);\n\t\t});\n\n\t\tproc.stderr!.setEncoding('utf-8');\n\t\tproc.stderr!.on('data', () => {});\n\n\t\tproc.on('close', (code) => {\n\t\t\tres({\n\t\t\t\toutput: chunks.join('').trim(),\n\t\t\t\texitCode: code ?? 1,\n\t\t\t});\n\t\t});\n\n\t\tproc.on('error', (err) => {\n\t\t\tres({\n\t\t\t\toutput: `Error spawning agent: ${err.message}`,\n\t\t\t\texitCode: 1,\n\t\t\t});\n\t\t});\n\t});\n}\n\n// ── Extension ──────────────────────────────────\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function chain(pi: ExtensionAPI) {\n\tconst cwd = process.cwd();\n\tconst agents = scan_agent_dirs(cwd);\n\tlet chains: ChainDef[] = [];\n\tlet active_chain: ChainDef | null = null;\n\n\t// Load chain definitions\n\tconst chain_paths = [\n\t\tjoin(cwd, '.pi', 'agents', 'agent-chain.yaml'),\n\t\tjoin(cwd, '.pi', 'agents', 'chains.yaml'),\n\t\tjoin(cwd, '.claude', 'agents', 'chains.yaml'),\n\t];\n\n\tfor (const path of chain_paths) {\n\t\tif (existsSync(path)) {\n\t\t\ttry {\n\t\t\t\tchains = parse_chain_yaml(readFileSync(path, 'utf-8'));\n\t\t\t\tbreak;\n\t\t\t} catch {\n\t\t\t\t// try next\n\t\t\t}\n\t\t}\n\t}\n\n\tif (chains.length > 0) {\n\t\tactive_chain = chains[0];\n\t}\n\n\t// ── run_chain tool ─────────────────────────\n\n\tpi.registerTool(\n\t\tdefineTool({\n\t\t\tname: 'run_chain',\n\t\t\tlabel: 'Run Chain',\n\t\t\tdescription:\n\t\t\t\t\"Execute the active agent chain pipeline. Each step runs sequentially — output from one step feeds into the next as $INPUT. $ORIGINAL is always the user's initial prompt.\",\n\t\t\tparameters: Type.Object({\n\t\t\t\ttask: Type.String({\n\t\t\t\t\tdescription: 'The task/prompt for the chain to process',\n\t\t\t\t}),\n\t\t\t}),\n\t\t\texecute: async (\n\t\t\t\t_id: string,\n\t\t\t\tparams: unknown,\n\t\t\t): Promise<{\n\t\t\t\tcontent: Array<{ type: 'text'; text: string }>;\n\t\t\t\tdetails: { chain: string; steps: number };\n\t\t\t}> => {\n\t\t\t\tconst { task } = params as { task: string };\n\n\t\t\t\tif (!active_chain) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\t\t\t\ttext: 'No chain active. Use /chain to select one.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tchain: '',\n\t\t\t\t\t\t\tsteps: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tlet input = task;\n\t\t\t\tconst original = task;\n\t\t\t\tconst results: string[] = [];\n\n\t\t\t\tfor (let i = 0; i < active_chain.steps.length; i++) {\n\t\t\t\t\tconst step = active_chain.steps[i];\n\t\t\t\t\tconst agent_def = agents.get(step.agent.toLowerCase());\n\n\t\t\t\t\tif (!agent_def) {\n\t\t\t\t\t\tconst msg = `Step ${i + 1}: agent \"${step.agent}\" not found. Available: ${Array.from(agents.keys()).join(', ')}`;\n\t\t\t\t\t\tresults.push(msg);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: 'text' as const, text: msg }],\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\tchain: active_chain.name,\n\t\t\t\t\t\t\t\tsteps: i,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst resolved_prompt = step.prompt\n\t\t\t\t\t\t.replace(/\\$INPUT/g, input)\n\t\t\t\t\t\t.replace(/\\$ORIGINAL/g, original);\n\n\t\t\t\t\tconst result = await run_agent_step(\n\t\t\t\t\t\tagent_def,\n\t\t\t\t\t\tresolved_prompt,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (result.exitCode !== 0) {\n\t\t\t\t\t\tconst msg = `Step ${i + 1} (${step.agent}) failed:\\n${result.output}`;\n\t\t\t\t\t\tresults.push(msg);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: 'text' as const, text: msg }],\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\tchain: active_chain.name,\n\t\t\t\t\t\t\t\tsteps: i + 1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tresults.push(\n\t\t\t\t\t\t`## Step ${i + 1}: ${step.agent}\\n${result.output}`,\n\t\t\t\t\t);\n\t\t\t\t\tinput = result.output;\n\t\t\t\t}\n\n\t\t\t\tconst summary = results.join('\\n\\n---\\n\\n');\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: 'text' as const, text: summary }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tchain: active_chain.name,\n\t\t\t\t\t\tsteps: active_chain.steps.length,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t}),\n\t);\n\n\t// ── /chain command ─────────────────────────\n\n\tpi.registerCommand('chain', {\n\t\tdescription: 'Switch active chain or list chains (chain list)',\n\t\tgetArgumentCompletions: (prefix) => {\n\t\t\tconst parts = prefix.trim().split(/\\s+/);\n\t\t\tif (parts.length <= 1) {\n\t\t\t\tconst subs = ['list', ...chains.map((c) => c.name)];\n\t\t\t\treturn subs\n\t\t\t\t\t.filter((s) => s.startsWith(parts[0] || ''))\n\t\t\t\t\t.map((s) => ({ value: s, label: s }));\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tconst sub = args.trim();\n\n\t\t\tif (!sub || sub === 'list') {\n\t\t\t\tif (chains.length === 0) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t'No chains found. Add chains to .pi/agents/agent-chain.yaml',\n\t\t\t\t\t\t'warning',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst lines = chains.map((c) => {\n\t\t\t\t\tconst active = c.name === active_chain?.name ? ' *' : '';\n\t\t\t\t\tconst steps = c.steps.map((s) => s.agent).join(' -> ');\n\t\t\t\t\treturn `${c.name}${active}: ${c.description || steps}`;\n\t\t\t\t});\n\t\t\t\tctx.ui.notify(lines.join('\\n'));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst found_chain = chains.find(\n\t\t\t\t(c) => c.name.toLowerCase() === sub.toLowerCase(),\n\t\t\t);\n\t\t\tif (!found_chain) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Unknown chain: ${sub}. Use /chain list.`,\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tactive_chain = found_chain;\n\t\t\tconst flow = found_chain.steps.map((s) => s.agent).join(' -> ');\n\t\t\tctx.ui.notify(`Active chain: ${found_chain.name} (${flow})`);\n\t\t},\n\t});\n\n\t// ── System prompt injection ────────────────\n\n\tpi.on(\n\t\t'before_agent_start',\n\t\tasync (event: { systemPrompt: string }) => {\n\t\t\tif (!active_chain || chains.length === 0) return {};\n\n\t\t\tconst flow = active_chain.steps\n\t\t\t\t.map((s) => s.agent)\n\t\t\t\t.join(' -> ');\n\n\t\t\tconst step_list = active_chain.steps\n\t\t\t\t.map((s, i) => {\n\t\t\t\t\tconst def = agents.get(s.agent.toLowerCase());\n\t\t\t\t\tconst desc = def?.description || 'unknown';\n\t\t\t\t\treturn `${i + 1}. **${s.agent}** — ${desc}`;\n\t\t\t\t})\n\t\t\t\t.join('\\n');\n\n\t\t\tconst chain_list = chains\n\t\t\t\t.map((c) => {\n\t\t\t\t\tconst active =\n\t\t\t\t\t\tc.name === active_chain?.name ? ' (active)' : '';\n\t\t\t\t\treturn `- ${c.name}${active}: ${c.description}`;\n\t\t\t\t})\n\t\t\t\t.join('\\n');\n\n\t\t\t// Append chain context to the existing system prompt\n\t\t\treturn {\n\t\t\t\tsystemPrompt:\n\t\t\t\t\tevent.systemPrompt +\n\t\t\t\t\t`\n\n## Agent Chains\n\nYou have a run_chain tool that executes sequential agent pipelines.\n\n### Active Chain: ${active_chain.name}\n${active_chain.description}\nFlow: ${flow}\n\n${step_list}\n\n### Available Chains\n${chain_list}\n\n### When to use run_chain\n- Non-trivial work: features, refactors, multi-file changes\n- Tasks that benefit from planning then building then reviewing\n- When structured multi-agent collaboration helps\n\n### When to work directly\n- Simple reads, quick lookups, small edits\n- Answering questions about the codebase\n- Anything you can handle in one step\n\nSwitch chains with /chain <name>.`,\n\t\t\t};\n\t\t},\n\t);\n\n\t// ── /agents command ────────────────────────\n\n\tpi.registerCommand('agents', {\n\t\tdescription: 'List discovered agent definitions',\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (agents.size === 0) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t'No agents found in agents/, .pi/agents/, or .claude/agents/',\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst lines = Array.from(agents.values()).map(\n\t\t\t\t(a) =>\n\t\t\t\t\t`${a.name}: ${a.description || '(no description)'} [${a.tools}]`,\n\t\t\t);\n\t\t\tctx.ui.notify(lines.join('\\n'));\n\t\t},\n\t});\n}\n","import {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\trenameSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nexport type BuiltinExtensionKey =\n\t| 'mcp'\n\t| 'skills'\n\t| 'chain'\n\t| 'filter-output'\n\t| 'handoff'\n\t| 'recall';\n\nexport interface BuiltinExtensionInfo {\n\tkey: BuiltinExtensionKey;\n\tlabel: string;\n\tdescription: string;\n\tcli_flag: string;\n\taliases: string[];\n}\n\nexport interface BuiltinExtensionsConfig {\n\tversion: number;\n\tenabled: Partial<Record<BuiltinExtensionKey, boolean>>;\n}\n\nexport interface BuiltinExtensionState extends BuiltinExtensionInfo {\n\tsaved_enabled: boolean;\n\teffective_enabled: boolean;\n\tforced_disabled: boolean;\n}\n\nconst DEFAULT_CONFIG: BuiltinExtensionsConfig = {\n\tversion: 1,\n\tenabled: {},\n};\n\nexport const BUILTIN_EXTENSIONS: BuiltinExtensionInfo[] = [\n\t{\n\t\tkey: 'mcp',\n\t\tlabel: 'MCP',\n\t\tdescription: 'MCP server integration and /mcp command',\n\t\tcli_flag: '--no-mcp',\n\t\taliases: ['mcp'],\n\t},\n\t{\n\t\tkey: 'skills',\n\t\tlabel: 'Skills',\n\t\tdescription: 'Managed pi-native skills and /skills command',\n\t\tcli_flag: '--no-skills',\n\t\taliases: ['skills', 'skill'],\n\t},\n\t{\n\t\tkey: 'chain',\n\t\tlabel: 'Chain',\n\t\tdescription: 'Agent chain orchestration and /chain command',\n\t\tcli_flag: '--no-chain',\n\t\taliases: ['chain', 'chains'],\n\t},\n\t{\n\t\tkey: 'filter-output',\n\t\tlabel: 'Filter output',\n\t\tdescription: 'Secret redaction for tool output',\n\t\tcli_flag: '--no-filter',\n\t\taliases: [\n\t\t\t'filter-output',\n\t\t\t'filter_output',\n\t\t\t'filter',\n\t\t\t'redaction',\n\t\t],\n\t},\n\t{\n\t\tkey: 'handoff',\n\t\tlabel: 'Handoff',\n\t\tdescription: 'Session handoff export and /handoff command',\n\t\tcli_flag: '--no-handoff',\n\t\taliases: ['handoff'],\n\t},\n\t{\n\t\tkey: 'recall',\n\t\tlabel: 'Recall',\n\t\tdescription: 'Past session recall guidance and /recall command',\n\t\tcli_flag: '--no-recall',\n\t\taliases: ['recall'],\n\t},\n];\n\nexport function get_builtin_extensions_config_path(): string {\n\tconst xdg =\n\t\tprocess.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n\treturn join(xdg, 'my-pi', 'extensions.json');\n}\n\nexport function load_builtin_extensions_config(): BuiltinExtensionsConfig {\n\tconst path = get_builtin_extensions_config_path();\n\tif (!existsSync(path)) return { ...DEFAULT_CONFIG };\n\n\ttry {\n\t\tconst raw = readFileSync(path, 'utf-8');\n\t\tconst parsed = JSON.parse(\n\t\t\traw,\n\t\t) as Partial<BuiltinExtensionsConfig>;\n\t\tconst enabled: BuiltinExtensionsConfig['enabled'] = {};\n\t\tfor (const extension of BUILTIN_EXTENSIONS) {\n\t\t\tconst value = parsed.enabled?.[extension.key];\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\tenabled[extension.key] = value;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tversion: parsed.version ?? 1,\n\t\t\tenabled,\n\t\t};\n\t} catch {\n\t\treturn { ...DEFAULT_CONFIG };\n\t}\n}\n\nexport function save_builtin_extensions_config(\n\tconfig: BuiltinExtensionsConfig,\n): void {\n\tconst path = get_builtin_extensions_config_path();\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(tmp, JSON.stringify(config, null, '\\t') + '\\n', {\n\t\tmode: 0o600,\n\t});\n\trenameSync(tmp, path);\n}\n\nexport function is_builtin_extension_enabled(\n\tconfig: BuiltinExtensionsConfig,\n\tkey: BuiltinExtensionKey,\n): boolean {\n\treturn config.enabled[key] ?? true;\n}\n\nexport function is_builtin_extension_active(\n\tconfig: BuiltinExtensionsConfig,\n\tkey: BuiltinExtensionKey,\n\tforce_disabled: ReadonlySet<BuiltinExtensionKey> = new Set(),\n): boolean {\n\treturn (\n\t\tis_builtin_extension_enabled(config, key) &&\n\t\t!force_disabled.has(key)\n\t);\n}\n\nexport function resolve_builtin_extension_states(\n\tforce_disabled: ReadonlySet<BuiltinExtensionKey> = new Set(),\n\tconfig: BuiltinExtensionsConfig = load_builtin_extensions_config(),\n): BuiltinExtensionState[] {\n\treturn BUILTIN_EXTENSIONS.map((extension) => {\n\t\tconst saved_enabled = is_builtin_extension_enabled(\n\t\t\tconfig,\n\t\t\textension.key,\n\t\t);\n\t\tconst forced = force_disabled.has(extension.key);\n\t\treturn {\n\t\t\t...extension,\n\t\t\tsaved_enabled,\n\t\t\teffective_enabled: saved_enabled && !forced,\n\t\t\tforced_disabled: forced,\n\t\t};\n\t});\n}\n\nexport function find_builtin_extension(\n\tquery: string,\n): BuiltinExtensionInfo | undefined {\n\tconst normalized = query.trim().toLowerCase();\n\tif (!normalized) return undefined;\n\n\treturn BUILTIN_EXTENSIONS.find((extension) =>\n\t\t[extension.key, extension.label, ...extension.aliases].some(\n\t\t\t(value) => value.toLowerCase() === normalized,\n\t\t),\n\t);\n}\n","import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';\nimport {\n\tContainer,\n\tSettingsList,\n\tText,\n\ttype SettingItem,\n} from '@mariozechner/pi-tui';\nimport {\n\tBUILTIN_EXTENSIONS,\n\tfind_builtin_extension,\n\tload_builtin_extensions_config,\n\tresolve_builtin_extension_states,\n\tsave_builtin_extensions_config,\n\ttype BuiltinExtensionKey,\n\ttype BuiltinExtensionState,\n} from './config.js';\n\nconst ENABLED = '[x]';\nconst DISABLED = '[ ]';\n\nexport interface ExtensionsManagerOptions {\n\tforce_disabled?: Iterable<BuiltinExtensionKey>;\n}\n\nfunction to_force_disabled_set(\n\tforce_disabled?: Iterable<BuiltinExtensionKey>,\n): ReadonlySet<BuiltinExtensionKey> {\n\treturn new Set(force_disabled ?? []);\n}\n\nfunction format_effective_state(\n\tstate: BuiltinExtensionState,\n): string {\n\tif (state.effective_enabled) {\n\t\treturn 'enabled';\n\t}\n\tif (state.forced_disabled) {\n\t\treturn `disabled in this process by ${state.cli_flag}`;\n\t}\n\treturn 'disabled';\n}\n\nfunction format_extension_lines(\n\tstates: BuiltinExtensionState[],\n\toptions?: { heading?: string },\n): string {\n\tconst lines: string[] = [];\n\tif (options?.heading) {\n\t\tlines.push(options.heading, '');\n\t}\n\n\tconst enabled_now = states.filter(\n\t\t(state) => state.effective_enabled,\n\t).length;\n\tconst disabled_now = states.length - enabled_now;\n\tlines.push(\n\t\t`${states.length} built-in extensions (${enabled_now} enabled now, ${disabled_now} disabled now)`,\n\t\t'',\n\t);\n\n\tfor (const state of states) {\n\t\tlines.push(\n\t\t\t`${state.saved_enabled ? ENABLED : DISABLED} ${state.label}`,\n\t\t);\n\t\tlines.push(` key: ${state.key}`);\n\t\tlines.push(\n\t\t\t` saved config: ${state.saved_enabled ? 'enabled' : 'disabled'}`,\n\t\t);\n\t\tlines.push(\n\t\t\t` current process: ${format_effective_state(state)}`,\n\t\t);\n\t\tlines.push(` ${state.description}`);\n\t}\n\n\treturn lines.join('\\n');\n}\n\nfunction to_setting_item(state: BuiltinExtensionState): SettingItem {\n\tconst detail_lines = [\n\t\tstate.key,\n\t\tstate.description,\n\t\t`current process: ${format_effective_state(state)}`,\n\t\t`startup override: ${state.cli_flag}`,\n\t];\n\n\treturn {\n\t\tid: state.key,\n\t\tlabel: state.label,\n\t\tdescription: detail_lines.join('\\n'),\n\t\tcurrentValue: state.saved_enabled ? ENABLED : DISABLED,\n\t\tvalues: [ENABLED, DISABLED],\n\t};\n}\n\nfunction sets_equal(\n\ta: ReadonlySet<string>,\n\tb: ReadonlySet<string>,\n): boolean {\n\tif (a.size !== b.size) return false;\n\tfor (const value of a) {\n\t\tif (!b.has(value)) return false;\n\t}\n\treturn true;\n}\n\nfunction search_states(\n\tstates: BuiltinExtensionState[],\n\tquery: string,\n): BuiltinExtensionState[] {\n\tconst normalized = query.trim().toLowerCase();\n\tif (!normalized) return states;\n\n\treturn states.filter((state) =>\n\t\t[\n\t\t\tstate.key,\n\t\t\tstate.label,\n\t\t\tstate.description,\n\t\t\t...state.aliases,\n\t\t].some((value) => value.toLowerCase().includes(normalized)),\n\t);\n}\n\nfunction save_extension_enabled(\n\tkey: BuiltinExtensionKey,\n\tenabled: boolean,\n): void {\n\tconst config = load_builtin_extensions_config();\n\tconfig.enabled[key] = enabled;\n\tsave_builtin_extensions_config(config);\n}\n\nexport function create_extensions_extension(\n\toptions: ExtensionsManagerOptions = {},\n) {\n\tconst force_disabled = to_force_disabled_set(\n\t\toptions.force_disabled,\n\t);\n\n\treturn async function extensions(pi: ExtensionAPI) {\n\t\tconst subs = ['list', 'enable', 'disable', 'toggle', 'search'];\n\n\t\tpi.registerCommand('extensions', {\n\t\t\tdescription: 'Manage built-in my-pi extensions',\n\t\t\tgetArgumentCompletions: (prefix) => {\n\t\t\t\tconst parts = prefix.trim().split(/\\s+/);\n\t\t\t\tif (parts.length <= 1) {\n\t\t\t\t\treturn subs\n\t\t\t\t\t\t.filter((sub) => sub.startsWith(parts[0] || ''))\n\t\t\t\t\t\t.map((sub) => ({ value: sub, label: sub }));\n\t\t\t\t}\n\n\t\t\t\tif (['enable', 'disable', 'toggle'].includes(parts[0])) {\n\t\t\t\t\tconst q = parts.slice(1).join(' ').toLowerCase();\n\t\t\t\t\treturn resolve_builtin_extension_states(force_disabled)\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(state) =>\n\t\t\t\t\t\t\t\tstate.key.toLowerCase().includes(q) ||\n\t\t\t\t\t\t\t\tstate.label.toLowerCase().includes(q),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.slice(0, 20)\n\t\t\t\t\t\t.map((state) => ({\n\t\t\t\t\t\t\tvalue: `${parts[0]} ${state.key}`,\n\t\t\t\t\t\t\tlabel: `${state.key} ${state.saved_enabled ? ENABLED : DISABLED}`,\n\t\t\t\t\t\t}));\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\thandler: async (args, ctx) => {\n\t\t\t\tconst trimmed = args.trim();\n\n\t\t\t\tif (!trimmed && ctx.hasUI) {\n\t\t\t\t\tconst states =\n\t\t\t\t\t\tresolve_builtin_extension_states(force_disabled);\n\t\t\t\t\tconst initial_enabled = new Set(\n\t\t\t\t\t\tstates\n\t\t\t\t\t\t\t.filter((state) => state.saved_enabled)\n\t\t\t\t\t\t\t.map((state) => state.key),\n\t\t\t\t\t);\n\t\t\t\t\tconst current_enabled = new Set(initial_enabled);\n\n\t\t\t\t\tawait ctx.ui.custom((tui, theme, _kb, done) => {\n\t\t\t\t\t\tconst items = states.map(to_setting_item);\n\t\t\t\t\t\tconst container = new Container();\n\n\t\t\t\t\t\tcontainer.addChild({\n\t\t\t\t\t\t\trender: () => {\n\t\t\t\t\t\t\t\tconst saved_enabled = current_enabled.size;\n\t\t\t\t\t\t\t\tconst saved_disabled = states.length - saved_enabled;\n\t\t\t\t\t\t\t\tconst enabled_now = [...current_enabled].filter(\n\t\t\t\t\t\t\t\t\t(key) =>\n\t\t\t\t\t\t\t\t\t\t!force_disabled.has(key as BuiltinExtensionKey),\n\t\t\t\t\t\t\t\t).length;\n\t\t\t\t\t\t\t\tconst disabled_now = states.length - enabled_now;\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\t\t'accent',\n\t\t\t\t\t\t\t\t\t\ttheme.bold('Built-in extensions'),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\t\t'muted',\n\t\t\t\t\t\t\t\t\t\t`${saved_enabled} saved enabled • ${saved_disabled} saved disabled • ${enabled_now} enabled now • ${disabled_now} disabled now`,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tinvalidate: () => {},\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst settings_list = new SettingsList(\n\t\t\t\t\t\t\titems,\n\t\t\t\t\t\t\tMath.min(Math.max(items.length + 4, 8), 16),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcursor: theme.fg('accent', '›'),\n\t\t\t\t\t\t\t\tlabel: (text, selected) =>\n\t\t\t\t\t\t\t\t\tselected ? theme.fg('accent', text) : text,\n\t\t\t\t\t\t\t\tvalue: (text, selected) => {\n\t\t\t\t\t\t\t\t\tconst color = text === ENABLED ? 'success' : 'dim';\n\t\t\t\t\t\t\t\t\tconst rendered = theme.fg(color, text);\n\t\t\t\t\t\t\t\t\treturn selected\n\t\t\t\t\t\t\t\t\t\t? theme.bold(theme.fg('accent', rendered))\n\t\t\t\t\t\t\t\t\t\t: rendered;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdescription: (text) => theme.fg('muted', text),\n\t\t\t\t\t\t\t\thint: (text) => theme.fg('dim', text),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t(id, new_value) => {\n\t\t\t\t\t\t\t\tconst key = id as BuiltinExtensionKey;\n\t\t\t\t\t\t\t\tconst enabled = new_value === ENABLED;\n\t\t\t\t\t\t\t\tif (enabled) {\n\t\t\t\t\t\t\t\t\tcurrent_enabled.add(key);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurrent_enabled.delete(key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tsave_extension_enabled(key, enabled);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t() => done(undefined),\n\t\t\t\t\t\t\t{ enableSearch: true },\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tcontainer.addChild(settings_list);\n\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t\t\t'esc close • search filters • changes save immediately • CLI --no-* flags still win in this process',\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\trender(width: number) {\n\t\t\t\t\t\t\t\treturn container.render(width);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tinvalidate() {\n\t\t\t\t\t\t\t\tcontainer.invalidate();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\thandleInput(data: string) {\n\t\t\t\t\t\t\t\tsettings_list.handleInput(data);\n\t\t\t\t\t\t\t\ttui.requestRender();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!sets_equal(initial_enabled, current_enabled)) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\tforce_disabled.size > 0\n\t\t\t\t\t\t\t\t? 'Reloading to apply updated built-in extensions. CLI --no-* flags still force-disable some extensions in this process.'\n\t\t\t\t\t\t\t\t: 'Reloading to apply updated built-in extensions...',\n\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait ctx.reload();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst [sub, ...rest] = (trimmed || 'list').split(/\\s+/);\n\t\t\t\tconst arg = rest.join(' ');\n\t\t\t\tconst states =\n\t\t\t\t\tresolve_builtin_extension_states(force_disabled);\n\n\t\t\t\tswitch (sub) {\n\t\t\t\t\tcase 'list': {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\tformat_extension_lines(states, {\n\t\t\t\t\t\t\t\theading: 'Built-in extensions',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'enable':\n\t\t\t\t\tcase 'disable':\n\t\t\t\t\tcase 'toggle': {\n\t\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`Usage: /extensions ${sub} <key>`,\n\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst extension = find_builtin_extension(arg);\n\t\t\t\t\t\tif (!extension) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`Unknown extension: ${arg}. Use: ${BUILTIN_EXTENSIONS.map((item) => item.key).join(', ')}`,\n\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst current_state = states.find(\n\t\t\t\t\t\t\t(state) => state.key === extension.key,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst next_enabled =\n\t\t\t\t\t\t\tsub === 'enable'\n\t\t\t\t\t\t\t\t? true\n\t\t\t\t\t\t\t\t: sub === 'disable'\n\t\t\t\t\t\t\t\t\t? false\n\t\t\t\t\t\t\t\t\t: !current_state?.saved_enabled;\n\t\t\t\t\t\tsave_extension_enabled(extension.key, next_enabled);\n\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\tnext_enabled && force_disabled.has(extension.key)\n\t\t\t\t\t\t\t\t? `Enabled ${extension.key} in saved config. Still disabled in this process by ${extension.cli_flag}. /reload or restart without that flag to apply.`\n\t\t\t\t\t\t\t\t: `${extension.key} ${next_enabled ? 'enabled' : 'disabled'}. /reload to apply.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'search': {\n\t\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t'Usage: /extensions search <query>',\n\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst results = search_states(states, arg);\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`No built-in extensions matching \"${arg}\"`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\tformat_extension_lines(results, {\n\t\t\t\t\t\t\t\theading: `Built-in extensions matching \"${arg}\"`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Unknown: ${sub}. Use: ${subs.join(', ')}`,\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n\nexport default create_extensions_extension();\n","// Filter-output extension — redact secrets from tool output\n// Patterns from https://github.com/spences10/nopeek\n\nimport type { ExtensionAPI } from '@mariozechner/pi-coding-agent';\n\ninterface SecretPattern {\n\tname: string;\n\tpattern: RegExp;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n\t{ name: 'AWS Access Key', pattern: /AKIA[A-Z0-9]{16}/g },\n\t{\n\t\tname: 'AWS Secret Key',\n\t\tpattern:\n\t\t\t/(?:SecretAccessKey|aws_secret_access_key)\\s*[:=]\\s*[A-Za-z0-9/+=]{40}/g,\n\t},\n\t{\n\t\tname: 'Bearer Token',\n\t\tpattern: /Bearer\\s+[a-zA-Z0-9._-]{20,}/g,\n\t},\n\t{\n\t\tname: 'OpenAI/Anthropic API Key',\n\t\tpattern: /sk-[a-zA-Z0-9._-]{20,}/g,\n\t},\n\t{\n\t\tname: 'Stripe Live Key',\n\t\tpattern: /sk_live_[a-zA-Z0-9]{20,}/g,\n\t},\n\t{\n\t\tname: 'Stripe Test Key',\n\t\tpattern: /sk_test_[a-zA-Z0-9]{20,}/g,\n\t},\n\t{\n\t\tname: 'Hetzner Token',\n\t\tpattern:\n\t\t\t/(?:HCLOUD_TOKEN|hcloud_token|token)\\s*[:=]\\s*[\"']?[a-f0-9]{64}\\b/g,\n\t},\n\t{\n\t\tname: 'Private Key',\n\t\tpattern: /-----BEGIN\\s+[\\w\\s]*PRIVATE\\s+KEY-----/g,\n\t},\n\t{\n\t\tname: 'Connection String with Password',\n\t\tpattern: /:\\/\\/[^:]+:[^@]+@/g,\n\t},\n\t{\n\t\tname: 'Generic Password Field',\n\t\tpattern:\n\t\t\t/(?:password|passwd|secret|token)\\s*[:=]\\s*[\"']?[^\\s\"']{8,}/gi,\n\t},\n\t{\n\t\tname: 'Tavily API Key',\n\t\tpattern: /tvly-[a-zA-Z0-9_-]{20,}/g,\n\t},\n\t{\n\t\tname: 'Kagi API Key',\n\t\tpattern: /[a-zA-Z0-9_-]{40,}\\.[a-zA-Z0-9_-]{40,}/g,\n\t},\n\t{\n\t\tname: 'Brave API Key',\n\t\tpattern: /BSA[A-Z0-9]{20,}/g,\n\t},\n\t{\n\t\tname: 'Firecrawl API Key',\n\t\tpattern: /fc-[a-f0-9]{32}/g,\n\t},\n\t{\n\t\tname: 'GitHub Token',\n\t\tpattern: /gh[pousr]_[a-zA-Z0-9]{36,}/g,\n\t},\n];\n\nfunction redact(text: string): { redacted: string; count: number } {\n\tlet count = 0;\n\tlet result = text;\n\n\tfor (const sp of SECRET_PATTERNS) {\n\t\t// Reset lastIndex for global regexes\n\t\tsp.pattern.lastIndex = 0;\n\t\tresult = result.replace(sp.pattern, (match) => {\n\t\t\tcount++;\n\t\t\tconst prefix = match.slice(0, 4);\n\t\t\treturn `${prefix}${'*'.repeat(Math.min(match.length - 4, 20))}[REDACTED:${sp.name}]`;\n\t\t});\n\t}\n\n\treturn { redacted: result, count };\n}\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function filter_output(pi: ExtensionAPI) {\n\tlet totalRedacted = 0;\n\n\t// Intercept tool results to redact secrets before the LLM sees them\n\tpi.on('tool_result' as const, async (event: any) => {\n\t\tif (!event.content) return;\n\n\t\tlet modified = false;\n\t\tconst newContent = event.content.map(\n\t\t\t(item: { type: string; text?: string }) => {\n\t\t\t\tif (item.type !== 'text' || !item.text) return item;\n\t\t\t\tconst { redacted, count } = redact(item.text);\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tmodified = true;\n\t\t\t\t\ttotalRedacted += count;\n\t\t\t\t}\n\t\t\t\treturn { ...item, text: redacted };\n\t\t\t},\n\t\t);\n\n\t\tif (modified) {\n\t\t\treturn { content: newContent };\n\t\t}\n\t});\n\n\tpi.registerCommand('redact-stats', {\n\t\tdescription: 'Show how many secrets have been redacted',\n\t\thandler: async (_args, ctx) => {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Secrets redacted this session: ${totalRedacted}`,\n\t\t\t);\n\t\t},\n\t});\n}\n","// Handoff extension — extract session context for a new session\n// Inspired by jayshah5696/pi-agent-extensions\n\nimport type { ExtensionAPI } from '@mariozechner/pi-coding-agent';\nimport { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function handoff(pi: ExtensionAPI) {\n\tconst history: Array<{\n\t\trole: string;\n\t\tsummary: string;\n\t\ttimestamp: number;\n\t}> = [];\n\n\t// Track conversation turns\n\tpi.on('message_end', async (event) => {\n\t\tconst msg = event.message as unknown as Record<string, unknown>;\n\t\tif (!msg) return;\n\n\t\tconst content = msg.content as\n\t\t\t| Array<{ type: string; text?: string }>\n\t\t\t| undefined;\n\t\tif (!Array.isArray(content)) return;\n\n\t\tconst text = content\n\t\t\t.filter((c) => c.type === 'text')\n\t\t\t.map((c) => c.text || '')\n\t\t\t.join('\\n');\n\n\t\tif (!text) return;\n\n\t\tconst summary =\n\t\t\ttext.length > 200 ? text.slice(0, 200) + '...' : text;\n\n\t\thistory.push({\n\t\t\trole: (msg.role as string) || 'unknown',\n\t\t\tsummary,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t});\n\n\tpi.registerCommand('handoff', {\n\t\tdescription:\n\t\t\t'Export session context as a handoff prompt for a new session',\n\t\thandler: async (args, ctx) => {\n\t\t\tconst task = args.trim();\n\n\t\t\tif (history.length === 0) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t'No conversation history to hand off',\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst context = history\n\t\t\t\t.map((h) => `[${h.role}] ${h.summary}`)\n\t\t\t\t.join('\\n\\n');\n\n\t\t\tconst handoff = `## Handoff from Previous Session\n\n### Context\nThe previous session covered the following:\n\n${context}\n\n### Task\n${task || 'Continue from where the previous session left off.'}\n\n### Instructions\n- Review the context above to understand what was done\n- Do NOT repeat work that was already completed\n- Focus on the task described above\n`;\n\n\t\t\t// Write to file\n\t\t\tconst filename = `handoff-${Date.now()}.md`;\n\t\t\tconst filepath = join(ctx.cwd, filename);\n\t\t\twriteFileSync(filepath, handoff, 'utf-8');\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Handoff written to ${filename}\\n\\nUse: my-pi < ${filename}`,\n\t\t\t);\n\t\t},\n\t});\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\n\nexport interface McpServerConfig {\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\ninterface JsonRpcRequest {\n\tjsonrpc: '2.0';\n\tid: number;\n\tmethod: string;\n\tparams?: unknown;\n}\n\ninterface JsonRpcResponse {\n\tjsonrpc: '2.0';\n\tid: number;\n\tresult?: unknown;\n\terror?: { code: number; message: string };\n}\n\nexport interface McpToolInfo {\n\tname: string;\n\tdescription?: string;\n\tinputSchema?: Record<string, unknown>;\n}\n\nexport class McpClient {\n\t#proc: ChildProcess | null = null;\n\t#config: McpServerConfig;\n\t#nextId = 1;\n\t#pending = new Map<\n\t\tnumber,\n\t\t{\n\t\t\tresolve: (v: unknown) => void;\n\t\t\treject: (e: Error) => void;\n\t\t}\n\t>();\n\t#buffer = '';\n\n\tconstructor(config: McpServerConfig) {\n\t\tthis.#config = config;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tconst { command, args = [], env } = this.#config;\n\n\t\tthis.#proc = spawn(command, args, {\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t\tenv: { ...process.env, ...env },\n\t\t});\n\n\t\tthis.#proc.stdout!.setEncoding('utf8');\n\t\tthis.#proc.stdout!.on('data', (chunk: string) => {\n\t\t\tthis.#buffer += chunk;\n\t\t\tconst lines = this.#buffer.split('\\n');\n\t\t\tthis.#buffer = lines.pop() || '';\n\n\t\t\tfor (const line of lines) {\n\t\t\t\tif (!line.trim()) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconst msg = JSON.parse(line) as JsonRpcResponse;\n\t\t\t\t\tif (msg.id != null && this.#pending.has(msg.id)) {\n\t\t\t\t\t\tconst p = this.#pending.get(msg.id)!;\n\t\t\t\t\t\tthis.#pending.delete(msg.id);\n\t\t\t\t\t\tif (msg.error) {\n\t\t\t\t\t\t\tp.reject(\n\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t`MCP error ${msg.error.code}: ${msg.error.message}`,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tp.resolve(msg.result);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore non-JSON lines\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// Initialize handshake\n\t\tawait this.#request('initialize', {\n\t\t\tprotocolVersion: '2024-11-05',\n\t\t\tcapabilities: {},\n\t\t\tclientInfo: { name: 'my-pi', version: '0.0.1' },\n\t\t});\n\n\t\t// Send initialized notification (no response expected)\n\t\tthis.#send({\n\t\t\tjsonrpc: '2.0',\n\t\t\tmethod: 'notifications/initialized',\n\t\t} as unknown as JsonRpcRequest);\n\t}\n\n\tasync listTools(): Promise<McpToolInfo[]> {\n\t\tconst result = (await this.#request('tools/list', {})) as {\n\t\t\ttools: McpToolInfo[];\n\t\t};\n\t\treturn result.tools;\n\t}\n\n\tasync callTool(\n\t\tname: string,\n\t\targs: Record<string, unknown>,\n\t): Promise<unknown> {\n\t\treturn this.#request('tools/call', {\n\t\t\tname,\n\t\t\targuments: args,\n\t\t});\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.#proc) {\n\t\t\tthis.#proc.kill();\n\t\t\tthis.#proc = null;\n\t\t}\n\t\tthis.#pending.clear();\n\t}\n\n\t#request(method: string, params: unknown): Promise<unknown> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst id = this.#nextId++;\n\t\t\tthis.#pending.set(id, { resolve, reject });\n\t\t\tthis.#send({ jsonrpc: '2.0', id, method, params });\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (this.#pending.has(id)) {\n\t\t\t\t\tthis.#pending.delete(id);\n\t\t\t\t\treject(new Error(`MCP request ${method} timed out`));\n\t\t\t\t}\n\t\t\t}, 30_000);\n\t\t});\n\t}\n\n\t#send(msg: JsonRpcRequest) {\n\t\tif (!this.#proc?.stdin?.writable) {\n\t\t\tthrow new Error('MCP server not connected');\n\t\t}\n\t\tthis.#proc.stdin.write(JSON.stringify(msg) + '\\n');\n\t}\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { McpServerConfig } from './client.js';\n\ninterface McpConfigFile {\n\tmcpServers: Record<\n\t\tstring,\n\t\t{\n\t\t\tcommand: string;\n\t\t\targs?: string[];\n\t\t\tenv?: Record<string, string>;\n\t\t}\n\t>;\n}\n\nfunction read_config(path: string): McpConfigFile['mcpServers'] {\n\tif (!existsSync(path)) return {};\n\tconst raw = readFileSync(path, 'utf-8');\n\tconst config = JSON.parse(raw) as McpConfigFile;\n\treturn config.mcpServers || {};\n}\n\nexport function load_mcp_config(cwd: string): McpServerConfig[] {\n\t// Global: ~/.pi/agent/mcp.json\n\tconst global_servers = read_config(\n\t\tjoin(homedir(), '.pi', 'agent', 'mcp.json'),\n\t);\n\n\t// Project: ./mcp.json (overrides global by name)\n\tconst project_servers = read_config(join(cwd, 'mcp.json'));\n\n\tconst merged = { ...global_servers, ...project_servers };\n\n\treturn Object.entries(merged).map(([name, server]) => ({\n\t\tname,\n\t\tcommand: server.command,\n\t\targs: server.args,\n\t\tenv: server.env,\n\t}));\n}\n","import {\n\ttype ExtensionAPI,\n\tdefineTool,\n} from '@mariozechner/pi-coding-agent';\nimport { McpClient, type McpServerConfig } from '../mcp/client.js';\nimport { load_mcp_config } from '../mcp/config.js';\n\ninterface ServerState {\n\tconfig: McpServerConfig;\n\tclient: McpClient;\n\ttool_names: string[];\n\tenabled: boolean;\n}\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function mcp(pi: ExtensionAPI) {\n\tconst cwd = process.cwd();\n\tconst servers = new Map<string, ServerState>();\n\tconst configs = load_mcp_config(cwd);\n\n\t// Connect all MCP servers in parallel for faster startup\n\tconst results = await Promise.allSettled(\n\t\tconfigs.map(async (config) => {\n\t\t\tconst client = new McpClient(config);\n\t\t\tawait client.connect();\n\t\t\tconst mcp_tools = await client.listTools();\n\t\t\treturn { config, client, mcp_tools };\n\t\t}),\n\t);\n\n\tfor (const result of results) {\n\t\tif (result.status === 'rejected') {\n\t\t\tconsole.error(`MCP server failed: ${result.reason}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { config, client, mcp_tools } = result.value;\n\t\tconst tool_names: string[] = [];\n\n\t\tfor (const mcp_tool of mcp_tools) {\n\t\t\tconst tool_name = `mcp__${config.name}__${mcp_tool.name}`;\n\t\t\ttool_names.push(tool_name);\n\n\t\t\tpi.registerTool(\n\t\t\t\tdefineTool({\n\t\t\t\t\tname: tool_name,\n\t\t\t\t\tlabel: `${config.name}: ${mcp_tool.name}`,\n\t\t\t\t\tdescription: mcp_tool.description || mcp_tool.name,\n\t\t\t\t\tparameters: (mcp_tool.inputSchema || {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: {},\n\t\t\t\t\t}) as Parameters<typeof defineTool>[0]['parameters'],\n\t\t\t\t\texecute: async (_id, params) => {\n\t\t\t\t\t\tconst result = (await client.callTool(\n\t\t\t\t\t\t\tmcp_tool.name,\n\t\t\t\t\t\t\tparams as Record<string, unknown>,\n\t\t\t\t\t\t)) as {\n\t\t\t\t\t\t\tcontent?: Array<{\n\t\t\t\t\t\t\t\ttype: string;\n\t\t\t\t\t\t\t\ttext?: string;\n\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst text =\n\t\t\t\t\t\t\tresult?.content?.map((c) => c.text || '').join('\\n') ||\n\t\t\t\t\t\t\tJSON.stringify(result);\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: 'text' as const, text }],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tservers.set(config.name, {\n\t\t\tconfig,\n\t\t\tclient,\n\t\t\ttool_names,\n\t\t\tenabled: true,\n\t\t});\n\t}\n\n\tpi.registerCommand('mcp', {\n\t\tdescription: 'Manage MCP servers (list, enable, disable)',\n\t\tgetArgumentCompletions: (prefix) => {\n\t\t\tconst parts = prefix.split(' ');\n\t\t\tif (parts.length <= 1) {\n\t\t\t\treturn ['list', 'enable', 'disable']\n\t\t\t\t\t.filter((s) => s.startsWith(prefix))\n\t\t\t\t\t.map((s) => ({ value: s, label: s }));\n\t\t\t}\n\t\t\tif (parts[0] === 'enable' || parts[0] === 'disable') {\n\t\t\t\tconst name_prefix = parts[1] || '';\n\t\t\t\treturn Array.from(servers.keys())\n\t\t\t\t\t.filter((n) => n.startsWith(name_prefix))\n\t\t\t\t\t.map((n) => ({\n\t\t\t\t\t\tvalue: `${parts[0]} ${n}`,\n\t\t\t\t\t\tlabel: n,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tconst [sub, ...rest] = args.trim().split(/\\s+/);\n\t\t\tconst name = rest.join(' ');\n\n\t\t\tswitch (sub || 'list') {\n\t\t\t\tcase 'list': {\n\t\t\t\t\tif (servers.size === 0) {\n\t\t\t\t\t\tctx.ui.notify('No MCP servers configured');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst lines: string[] = [];\n\t\t\t\t\tfor (const [sname, state] of servers.entries()) {\n\t\t\t\t\t\tconst status = state.enabled ? 'enabled' : 'disabled';\n\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t`${sname} (${status}) — ${state.tool_names.length} tools`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tctx.ui.notify(lines.join('\\n'));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'enable': {\n\t\t\t\t\tconst server = servers.get(name);\n\t\t\t\t\tif (!server) {\n\t\t\t\t\t\tctx.ui.notify(`Unknown server: ${name}`, 'warning');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (server.enabled) {\n\t\t\t\t\t\tctx.ui.notify(`${name} already enabled`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tserver.enabled = true;\n\t\t\t\t\tconst active = pi.getActiveTools();\n\t\t\t\t\tpi.setActiveTools([...active, ...server.tool_names]);\n\t\t\t\t\tctx.ui.notify(`Enabled ${name}`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'disable': {\n\t\t\t\t\tconst server = servers.get(name);\n\t\t\t\t\tif (!server) {\n\t\t\t\t\t\tctx.ui.notify(`Unknown server: ${name}`, 'warning');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!server.enabled) {\n\t\t\t\t\t\tctx.ui.notify(`${name} already disabled`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tserver.enabled = false;\n\t\t\t\t\tconst tool_set = new Set(server.tool_names);\n\t\t\t\t\tpi.setActiveTools(\n\t\t\t\t\t\tpi.getActiveTools().filter((t) => !tool_set.has(t)),\n\t\t\t\t\t);\n\t\t\t\t\tctx.ui.notify(`Disabled ${name}`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`Unknown subcommand: ${sub}. Use list, enable, or disable.`,\n\t\t\t\t\t\t'warning',\n\t\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.on('session_shutdown', async () => {\n\t\tfor (const server of servers.values()) {\n\t\t\tawait server.client.disconnect();\n\t\t}\n\t});\n}\n","// Recall extension — nudge the agent to use pirecall for past session context\n// The model uses `npx pirecall` via bash directly — no custom tools needed\n\nimport type { ExtensionAPI } from '@mariozechner/pi-coding-agent';\nimport { execFileSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst DEFAULT_DB_PATH = join(process.env.HOME!, '.pi', 'pirecall.db');\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function recall(pi: ExtensionAPI) {\n\t// Sync on startup if db exists\n\tif (existsSync(DEFAULT_DB_PATH)) {\n\t\ttry {\n\t\t\texecFileSync('npx', ['pirecall', 'sync', '--json'], {\n\t\t\t\tencoding: 'utf-8',\n\t\t\t\ttimeout: 30_000,\n\t\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t\t});\n\t\t} catch {\n\t\t\t// Non-critical — db may just not have new data\n\t\t}\n\t}\n\n\t// System prompt hint so the model knows pirecall exists\n\tpi.on(\n\t\t'before_agent_start',\n\t\tasync (event: { systemPrompt: string }) => {\n\t\t\treturn {\n\t\t\t\tsystemPrompt:\n\t\t\t\t\tevent.systemPrompt +\n\t\t\t\t\t`\n\n## Session Recall\n\nYou have access to past Pi session history via \\`npx pirecall\\`. Use it when:\n- The user references prior work (\"what did we do\", \"last time\", \"remember when\")\n- You need context from a previous session about this project\n- You want to avoid repeating work already done\n\nQuick reference:\n- \\`npx pirecall recall \"<query>\" --json\\` — LLM-optimised context retrieval with surrounding messages\n- \\`npx pirecall search \"<query>\" --json\\` — full-text search (supports FTS5: AND, OR, NOT, \"phrase\", prefix*)\n- \\`npx pirecall search \"<query>\" --json --project my-pi\\` — filter by project\n- \\`npx pirecall search \"<query>\" --json --after 2026-04-10\\` — filter by date\n- \\`npx pirecall sessions --json\\` — list recent sessions\n- \\`npx pirecall stats --json\\` — database statistics\n\nAlways pass \\`--json\\` for structured output.`,\n\t\t\t};\n\t\t},\n\t);\n}\n","import {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\trenameSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport interface SkillsConfig {\n\tversion: number;\n\tenabled: Record<string, boolean>;\n\tdefaults: 'all-enabled' | 'all-disabled';\n}\n\nconst DEFAULT_CONFIG: SkillsConfig = {\n\tversion: 1,\n\tenabled: {},\n\tdefaults: 'all-disabled',\n};\n\nexport function get_config_path(): string {\n\tconst xdg =\n\t\tprocess.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n\treturn join(xdg, 'my-pi', 'skills.json');\n}\n\nexport function load_skills_config(): SkillsConfig {\n\tconst path = get_config_path();\n\tif (!existsSync(path)) return { ...DEFAULT_CONFIG };\n\n\ttry {\n\t\tconst raw = readFileSync(path, 'utf-8');\n\t\tconst parsed = JSON.parse(raw) as Partial<SkillsConfig>;\n\t\treturn {\n\t\t\tversion: parsed.version ?? 1,\n\t\t\tenabled: parsed.enabled ?? {},\n\t\t\tdefaults: parsed.defaults ?? 'all-enabled',\n\t\t};\n\t} catch {\n\t\treturn { ...DEFAULT_CONFIG };\n\t}\n}\n\nexport function save_skills_config(config: SkillsConfig): void {\n\tconst path = get_config_path();\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(tmp, JSON.stringify(config, null, '\\t') + '\\n', {\n\t\tmode: 0o600,\n\t});\n\trenameSync(tmp, path);\n}\n\nexport function make_skill_key(name: string, source: string): string {\n\treturn `${name}@${source}`;\n}\n\nexport function is_skill_enabled(\n\tconfig: SkillsConfig,\n\tkey: string,\n): boolean {\n\tif (key in config.enabled) return config.enabled[key];\n\treturn config.defaults === 'all-enabled';\n}\n","import {\n\tparseFrontmatter,\n\ttype SkillFrontmatter,\n} from '@mariozechner/pi-coding-agent';\nimport { existsSync, globSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { basename, dirname, join, resolve } from 'node:path';\n\nexport const IMPORT_METADATA_FILE = '.my-pi-source.json';\n\nexport interface InstalledPlugin {\n\tscope: string;\n\tinstallPath: string;\n\tversion: string;\n\tinstalledAt?: string;\n\tlastUpdated?: string;\n\tgitCommitSha?: string;\n}\n\ninterface InstalledPluginsFile {\n\tversion: number;\n\tplugins: Record<string, InstalledPlugin[]>;\n}\n\nexport interface ImportedSkillMetadata {\n\tversion: number;\n\tsource: string;\n\tupstream_skill_path: string;\n\tupstream_base_dir: string;\n\tupstream_install_path?: string;\n\tupstream_version?: string;\n\tupstream_git_commit_sha?: string;\n\timported_at: string;\n\tlast_synced_at: string;\n\timported_hash: string;\n\tupstream_hash: string;\n}\n\nexport interface PluginSkillSource {\n\tpluginId: string;\n\tinstallPath: string;\n\tversion: string;\n\tgitCommitSha?: string;\n}\n\nexport interface DiscoveredSkill {\n\tname: string;\n\tdescription: string;\n\tskillPath: string;\n\tbaseDir: string;\n\tsource: string;\n\tkind: 'managed' | 'external';\n\tplugin?: PluginSkillSource;\n\timport_meta?: ImportedSkillMetadata;\n}\n\nfunction read_installed_plugins(): InstalledPluginsFile | null {\n\tconst path = join(\n\t\thomedir(),\n\t\t'.claude',\n\t\t'plugins',\n\t\t'installed_plugins.json',\n\t);\n\tif (!existsSync(path)) return null;\n\n\ttry {\n\t\treturn JSON.parse(\n\t\t\treadFileSync(path, 'utf-8'),\n\t\t) as InstalledPluginsFile;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction parse_skill_md(\n\tskill_path: string,\n): { name: string; description: string } | null {\n\ttry {\n\t\tconst content = readFileSync(skill_path, 'utf-8');\n\t\tconst { frontmatter } =\n\t\t\tparseFrontmatter<SkillFrontmatter>(content);\n\t\tconst description = frontmatter?.description;\n\t\tif (!description) return null;\n\n\t\tconst name = frontmatter?.name || basename(dirname(skill_path));\n\t\treturn { name, description: description.trim() };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction read_import_metadata(\n\tbase_dir: string,\n): ImportedSkillMetadata | undefined {\n\tconst metadata_path = join(base_dir, IMPORT_METADATA_FILE);\n\tif (!existsSync(metadata_path)) return undefined;\n\n\ttry {\n\t\treturn JSON.parse(\n\t\t\treadFileSync(metadata_path, 'utf-8'),\n\t\t) as ImportedSkillMetadata;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction scan_dir_for_skills(\n\tdir: string,\n\toptions: {\n\t\tsource: string;\n\t\tkind: 'managed' | 'external';\n\t\tplugin?: PluginSkillSource;\n\t\tinclude_direct_root_skill?: boolean;\n\t},\n): DiscoveredSkill[] {\n\tif (!existsSync(dir)) return [];\n\n\tconst results: DiscoveredSkill[] = [];\n\tconst direct = join(dir, 'SKILL.md');\n\tconst include_direct_root_skill =\n\t\toptions.include_direct_root_skill ?? true;\n\n\tif (include_direct_root_skill && existsSync(direct)) {\n\t\tconst parsed = parse_skill_md(direct);\n\t\tif (parsed) {\n\t\t\tresults.push({\n\t\t\t\t...parsed,\n\t\t\t\tskillPath: direct,\n\t\t\t\tbaseDir: dir,\n\t\t\t\tsource: options.source,\n\t\t\t\tkind: options.kind,\n\t\t\t\tplugin: options.plugin,\n\t\t\t\timport_meta:\n\t\t\t\t\toptions.kind === 'managed'\n\t\t\t\t\t\t? read_import_metadata(dir)\n\t\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\ttry {\n\t\tconst matches = globSync('*/SKILL.md', { cwd: dir });\n\t\tfor (const match of matches) {\n\t\t\tconst full_path = resolve(dir, match);\n\t\t\tconst parsed = parse_skill_md(full_path);\n\t\t\tif (parsed) {\n\t\t\t\tconst base_dir = dirname(full_path);\n\t\t\t\tresults.push({\n\t\t\t\t\t...parsed,\n\t\t\t\t\tskillPath: full_path,\n\t\t\t\t\tbaseDir: base_dir,\n\t\t\t\t\tsource: options.source,\n\t\t\t\t\tkind: options.kind,\n\t\t\t\t\tplugin: options.plugin,\n\t\t\t\t\timport_meta:\n\t\t\t\t\t\toptions.kind === 'managed'\n\t\t\t\t\t\t\t? read_import_metadata(base_dir)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// skip inaccessible dirs\n\t}\n\n\treturn results;\n}\n\nfunction dedupe_by_skill_path(\n\tskills: DiscoveredSkill[],\n): DiscoveredSkill[] {\n\tconst seen = new Set<string>();\n\tconst deduped: DiscoveredSkill[] = [];\n\n\tfor (const skill of skills) {\n\t\tif (seen.has(skill.skillPath)) continue;\n\t\tseen.add(skill.skillPath);\n\t\tdeduped.push(skill);\n\t}\n\n\treturn deduped;\n}\n\nexport function scan_managed_skills(): DiscoveredSkill[] {\n\tconst skills: DiscoveredSkill[] = [];\n\n\tfor (const skill of scan_dir_for_skills(\n\t\tjoin(homedir(), '.claude', 'skills'),\n\t\t{\n\t\t\tsource: 'user-local',\n\t\t\tkind: 'managed',\n\t\t},\n\t)) {\n\t\tskills.push(skill);\n\t}\n\n\tfor (const skill of scan_dir_for_skills(\n\t\tjoin(homedir(), '.pi', 'agent', 'skills'),\n\t\t{\n\t\t\tsource: 'pi-native',\n\t\t\tkind: 'managed',\n\t\t\tinclude_direct_root_skill: false,\n\t\t},\n\t)) {\n\t\tskills.push(skill);\n\t}\n\n\treturn dedupe_by_skill_path(skills);\n}\n\nexport function scan_importable_skills(): DiscoveredSkill[] {\n\tconst skills: DiscoveredSkill[] = [];\n\tconst plugins = read_installed_plugins();\n\tif (!plugins?.plugins) return skills;\n\n\tfor (const [plugin_id, entries] of Object.entries(\n\t\tplugins.plugins,\n\t)) {\n\t\tconst entry = entries[0];\n\t\tif (!entry?.installPath || !existsSync(entry.installPath))\n\t\t\tcontinue;\n\n\t\tconst source = `plugin:${plugin_id}`;\n\t\tconst plugin: PluginSkillSource = {\n\t\t\tpluginId: plugin_id,\n\t\t\tinstallPath: entry.installPath,\n\t\t\tversion: entry.version,\n\t\t\tgitCommitSha: entry.gitCommitSha,\n\t\t};\n\n\t\tfor (const skill of scan_dir_for_skills(\n\t\t\tjoin(entry.installPath, 'skills'),\n\t\t\t{\n\t\t\t\tsource,\n\t\t\t\tkind: 'external',\n\t\t\t\tplugin,\n\t\t\t},\n\t\t)) {\n\t\t\tskills.push(skill);\n\t\t}\n\n\t\tfor (const skill of scan_dir_for_skills(\n\t\t\tjoin(entry.installPath, '.pi', 'skills'),\n\t\t\t{\n\t\t\t\tsource,\n\t\t\t\tkind: 'external',\n\t\t\t\tplugin,\n\t\t\t},\n\t\t)) {\n\t\t\tskills.push(skill);\n\t\t}\n\n\t\tconst direct_root_skill = join(entry.installPath, 'SKILL.md');\n\t\tif (existsSync(direct_root_skill)) {\n\t\t\tconst parsed = parse_skill_md(direct_root_skill);\n\t\t\tif (parsed) {\n\t\t\t\tskills.push({\n\t\t\t\t\t...parsed,\n\t\t\t\t\tskillPath: direct_root_skill,\n\t\t\t\t\tbaseDir: entry.installPath,\n\t\t\t\t\tsource,\n\t\t\t\t\tkind: 'external',\n\t\t\t\t\tplugin,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dedupe_by_skill_path(skills);\n}\n\nexport function scan_all_skills(): DiscoveredSkill[] {\n\treturn [...scan_managed_skills(), ...scan_importable_skills()];\n}\n","import { createHash } from 'node:crypto';\nimport {\n\tcpSync,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trmSync,\n\tstatSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport {\n\tIMPORT_METADATA_FILE,\n\ttype DiscoveredSkill,\n\ttype ImportedSkillMetadata,\n} from './scanner.js';\n\nconst IMPORT_METADATA_VERSION = 1;\n\nfunction get_managed_skills_dir(): string {\n\treturn join(homedir(), '.pi', 'agent', 'skills');\n}\n\nfunction ensure_dir(path: string): void {\n\tmkdirSync(path, { recursive: true, mode: 0o700 });\n}\n\nfunction list_files_recursively(dir: string): string[] {\n\tconst files: string[] = [];\n\n\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\tconst full_path = join(dir, entry.name);\n\t\tif (entry.name === IMPORT_METADATA_FILE) continue;\n\t\tif (entry.isDirectory()) {\n\t\t\tfiles.push(...list_files_recursively(full_path));\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.isFile()) {\n\t\t\tfiles.push(full_path);\n\t\t}\n\t}\n\n\treturn files.sort((a, b) => a.localeCompare(b));\n}\n\nfunction hash_directory(dir: string): string {\n\tconst hash = createHash('sha256');\n\tfor (const file of list_files_recursively(dir)) {\n\t\thash.update(relative(dir, file));\n\t\thash.update('\\0');\n\t\thash.update(readFileSync(file));\n\t\thash.update('\\0');\n\t}\n\treturn hash.digest('hex');\n}\n\nfunction read_metadata(\n\tbase_dir: string,\n): ImportedSkillMetadata | undefined {\n\tconst path = join(base_dir, IMPORT_METADATA_FILE);\n\tif (!existsSync(path)) return undefined;\n\n\ttry {\n\t\treturn JSON.parse(\n\t\t\treadFileSync(path, 'utf-8'),\n\t\t) as ImportedSkillMetadata;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction write_metadata(\n\tbase_dir: string,\n\tmetadata: ImportedSkillMetadata,\n): void {\n\twriteFileSync(\n\t\tjoin(base_dir, IMPORT_METADATA_FILE),\n\t\tJSON.stringify(metadata, null, '\\t') + '\\n',\n\t\t{ mode: 0o600 },\n\t);\n}\n\nfunction replace_directory(\n\tsource_dir: string,\n\tdest_dir: string,\n): void {\n\tconst parent_dir = dirname(dest_dir);\n\tensure_dir(parent_dir);\n\tconst tmp_dir = join(\n\t\tparent_dir,\n\t\t`.${resolve(dest_dir).split('/').pop()}.tmp-${Date.now()}`,\n\t);\n\n\trmSync(tmp_dir, { recursive: true, force: true });\n\tcpSync(source_dir, tmp_dir, {\n\t\trecursive: true,\n\t\tpreserveTimestamps: true,\n\t\tverbatimSymlinks: false,\n\t});\n\trmSync(dest_dir, { recursive: true, force: true });\n\tcpSync(tmp_dir, dest_dir, {\n\t\trecursive: true,\n\t\tpreserveTimestamps: true,\n\t\tverbatimSymlinks: false,\n\t});\n\trmSync(tmp_dir, { recursive: true, force: true });\n}\n\nexport interface ImportSkillResult {\n\tskillDir: string;\n\tmetadata: ImportedSkillMetadata;\n}\n\nexport function import_external_skill(\n\tskill: DiscoveredSkill,\n): ImportSkillResult {\n\tif (skill.kind !== 'external') {\n\t\tthrow new Error(`Skill ${skill.name} is not importable`);\n\t}\n\n\tconst managed_root = get_managed_skills_dir();\n\tensure_dir(managed_root);\n\n\tconst skill_dir = join(managed_root, skill.name);\n\tconst existing = existsSync(skill_dir);\n\tif (existing) {\n\t\tconst existing_stat = statSync(skill_dir);\n\t\tif (!existing_stat.isDirectory()) {\n\t\t\tthrow new Error(`${skill_dir} exists and is not a directory`);\n\t\t}\n\n\t\tconst existing_metadata = read_metadata(skill_dir);\n\t\tif (!existing_metadata) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to overwrite existing unmanaged skill at ${skill_dir}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treplace_directory(skill.baseDir, skill_dir);\n\n\tconst upstream_hash = hash_directory(skill.baseDir);\n\tconst imported_hash = hash_directory(skill_dir);\n\tconst now = new Date().toISOString();\n\tconst metadata: ImportedSkillMetadata = {\n\t\tversion: IMPORT_METADATA_VERSION,\n\t\tsource: skill.source,\n\t\tupstream_skill_path: skill.skillPath,\n\t\tupstream_base_dir: skill.baseDir,\n\t\tupstream_install_path: skill.plugin?.installPath,\n\t\tupstream_version: skill.plugin?.version,\n\t\tupstream_git_commit_sha: skill.plugin?.gitCommitSha,\n\t\timported_at: now,\n\t\tlast_synced_at: now,\n\t\timported_hash,\n\t\tupstream_hash,\n\t};\n\n\twrite_metadata(skill_dir, metadata);\n\treturn {\n\t\tskillDir: skill_dir,\n\t\tmetadata,\n\t};\n}\n\nexport interface SyncSkillResult {\n\tskillDir: string;\n\tmetadata: ImportedSkillMetadata;\n\tchanged: boolean;\n}\n\nexport function sync_imported_skill(\n\tskill: DiscoveredSkill,\n): SyncSkillResult {\n\tif (skill.kind !== 'managed' || !skill.import_meta) {\n\t\tthrow new Error(\n\t\t\t`Skill ${skill.name} is not managed by my-pi sync`,\n\t\t);\n\t}\n\n\tconst metadata = skill.import_meta;\n\tif (!existsSync(metadata.upstream_base_dir)) {\n\t\tthrow new Error(\n\t\t\t`Upstream source no longer exists: ${metadata.upstream_base_dir}`,\n\t\t);\n\t}\n\n\tconst current_hash = hash_directory(skill.baseDir);\n\tif (current_hash !== metadata.imported_hash) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync ${skill.name}; local changes detected in ${skill.baseDir}`,\n\t\t);\n\t}\n\n\tconst upstream_hash = hash_directory(metadata.upstream_base_dir);\n\tif (upstream_hash === metadata.upstream_hash) {\n\t\treturn {\n\t\t\tskillDir: skill.baseDir,\n\t\t\tmetadata,\n\t\t\tchanged: false,\n\t\t};\n\t}\n\n\treplace_directory(metadata.upstream_base_dir, skill.baseDir);\n\tconst imported_hash = hash_directory(skill.baseDir);\n\tconst updated: ImportedSkillMetadata = {\n\t\t...metadata,\n\t\tlast_synced_at: new Date().toISOString(),\n\t\timported_hash,\n\t\tupstream_hash,\n\t};\n\twrite_metadata(skill.baseDir, updated);\n\n\treturn {\n\t\tskillDir: skill.baseDir,\n\t\tmetadata: updated,\n\t\tchanged: true,\n\t};\n}\n","import {\n\ttype SkillsConfig,\n\tis_skill_enabled,\n\tload_skills_config,\n\tmake_skill_key,\n\tsave_skills_config,\n} from './config.js';\nimport {\n\ttype ImportSkillResult,\n\ttype SyncSkillResult,\n\timport_external_skill,\n\tsync_imported_skill,\n} from './importer.js';\nimport {\n\ttype DiscoveredSkill,\n\tscan_importable_skills,\n\tscan_managed_skills,\n} from './scanner.js';\n\nexport interface ManagedSkill extends DiscoveredSkill {\n\tkey: string;\n\tenabled: boolean;\n}\n\nexport interface SkillsManager {\n\tdiscover(): ManagedSkill[];\n\tdiscover_importable(): ManagedSkill[];\n\tget_enabled_skill_paths(): string[];\n\t/** Check if a skill should pass through pi's skillsOverride */\n\tis_enabled_by_skill(name: string, filePath: string): boolean;\n\tenable(key: string): boolean;\n\tdisable(key: string): boolean;\n\ttoggle(key: string): boolean;\n\tsearch(query: string): ManagedSkill[];\n\tsearch_importable(query: string): ManagedSkill[];\n\tset_defaults(policy: 'all-enabled' | 'all-disabled'): void;\n\timport_skill(\n\t\tkey_or_name: string,\n\t): ImportSkillResult & { key: string };\n\tsync_skill(key_or_name: string): SyncSkillResult & { key: string };\n\trefresh(): void;\n}\n\nfunction resolve_skill_key(skill: DiscoveredSkill): string {\n\treturn make_skill_key(skill.name, skill.source);\n}\n\nfunction match_skill_by_key_or_name(\n\tskills: DiscoveredSkill[],\n\tkey_or_name: string,\n): DiscoveredSkill {\n\tconst exact_key = skills.find(\n\t\t(skill) => resolve_skill_key(skill) === key_or_name,\n\t);\n\tif (exact_key) return exact_key;\n\n\tconst by_name = skills.filter(\n\t\t(skill) => skill.name === key_or_name,\n\t);\n\tif (by_name.length === 1) {\n\t\treturn by_name[0]!;\n\t}\n\tif (by_name.length > 1) {\n\t\tthrow new Error(\n\t\t\t`Multiple skills named ${key_or_name}. Use an exact key instead.`,\n\t\t);\n\t}\n\n\tthrow new Error(`Unknown skill: ${key_or_name}`);\n}\n\nexport function create_skills_manager(): SkillsManager {\n\tlet config: SkillsConfig = load_skills_config();\n\tlet managed_cache: DiscoveredSkill[] | null = null;\n\tlet importable_cache: DiscoveredSkill[] | null = null;\n\n\tfunction get_managed(): DiscoveredSkill[] {\n\t\tif (!managed_cache) {\n\t\t\tmanaged_cache = scan_managed_skills();\n\t\t}\n\t\treturn managed_cache;\n\t}\n\n\tfunction get_importable(): DiscoveredSkill[] {\n\t\tif (!importable_cache) {\n\t\t\timportable_cache = scan_importable_skills();\n\t\t}\n\t\treturn importable_cache;\n\t}\n\n\tfunction to_managed(skill: DiscoveredSkill): ManagedSkill {\n\t\tconst key = resolve_skill_key(skill);\n\t\treturn {\n\t\t\t...skill,\n\t\t\tkey,\n\t\t\tenabled:\n\t\t\t\tskill.kind === 'managed'\n\t\t\t\t\t? is_skill_enabled(config, key)\n\t\t\t\t\t: false,\n\t\t};\n\t}\n\n\tfunction get_enabled_managed_skills(): ManagedSkill[] {\n\t\treturn get_managed()\n\t\t\t.filter((skill) =>\n\t\t\t\tis_skill_enabled(config, resolve_skill_key(skill)),\n\t\t\t)\n\t\t\t.map(to_managed);\n\t}\n\n\treturn {\n\t\tdiscover(): ManagedSkill[] {\n\t\t\treturn get_managed().map(to_managed);\n\t\t},\n\n\t\tdiscover_importable(): ManagedSkill[] {\n\t\t\treturn get_importable().map(to_managed);\n\t\t},\n\n\t\tis_enabled_by_skill(name: string, filePath: string): boolean {\n\t\t\tconst discovered = get_managed();\n\t\t\tconst match = discovered.find((s) => s.skillPath === filePath);\n\t\t\tif (match) {\n\t\t\t\treturn is_skill_enabled(config, resolve_skill_key(match));\n\t\t\t}\n\n\t\t\tconst by_name = discovered.find((s) => s.name === name);\n\t\t\tif (by_name) {\n\t\t\t\treturn is_skill_enabled(config, resolve_skill_key(by_name));\n\t\t\t}\n\n\t\t\t// Unknown skill sources should remain enabled so pi's native\n\t\t\t// discovery keeps working for project and other default locations.\n\t\t\treturn true;\n\t\t},\n\n\t\tget_enabled_skill_paths(): string[] {\n\t\t\treturn get_enabled_managed_skills().map(\n\t\t\t\t(skill) => skill.baseDir,\n\t\t\t);\n\t\t},\n\n\t\tenable(key: string): boolean {\n\t\t\tconfig.enabled[key] = true;\n\t\t\tsave_skills_config(config);\n\t\t\treturn true;\n\t\t},\n\n\t\tdisable(key: string): boolean {\n\t\t\tconfig.enabled[key] = false;\n\t\t\tsave_skills_config(config);\n\t\t\treturn false;\n\t\t},\n\n\t\ttoggle(key: string): boolean {\n\t\t\tconst current = is_skill_enabled(config, key);\n\t\t\tconfig.enabled[key] = !current;\n\t\t\tsave_skills_config(config);\n\t\t\treturn !current;\n\t\t},\n\n\t\tsearch(query: string): ManagedSkill[] {\n\t\t\tconst q = query.toLowerCase();\n\t\t\treturn this.discover().filter(\n\t\t\t\t(s) =>\n\t\t\t\t\ts.name.toLowerCase().includes(q) ||\n\t\t\t\t\ts.description.toLowerCase().includes(q) ||\n\t\t\t\t\ts.source.toLowerCase().includes(q),\n\t\t\t);\n\t\t},\n\n\t\tsearch_importable(query: string): ManagedSkill[] {\n\t\t\tconst q = query.toLowerCase();\n\t\t\treturn this.discover_importable().filter(\n\t\t\t\t(s) =>\n\t\t\t\t\ts.name.toLowerCase().includes(q) ||\n\t\t\t\t\ts.description.toLowerCase().includes(q) ||\n\t\t\t\t\ts.source.toLowerCase().includes(q),\n\t\t\t);\n\t\t},\n\n\t\tset_defaults(policy: 'all-enabled' | 'all-disabled'): void {\n\t\t\tconfig.defaults = policy;\n\t\t\tsave_skills_config(config);\n\t\t},\n\n\t\timport_skill(key_or_name: string) {\n\t\t\tconst skill = match_skill_by_key_or_name(\n\t\t\t\tget_importable(),\n\t\t\t\tkey_or_name,\n\t\t\t);\n\t\t\tconst result = import_external_skill(skill);\n\t\t\tconst managed_key = make_skill_key(skill.name, 'pi-native');\n\t\t\tconfig.enabled[managed_key] = true;\n\t\t\tsave_skills_config(config);\n\t\t\tthis.refresh();\n\t\t\treturn {\n\t\t\t\t...result,\n\t\t\t\tkey: managed_key,\n\t\t\t};\n\t\t},\n\n\t\tsync_skill(key_or_name: string) {\n\t\t\tconst skill = match_skill_by_key_or_name(\n\t\t\t\tget_managed(),\n\t\t\t\tkey_or_name,\n\t\t\t);\n\t\t\tconst result = sync_imported_skill(skill);\n\t\t\tthis.refresh();\n\t\t\treturn {\n\t\t\t\t...result,\n\t\t\t\tkey: resolve_skill_key(skill),\n\t\t\t};\n\t\t},\n\n\t\trefresh(): void {\n\t\t\tmanaged_cache = null;\n\t\t\timportable_cache = null;\n\t\t\tconfig = load_skills_config();\n\t\t},\n\t};\n}\n","import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';\nimport {\n\tContainer,\n\tSettingsList,\n\tText,\n\ttype SettingItem,\n} from '@mariozechner/pi-tui';\nimport {\n\tcreate_skills_manager,\n\ttype ManagedSkill,\n} from '../skills/manager.js';\n\nconst ENABLED = '[x]';\nconst DISABLED = '[ ]';\nconst SYNC = '[~]';\nconst IMPORTED_LABEL = '[=]';\n\nfunction sort_skills(skills: ManagedSkill[]): ManagedSkill[] {\n\treturn [...skills].sort((a, b) => {\n\t\tconst by_name = a.name.localeCompare(b.name);\n\t\tif (by_name !== 0) return by_name;\n\t\tconst by_source = a.source.localeCompare(b.source);\n\t\tif (by_source !== 0) return by_source;\n\t\treturn a.key.localeCompare(b.key);\n\t});\n}\n\nfunction find_matching_imported_skill(\n\tmanaged_skills: ManagedSkill[],\n\tskill: ManagedSkill,\n): ManagedSkill | undefined {\n\tconst exact_match = managed_skills.find(\n\t\t(candidate) =>\n\t\t\tcandidate.import_meta?.source === skill.source &&\n\t\t\t(candidate.import_meta.upstream_skill_path ===\n\t\t\t\tskill.skillPath ||\n\t\t\t\tcandidate.import_meta.upstream_base_dir === skill.baseDir),\n\t);\n\tif (exact_match) return exact_match;\n\n\treturn managed_skills.find(\n\t\t(candidate) =>\n\t\t\tcandidate.import_meta?.source === skill.source &&\n\t\t\tcandidate.name === skill.name,\n\t);\n}\n\nfunction get_importable_state(\n\tmanaged_skills: ManagedSkill[],\n\tskill: ManagedSkill,\n): {\n\tlabel: string;\n\tdetail: string;\n\taction: 'import' | 'sync' | null;\n} {\n\tconst imported = find_matching_imported_skill(\n\t\tmanaged_skills,\n\t\tskill,\n\t);\n\tif (imported?.import_meta) {\n\t\tconst version_changed = Boolean(\n\t\t\tskill.plugin?.version &&\n\t\t\timported.import_meta.upstream_version &&\n\t\t\tskill.plugin.version !== imported.import_meta.upstream_version,\n\t\t);\n\t\tconst sha_changed = Boolean(\n\t\t\tskill.plugin?.gitCommitSha &&\n\t\t\timported.import_meta.upstream_git_commit_sha &&\n\t\t\tskill.plugin.gitCommitSha !==\n\t\t\t\timported.import_meta.upstream_git_commit_sha,\n\t\t);\n\n\t\tif (version_changed || sha_changed) {\n\t\t\treturn {\n\t\t\t\tlabel: 'sync',\n\t\t\t\tdetail: 'Press Enter to sync the imported copy and reload',\n\t\t\t\taction: 'sync',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tlabel: 'imported',\n\t\t\tdetail: `Already imported to ${imported.baseDir}`,\n\t\t\taction: null,\n\t\t};\n\t}\n\n\tconst managed_conflict = managed_skills.find(\n\t\t(candidate) => candidate.name === skill.name,\n\t);\n\tif (managed_conflict) {\n\t\treturn {\n\t\t\tlabel: 'managed',\n\t\t\tdetail: `Already managed at ${managed_conflict.baseDir}`,\n\t\t\taction: null,\n\t\t};\n\t}\n\n\treturn {\n\t\tlabel: 'import',\n\t\tdetail: 'Press Enter to import into pi-native skills and reload',\n\t\taction: 'import',\n\t};\n}\n\nfunction to_setting_item(skill: ManagedSkill): SettingItem {\n\tconst detail_lines = [\n\t\t`${skill.source} • ${skill.key}`,\n\t\tskill.description,\n\t\tskill.baseDir,\n\t];\n\tif (skill.import_meta?.upstream_version) {\n\t\tdetail_lines.push(\n\t\t\t`upstream: ${skill.import_meta.upstream_version}${skill.import_meta.upstream_git_commit_sha ? ` • ${skill.import_meta.upstream_git_commit_sha.slice(0, 12)}` : ''}`,\n\t\t);\n\t}\n\n\treturn {\n\t\tid: skill.key,\n\t\tlabel: skill.name,\n\t\tdescription: detail_lines.join('\\n'),\n\t\tcurrentValue: skill.enabled ? ENABLED : DISABLED,\n\t\tvalues: [ENABLED, DISABLED],\n\t};\n}\n\nfunction to_importable_setting_item(\n\tmanaged_skills: ManagedSkill[],\n\tskill: ManagedSkill,\n): SettingItem {\n\tconst state = get_importable_state(managed_skills, skill);\n\tconst detail_lines = [\n\t\t`${skill.source} • ${skill.key}`,\n\t\tskill.description,\n\t\tskill.baseDir,\n\t];\n\tif (skill.plugin?.version) {\n\t\tdetail_lines.push(\n\t\t\t`plugin: ${skill.plugin.version}${skill.plugin.gitCommitSha ? ` • ${skill.plugin.gitCommitSha.slice(0, 12)}` : ''}`,\n\t\t);\n\t}\n\n\tif (state.action === 'import') {\n\t\treturn {\n\t\t\tid: skill.key,\n\t\t\tlabel: skill.name,\n\t\t\tdescription: detail_lines.join('\\n'),\n\t\t\tcurrentValue: DISABLED,\n\t\t\tvalues: [ENABLED, DISABLED],\n\t\t};\n\t}\n\n\tif (state.action === 'sync') {\n\t\tdetail_lines.push('enter to sync');\n\t\treturn {\n\t\t\tid: skill.key,\n\t\t\tlabel: skill.name,\n\t\t\tdescription: detail_lines.join('\\n'),\n\t\t\tcurrentValue: SYNC,\n\t\t\tvalues: [SYNC],\n\t\t};\n\t}\n\n\tdetail_lines.push(state.detail);\n\treturn {\n\t\tid: skill.key,\n\t\tlabel: skill.name,\n\t\tdescription: detail_lines.join('\\n'),\n\t\tcurrentValue: IMPORTED_LABEL,\n\t};\n}\n\nfunction sets_equal(\n\ta: ReadonlySet<string>,\n\tb: ReadonlySet<string>,\n): boolean {\n\tif (a.size !== b.size) return false;\n\tfor (const value of a) {\n\t\tif (!b.has(value)) return false;\n\t}\n\treturn true;\n}\n\n// Default export for Pi Package / additionalExtensionPaths loading\nexport default async function skills(pi: ExtensionAPI) {\n\tconst mgr = create_skills_manager();\n\n\tconst subs = ['import', 'sync', 'refresh', 'defaults'];\n\n\tpi.registerCommand('skills', {\n\t\tdescription: 'Manage pi-native skills and import external skills',\n\t\tgetArgumentCompletions: (prefix) => {\n\t\t\tconst parts = prefix.trim().split(/\\s+/);\n\t\t\tif (parts.length <= 1) {\n\t\t\t\treturn subs\n\t\t\t\t\t.filter((s) => s.startsWith(parts[0] || ''))\n\t\t\t\t\t.map((s) => ({ value: s, label: s }));\n\t\t\t}\n\n\t\t\tif (parts[0] === 'import') {\n\t\t\t\tconst q = parts.slice(1).join(' ').toLowerCase();\n\t\t\t\treturn sort_skills(mgr.discover_importable())\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(s) =>\n\t\t\t\t\t\t\ts.key.toLowerCase().includes(q) ||\n\t\t\t\t\t\t\ts.name.toLowerCase().includes(q),\n\t\t\t\t\t)\n\t\t\t\t\t.slice(0, 20)\n\t\t\t\t\t.map((s) => ({\n\t\t\t\t\t\tvalue: `${parts[0]} ${s.key}`,\n\t\t\t\t\t\tlabel: s.key,\n\t\t\t\t\t}));\n\t\t\t}\n\n\t\t\tif (parts[0] === 'sync') {\n\t\t\t\tconst q = parts.slice(1).join(' ').toLowerCase();\n\t\t\t\treturn sort_skills(\n\t\t\t\t\tmgr\n\t\t\t\t\t\t.discover()\n\t\t\t\t\t\t.filter((skill) => Boolean(skill.import_meta)),\n\t\t\t\t)\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(s) =>\n\t\t\t\t\t\t\ts.key.toLowerCase().includes(q) ||\n\t\t\t\t\t\t\ts.name.toLowerCase().includes(q),\n\t\t\t\t\t)\n\t\t\t\t\t.slice(0, 20)\n\t\t\t\t\t.map((s) => ({\n\t\t\t\t\t\tvalue: `${parts[0]} ${s.key}`,\n\t\t\t\t\t\tlabel: s.key,\n\t\t\t\t\t}));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tconst trimmed = args.trim();\n\n\t\t\tif (!trimmed && ctx.hasUI) {\n\t\t\t\tconst discovered = sort_skills(mgr.discover());\n\t\t\t\tconst importable = sort_skills(mgr.discover_importable());\n\t\t\t\tif (discovered.length === 0 && importable.length === 0) {\n\t\t\t\t\tctx.ui.notify('No managed or importable skills found');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst initial_enabled = new Set(\n\t\t\t\t\tdiscovered\n\t\t\t\t\t\t.filter((skill) => skill.enabled)\n\t\t\t\t\t\t.map((skill) => skill.key),\n\t\t\t\t);\n\t\t\t\tconst current_enabled = new Set(initial_enabled);\n\t\t\t\tconst queued_imports = new Set<string>();\n\t\t\t\tlet reload_notice: string | null = null;\n\n\t\t\t\tconst managed_items = discovered.map(to_setting_item);\n\t\t\t\tconst importable_items = importable.map((skill) =>\n\t\t\t\t\tto_importable_setting_item(discovered, skill),\n\t\t\t\t);\n\n\t\t\t\tconst all_items: SettingItem[] = [];\n\t\t\t\tif (managed_items.length > 0) {\n\t\t\t\t\tall_items.push({\n\t\t\t\t\t\tid: '__header_managed__',\n\t\t\t\t\t\tlabel: `── Managed (${managed_items.length}) ──`,\n\t\t\t\t\t\tdescription: '',\n\t\t\t\t\t\tcurrentValue: '',\n\t\t\t\t\t});\n\t\t\t\t\tall_items.push(...managed_items);\n\t\t\t\t}\n\t\t\t\tif (importable_items.length > 0) {\n\t\t\t\t\tall_items.push({\n\t\t\t\t\t\tid: '__header_importable__',\n\t\t\t\t\t\tlabel: `── Importable (${importable_items.length}) ──`,\n\t\t\t\t\t\tdescription: '',\n\t\t\t\t\t\tcurrentValue: '',\n\t\t\t\t\t});\n\t\t\t\t\tall_items.push(...importable_items);\n\t\t\t\t}\n\n\t\t\t\tconst managed_keys = new Set(discovered.map((s) => s.key));\n\t\t\t\tconst importable_map = new Map(\n\t\t\t\t\timportable.map((s) => [s.key, s]),\n\t\t\t\t);\n\n\t\t\t\tawait ctx.ui.custom((tui, theme, _kb, done) => {\n\t\t\t\t\tconst list = new SettingsList(\n\t\t\t\t\t\tall_items,\n\t\t\t\t\t\tMath.min(Math.max(all_items.length + 4, 8), 22),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcursor: theme.fg('accent', '›'),\n\t\t\t\t\t\t\tlabel: (text, selected) => {\n\t\t\t\t\t\t\t\tif (text.startsWith('──') && text.endsWith('──')) {\n\t\t\t\t\t\t\t\t\treturn theme.fg('dim', theme.bold(text));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn selected ? theme.fg('accent', text) : text;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tvalue: (text, selected) => {\n\t\t\t\t\t\t\t\tconst color =\n\t\t\t\t\t\t\t\t\ttext === ENABLED\n\t\t\t\t\t\t\t\t\t\t? ('success' as const)\n\t\t\t\t\t\t\t\t\t\t: text === SYNC\n\t\t\t\t\t\t\t\t\t\t\t? ('warning' as const)\n\t\t\t\t\t\t\t\t\t\t\t: text === IMPORTED_LABEL\n\t\t\t\t\t\t\t\t\t\t\t\t? ('success' as const)\n\t\t\t\t\t\t\t\t\t\t\t\t: ('dim' as const);\n\t\t\t\t\t\t\t\tconst rendered = theme.fg(color, text);\n\t\t\t\t\t\t\t\treturn selected\n\t\t\t\t\t\t\t\t\t? theme.bold(theme.fg('accent', rendered))\n\t\t\t\t\t\t\t\t\t: rendered;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdescription: (text) => theme.fg('muted', text),\n\t\t\t\t\t\t\thint: (text) => theme.fg('dim', text),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(id, new_value) => {\n\t\t\t\t\t\t\tif (id.startsWith('__header_')) return;\n\n\t\t\t\t\t\t\tif (managed_keys.has(id)) {\n\t\t\t\t\t\t\t\tif (new_value === ENABLED) {\n\t\t\t\t\t\t\t\t\tcurrent_enabled.add(id);\n\t\t\t\t\t\t\t\t\tmgr.enable(id);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurrent_enabled.delete(id);\n\t\t\t\t\t\t\t\t\tmgr.disable(id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst import_skill = importable_map.get(id);\n\t\t\t\t\t\t\tif (!import_skill) return;\n\n\t\t\t\t\t\t\tconst state = get_importable_state(\n\t\t\t\t\t\t\t\tdiscovered,\n\t\t\t\t\t\t\t\timport_skill,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (state.action === 'import') {\n\t\t\t\t\t\t\t\tif (new_value === ENABLED) {\n\t\t\t\t\t\t\t\t\tqueued_imports.add(id);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tqueued_imports.delete(id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (state.action === 'sync') {\n\t\t\t\t\t\t\t\tconst imported_skill = find_matching_imported_skill(\n\t\t\t\t\t\t\t\t\tdiscovered,\n\t\t\t\t\t\t\t\t\timport_skill,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (!imported_skill) {\n\t\t\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t\t\t`Imported copy for ${import_skill.name} was not found`,\n\t\t\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst result = mgr.sync_skill(imported_skill.key);\n\t\t\t\t\t\t\t\t\tif (result.changed) {\n\t\t\t\t\t\t\t\t\t\treload_notice = `Synced ${import_skill.name}. Reloading...`;\n\t\t\t\t\t\t\t\t\t\tdone(undefined);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t\t\t\t`${import_skill.name} is already up to date.`,\n\t\t\t\t\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t\t: String(error),\n\t\t\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => done(undefined),\n\t\t\t\t\t\t{ enableSearch: true },\n\t\t\t\t\t);\n\n\t\t\t\t\tconst container = new Container();\n\n\t\t\t\t\tcontainer.addChild({\n\t\t\t\t\t\trender: () => {\n\t\t\t\t\t\t\tconst enabled = current_enabled.size;\n\t\t\t\t\t\t\tconst disabled = discovered.length - enabled;\n\t\t\t\t\t\t\tconst queued = queued_imports.size;\n\t\t\t\t\t\t\tconst parts = [\n\t\t\t\t\t\t\t\t`${enabled} enabled`,\n\t\t\t\t\t\t\t\t`${disabled} disabled`,\n\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\tif (importable.length > 0) {\n\t\t\t\t\t\t\t\tparts.push(`${importable.length} importable`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (queued > 0) {\n\t\t\t\t\t\t\t\tparts.push(`${queued} queued for import`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\ttheme.fg('accent', theme.bold('Skills')),\n\t\t\t\t\t\t\t\ttheme.fg('muted', parts.join(' • ')),\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t];\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalidate: () => {},\n\t\t\t\t\t});\n\n\t\t\t\t\tcontainer.addChild({\n\t\t\t\t\t\trender(width: number) {\n\t\t\t\t\t\t\treturn list.render(width);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalidate() {\n\t\t\t\t\t\t\tlist.invalidate();\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t\t'search filters • enter toggles • esc close',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\trender(width: number) {\n\t\t\t\t\t\t\treturn container.render(width);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalidate() {\n\t\t\t\t\t\t\tcontainer.invalidate();\n\t\t\t\t\t\t},\n\t\t\t\t\t\thandleInput(data: string) {\n\t\t\t\t\t\t\tlist.handleInput(data);\n\t\t\t\t\t\t\ttui.requestRender();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\tif (queued_imports.size > 0) {\n\t\t\t\t\tconst imported_names: string[] = [];\n\t\t\t\t\tfor (const key of queued_imports) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tmgr.import_skill(key);\n\t\t\t\t\t\t\timported_names.push(key);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t: String(error),\n\t\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (imported_names.length > 0) {\n\t\t\t\t\t\treload_notice = `Imported ${imported_names.length} skill(s). Reloading...`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (reload_notice) {\n\t\t\t\t\tctx.ui.notify(reload_notice, 'info');\n\t\t\t\t\tawait ctx.reload();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!sets_equal(initial_enabled, current_enabled)) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t'Reloading to apply updated skills...',\n\t\t\t\t\t\t'info',\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.reload();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst [sub, ...rest] = (trimmed || 'list').split(/\\s+/);\n\t\t\tconst arg = rest.join(' ');\n\n\t\t\tswitch (sub) {\n\t\t\t\tcase 'import': {\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /skills import <key|name>',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = mgr.import_skill(arg);\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Imported ${arg} to ${result.skillDir}. Reloading...`,\n\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait ctx.reload();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 'sync': {\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /skills sync <key|name>',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = mgr.sync_skill(arg);\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\tresult.changed\n\t\t\t\t\t\t\t\t? `Synced ${arg}. Reloading...`\n\t\t\t\t\t\t\t\t: `${arg} is already up to date.`,\n\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (result.changed) {\n\t\t\t\t\t\t\tawait ctx.reload();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 'refresh': {\n\t\t\t\t\tmgr.refresh();\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`Rescanned: ${mgr.discover().length} managed skills, ${mgr.discover_importable().length} importable skills found`,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'defaults': {\n\t\t\t\t\tif (arg !== 'all-enabled' && arg !== 'all-disabled') {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /skills defaults <all-enabled|all-disabled>',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tmgr.set_defaults(arg);\n\t\t\t\t\tctx.ui.notify(`Default policy: ${arg}`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`Unknown: ${sub}. Use: ${subs.join(', ')}`,\n\t\t\t\t\t\t'warning',\n\t\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n}\n","// Composable programmatic API for my-pi\n// Extension loading patterns inspired by pi-vs-claude-code\n\nimport {\n\tInteractiveMode,\n\tSessionManager,\n\tSettingsManager,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionRuntime,\n\tcreateAgentSessionServices,\n\tgetAgentDir,\n\trunPrintMode,\n\ttype ExtensionFactory,\n\ttype LoadExtensionsResult,\n} from '@mariozechner/pi-coding-agent';\nimport { resolve } from 'node:path';\nimport chain_extension from './extensions/chain.js';\nimport {\n\tBUILTIN_EXTENSIONS,\n\tis_builtin_extension_active,\n\tload_builtin_extensions_config,\n\ttype BuiltinExtensionKey,\n} from './extensions/config.js';\nimport { create_extensions_extension } from './extensions/extensions.js';\nimport filter_output_extension from './extensions/filter-output.js';\nimport handoff_extension from './extensions/handoff.js';\nimport mcp_extension from './extensions/mcp.js';\nimport recall_extension from './extensions/recall.js';\nimport skills_extension from './extensions/skills.js';\nimport { create_skills_manager } from './skills/manager.js';\n\nexport interface CreateMyPiOptions {\n\tcwd?: string;\n\textensions?: string[];\n\textensionFactories?: ExtensionFactory[];\n\tmcp?: boolean;\n\tskills?: boolean;\n\tchain?: boolean;\n\tfilter_output?: boolean;\n\thandoff?: boolean;\n\trecall?: boolean;\n\tmodel?: string;\n}\n\nconst BUILTIN_EXTENSION_FACTORIES: Record<\n\tBuiltinExtensionKey,\n\tExtensionFactory\n> = {\n\tmcp: mcp_extension,\n\tskills: skills_extension,\n\tchain: chain_extension,\n\t'filter-output': filter_output_extension,\n\thandoff: handoff_extension,\n\trecall: recall_extension,\n};\n\nfunction get_force_disabled_builtins(\n\toptions: Pick<\n\t\tCreateMyPiOptions,\n\t\t| 'mcp'\n\t\t| 'skills'\n\t\t| 'chain'\n\t\t| 'filter_output'\n\t\t| 'handoff'\n\t\t| 'recall'\n\t>,\n): ReadonlySet<BuiltinExtensionKey> {\n\tconst force_disabled = new Set<BuiltinExtensionKey>();\n\tif (!options.mcp) force_disabled.add('mcp');\n\tif (!options.skills) force_disabled.add('skills');\n\tif (!options.chain) force_disabled.add('chain');\n\tif (!options.filter_output) force_disabled.add('filter-output');\n\tif (!options.handoff) force_disabled.add('handoff');\n\tif (!options.recall) force_disabled.add('recall');\n\treturn force_disabled;\n}\n\nfunction create_builtin_extension_factory(\n\tkey: BuiltinExtensionKey,\n\textension: ExtensionFactory,\n\tforce_disabled: ReadonlySet<BuiltinExtensionKey>,\n): ExtensionFactory {\n\treturn async (pi) => {\n\t\tconst config = load_builtin_extensions_config();\n\t\tif (!is_builtin_extension_active(config, key, force_disabled)) {\n\t\t\treturn;\n\t\t}\n\t\tawait extension(pi);\n\t};\n}\n\nfunction create_extensions_override(\n\tmanaged_inline_paths: string[],\n): (base: LoadExtensionsResult) => LoadExtensionsResult {\n\tconst managed_paths = new Set(managed_inline_paths);\n\treturn (base) => {\n\t\tconst managed = new Map(\n\t\t\tbase.extensions.map((extension) => [extension.path, extension]),\n\t\t);\n\t\tconst ordered_managed = managed_inline_paths\n\t\t\t.map((path) => managed.get(path))\n\t\t\t.filter(\n\t\t\t\t(\n\t\t\t\t\textension,\n\t\t\t\t): extension is LoadExtensionsResult['extensions'][number] =>\n\t\t\t\t\tBoolean(extension),\n\t\t\t);\n\t\tconst others = base.extensions.filter(\n\t\t\t(extension) => !managed_paths.has(extension.path),\n\t\t);\n\t\treturn {\n\t\t\t...base,\n\t\t\textensions: [...ordered_managed, ...others],\n\t\t};\n\t};\n}\n\nexport async function create_my_pi(options: CreateMyPiOptions = {}) {\n\tconst {\n\t\tcwd = process.cwd(),\n\t\textensions = [],\n\t\textensionFactories: user_factories = [],\n\t\tmcp = true,\n\t\tskills = true,\n\t\tchain = true,\n\t\tfilter_output = true,\n\t\thandoff = true,\n\t\trecall = true,\n\t\tmodel,\n\t} = options;\n\n\tconst resolved_extensions = extensions.map((p) => resolve(cwd, p));\n\tconst force_disabled = get_force_disabled_builtins({\n\t\tmcp,\n\t\tskills,\n\t\tchain,\n\t\tfilter_output,\n\t\thandoff,\n\t\trecall,\n\t});\n\tconst managed_extension_factories: ExtensionFactory[] = [\n\t\tcreate_extensions_extension({ force_disabled }),\n\t\t...BUILTIN_EXTENSIONS.map((extension) =>\n\t\t\tcreate_builtin_extension_factory(\n\t\t\t\textension.key,\n\t\t\t\tBUILTIN_EXTENSION_FACTORIES[extension.key],\n\t\t\t\tforce_disabled,\n\t\t\t),\n\t\t),\n\t];\n\tconst managed_inline_paths = managed_extension_factories.map(\n\t\t(_, index) => `<inline:${index + 1}>`,\n\t);\n\n\tconst create_runtime = async ({\n\t\tcwd: runtime_cwd,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t}: {\n\t\tcwd: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: unknown;\n\t}) => {\n\t\tconst settings_manager = model\n\t\t\t? (() => {\n\t\t\t\t\tconst sm = SettingsManager.create(runtime_cwd);\n\t\t\t\t\tsm.setDefaultModel(model);\n\t\t\t\t\treturn sm;\n\t\t\t\t})()\n\t\t\t: undefined;\n\n\t\tconst services = await createAgentSessionServices({\n\t\t\tcwd: runtime_cwd,\n\t\t\t...(settings_manager\n\t\t\t\t? { settingsManager: settings_manager }\n\t\t\t\t: {}),\n\t\t\tresourceLoaderOptions: {\n\t\t\t\tadditionalExtensionPaths: [...resolved_extensions],\n\t\t\t\textensionFactories: [\n\t\t\t\t\t...managed_extension_factories,\n\t\t\t\t\t...user_factories,\n\t\t\t\t],\n\t\t\t\textensionsOverride: create_extensions_override(\n\t\t\t\t\tmanaged_inline_paths,\n\t\t\t\t),\n\t\t\t\tskillsOverride: (base: any) => {\n\t\t\t\t\tconst config = load_builtin_extensions_config();\n\t\t\t\t\tif (\n\t\t\t\t\t\t!is_builtin_extension_active(\n\t\t\t\t\t\t\tconfig,\n\t\t\t\t\t\t\t'skills',\n\t\t\t\t\t\t\tforce_disabled,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn base;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst skills_manager = create_skills_manager();\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...base,\n\t\t\t\t\t\tskills: base.skills.filter((skill: any) =>\n\t\t\t\t\t\t\tskills_manager.is_enabled_by_skill(\n\t\t\t\t\t\t\t\tskill.name,\n\t\t\t\t\t\t\t\tskill.filePath,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t} as any,\n\t\t});\n\n\t\treturn {\n\t\t\t...(await createAgentSessionFromServices({\n\t\t\t\tservices,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: sessionStartEvent as any,\n\t\t\t})),\n\t\t\tservices,\n\t\t\tdiagnostics: services.diagnostics,\n\t\t};\n\t};\n\n\treturn createAgentSessionRuntime(create_runtime, {\n\t\tcwd,\n\t\tagentDir: getAgentDir(),\n\t\tsessionManager: SessionManager.create(cwd),\n\t});\n}\n\nexport { InteractiveMode, runPrintMode };\n\nexport type {\n\tAgentSessionRuntime,\n\tExtensionFactory,\n\tInteractiveModeOptions,\n\tPrintModeOptions,\n} from '@mariozechner/pi-coding-agent';\n"],"mappings":";;;;;;;;;AAmCA,SAAS,iBAAiB,KAAyB;CAClD,MAAM,SAAqB,EAAE;CAC7B,IAAI,UAA2B;CAC/B,IAAI,eAAiC;AAErC,MAAK,MAAM,QAAQ,IAAI,MAAM,KAAK,EAAE;EACnC,MAAM,cAAc,KAAK,MAAM,eAAe;AAC9C,MAAI,aAAa;AAChB,OAAI,WAAW,cAAc;AAC5B,YAAQ,MAAM,KAAK,aAAa;AAChC,mBAAe;;AAEhB,aAAU;IACT,MAAM,YAAY,GAAG,MAAM;IAC3B,aAAa;IACb,OAAO,EAAE;IACT;AACD,UAAO,KAAK,QAAQ;AACpB;;EAGD,MAAM,aAAa,KAAK,MAAM,2BAA2B;AACzD,MAAI,cAAc,WAAW,CAAC,cAAc;GAC3C,IAAI,OAAO,WAAW,GAAG,MAAM;AAC/B,OACE,KAAK,WAAW,KAAI,IAAI,KAAK,SAAS,KAAI,IAC1C,KAAK,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,CAE3C,QAAO,KAAK,MAAM,GAAG,GAAG;AAEzB,WAAQ,cAAc;AACtB;;AAGD,MAAI,KAAK,MAAM,iBAAiB,IAAI,QAAS;EAE7C,MAAM,cAAc,KAAK,MAAM,yBAAyB;AACxD,MAAI,eAAe,SAAS;AAC3B,OAAI,aAAc,SAAQ,MAAM,KAAK,aAAa;AAClD,kBAAe;IACd,OAAO,YAAY,GAAG,MAAM;IAC5B,QAAQ;IACR;AACD;;EAGD,MAAM,eAAe,KAAK,MAAM,sBAAsB;AACtD,MAAI,gBAAgB,cAAc;GACjC,IAAI,SAAS,aAAa,GAAG,MAAM;AACnC,OACE,OAAO,WAAW,KAAI,IAAI,OAAO,SAAS,KAAI,IAC9C,OAAO,WAAW,IAAI,IAAI,OAAO,SAAS,IAAI,CAE/C,UAAS,OAAO,MAAM,GAAG,GAAG;AAE7B,YAAS,OAAO,QAAQ,QAAQ,KAAK;AACrC,gBAAa,SAAS;AACtB;;;AAIF,KAAI,WAAW,aACd,SAAQ,MAAM,KAAK,aAAa;AAGjC,QAAO;;AAKR,SAAS,iBAAiB,UAAmC;AAC5D,KAAI;EAEH,MAAM,EAAE,aAAa,SAAS,iBADlB,aAAa,UAAU,QAAQ,CAKpC;AAEP,MAAI,CAAC,aAAa,KAAM,QAAO;AAE/B,SAAO;GACN,MAAM,YAAY;GAClB,aAAa,YAAY,eAAe;GACxC,OAAO,YAAY,SAAS;GAC5B,cAAc,KAAK,MAAM;GACzB;SACM;AACP,SAAO;;;AAIT,SAAS,gBAAgB,KAAoC;CAC5D,MAAM,OAAO;EACZ,KAAK,KAAK,SAAS;EACnB,KAAK,KAAK,WAAW,SAAS;EAC9B,KAAK,KAAK,OAAO,SAAS;EAC1B;CAED,MAAM,yBAAS,IAAI,KAAuB;AAE1C,MAAK,MAAM,OAAO,MAAM;AACvB,MAAI,CAAC,WAAW,IAAI,CAAE;AACtB,MAAI;AACH,QAAK,MAAM,QAAQ,YAAY,IAAI,EAAE;AACpC,QAAI,CAAC,KAAK,SAAS,MAAM,CAAE;IAC3B,MAAM,MAAM,iBAAiB,QAAQ,KAAK,KAAK,CAAC;AAChD,QAAI,OAAO,CAAC,OAAO,IAAI,IAAI,KAAK,aAAa,CAAC,CAC7C,QAAO,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI;;UAGlC;;AAKT,QAAO;;AAKR,SAAS,eACR,WACA,MACgD;CAEhD,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,OAAO;EAAC;EAAgB;EAAM;EAAK;CAEzC,MAAM,SAAmB,EAAE;AAE3B,QAAO,IAAI,SAAS,QAAQ;EAC3B,MAAM,OAAO,MAAM,QAAQ,UAAU,CAAC,KAAK,GAAG,KAAK,EAAE;GACpD,OAAO;IAAC;IAAU;IAAQ;IAAO;GACjC,KAAK;IACJ,GAAG,QAAQ;IACX,2BAA2B,UAAU;IACrC;GACD,CAAC;AAEF,OAAK,OAAQ,YAAY,QAAQ;AACjC,OAAK,OAAQ,GAAG,SAAS,UAAkB;AAC1C,UAAO,KAAK,MAAM;IACjB;AAEF,OAAK,OAAQ,YAAY,QAAQ;AACjC,OAAK,OAAQ,GAAG,cAAc,GAAG;AAEjC,OAAK,GAAG,UAAU,SAAS;AAC1B,OAAI;IACH,QAAQ,OAAO,KAAK,GAAG,CAAC,MAAM;IAC9B,UAAU,QAAQ;IAClB,CAAC;IACD;AAEF,OAAK,GAAG,UAAU,QAAQ;AACzB,OAAI;IACH,QAAQ,yBAAyB,IAAI;IACrC,UAAU;IACV,CAAC;IACD;GACD;;AAMH,eAA8B,MAAM,IAAkB;CACrD,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,SAAS,gBAAgB,IAAI;CACnC,IAAI,SAAqB,EAAE;CAC3B,IAAI,eAAgC;CAGpC,MAAM,cAAc;EACnB,KAAK,KAAK,OAAO,UAAU,mBAAmB;EAC9C,KAAK,KAAK,OAAO,UAAU,cAAc;EACzC,KAAK,KAAK,WAAW,UAAU,cAAc;EAC7C;AAED,MAAK,MAAM,QAAQ,YAClB,KAAI,WAAW,KAAK,CACnB,KAAI;AACH,WAAS,iBAAiB,aAAa,MAAM,QAAQ,CAAC;AACtD;SACO;AAMV,KAAI,OAAO,SAAS,EACnB,gBAAe,OAAO;AAKvB,IAAG,aACF,WAAW;EACV,MAAM;EACN,OAAO;EACP,aACC;EACD,YAAY,KAAK,OAAO,EACvB,MAAM,KAAK,OAAO,EACjB,aAAa,4CACb,CAAC,EACF,CAAC;EACF,SAAS,OACR,KACA,WAIK;GACL,MAAM,EAAE,SAAS;AAEjB,OAAI,CAAC,aACJ,QAAO;IACN,SAAS,CACR;KACC,MAAM;KACN,MAAM;KACN,CACD;IACD,SAAS;KACR,OAAO;KACP,OAAO;KACP;IACD;GAGF,IAAI,QAAQ;GACZ,MAAM,WAAW;GACjB,MAAM,UAAoB,EAAE;AAE5B,QAAK,IAAI,IAAI,GAAG,IAAI,aAAa,MAAM,QAAQ,KAAK;IACnD,MAAM,OAAO,aAAa,MAAM;IAChC,MAAM,YAAY,OAAO,IAAI,KAAK,MAAM,aAAa,CAAC;AAEtD,QAAI,CAAC,WAAW;KACf,MAAM,MAAM,QAAQ,IAAI,EAAE,WAAW,KAAK,MAAM,0BAA0B,MAAM,KAAK,OAAO,MAAM,CAAC,CAAC,KAAK,KAAK;AAC9G,aAAQ,KAAK,IAAI;AACjB,YAAO;MACN,SAAS,CAAC;OAAE,MAAM;OAAiB,MAAM;OAAK,CAAC;MAC/C,SAAS;OACR,OAAO,aAAa;OACpB,OAAO;OACP;MACD;;IAOF,MAAM,SAAS,MAAM,eACpB,WALuB,KAAK,OAC3B,QAAQ,YAAY,MAAM,CAC1B,QAAQ,eAAe,SAAS,CAKjC;AAED,QAAI,OAAO,aAAa,GAAG;KAC1B,MAAM,MAAM,QAAQ,IAAI,EAAE,IAAI,KAAK,MAAM,aAAa,OAAO;AAC7D,aAAQ,KAAK,IAAI;AACjB,YAAO;MACN,SAAS,CAAC;OAAE,MAAM;OAAiB,MAAM;OAAK,CAAC;MAC/C,SAAS;OACR,OAAO,aAAa;OACpB,OAAO,IAAI;OACX;MACD;;AAGF,YAAQ,KACP,WAAW,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,SAC3C;AACD,YAAQ,OAAO;;AAIhB,UAAO;IACN,SAAS,CAAC;KAAE,MAAM;KAAiB,MAFpB,QAAQ,KAAK,cAAc;KAEQ,CAAC;IACnD,SAAS;KACR,OAAO,aAAa;KACpB,OAAO,aAAa,MAAM;KAC1B;IACD;;EAEF,CAAC,CACF;AAID,IAAG,gBAAgB,SAAS;EAC3B,aAAa;EACb,yBAAyB,WAAW;GACnC,MAAM,QAAQ,OAAO,MAAM,CAAC,MAAM,MAAM;AACxC,OAAI,MAAM,UAAU,EAEnB,QADa,CAAC,QAAQ,GAAG,OAAO,KAAK,MAAM,EAAE,KAAK,CAAC,CAEjD,QAAQ,MAAM,EAAE,WAAW,MAAM,MAAM,GAAG,CAAC,CAC3C,KAAK,OAAO;IAAE,OAAO;IAAG,OAAO;IAAG,EAAE;AAEvC,UAAO;;EAER,SAAS,OAAO,MAAM,QAAQ;GAC7B,MAAM,MAAM,KAAK,MAAM;AAEvB,OAAI,CAAC,OAAO,QAAQ,QAAQ;AAC3B,QAAI,OAAO,WAAW,GAAG;AACxB,SAAI,GAAG,OACN,8DACA,UACA;AACD;;IAED,MAAM,QAAQ,OAAO,KAAK,MAAM;KAC/B,MAAM,SAAS,EAAE,SAAS,cAAc,OAAO,OAAO;KACtD,MAAM,QAAQ,EAAE,MAAM,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO;AACtD,YAAO,GAAG,EAAE,OAAO,OAAO,IAAI,EAAE,eAAe;MAC9C;AACF,QAAI,GAAG,OAAO,MAAM,KAAK,KAAK,CAAC;AAC/B;;GAGD,MAAM,cAAc,OAAO,MACzB,MAAM,EAAE,KAAK,aAAa,KAAK,IAAI,aAAa,CACjD;AACD,OAAI,CAAC,aAAa;AACjB,QAAI,GAAG,OACN,kBAAkB,IAAI,qBACtB,UACA;AACD;;AAGD,kBAAe;GACf,MAAM,OAAO,YAAY,MAAM,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO;AAC/D,OAAI,GAAG,OAAO,iBAAiB,YAAY,KAAK,IAAI,KAAK,GAAG;;EAE7D,CAAC;AAIF,IAAG,GACF,sBACA,OAAO,UAAoC;AAC1C,MAAI,CAAC,gBAAgB,OAAO,WAAW,EAAG,QAAO,EAAE;EAEnD,MAAM,OAAO,aAAa,MACxB,KAAK,MAAM,EAAE,MAAM,CACnB,KAAK,OAAO;EAEd,MAAM,YAAY,aAAa,MAC7B,KAAK,GAAG,MAAM;GAEd,MAAM,OADM,OAAO,IAAI,EAAE,MAAM,aAAa,CAAC,EAC3B,eAAe;AACjC,UAAO,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,OAAO;IACpC,CACD,KAAK,KAAK;EAEZ,MAAM,aAAa,OACjB,KAAK,MAAM;GACX,MAAM,SACL,EAAE,SAAS,cAAc,OAAO,cAAc;AAC/C,UAAO,KAAK,EAAE,OAAO,OAAO,IAAI,EAAE;IACjC,CACD,KAAK,KAAK;AAGZ,SAAO,EACN,cACC,MAAM,eACN;;;;;;oBAMe,aAAa,KAAK;EACpC,aAAa,YAAY;QACnB,KAAK;;EAEX,UAAU;;;EAGV,WAAW;;;;;;;;;;;;oCAaT;GAEF;AAID,IAAG,gBAAgB,UAAU;EAC5B,aAAa;EACb,SAAS,OAAO,OAAO,QAAQ;AAC9B,OAAI,OAAO,SAAS,GAAG;AACtB,QAAI,GAAG,OACN,+DACA,UACA;AACD;;GAED,MAAM,QAAQ,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,KACxC,MACA,GAAG,EAAE,KAAK,IAAI,EAAE,eAAe,mBAAmB,IAAI,EAAE,MAAM,GAC/D;AACD,OAAI,GAAG,OAAO,MAAM,KAAK,KAAK,CAAC;;EAEhC,CAAC;;;;ACnaH,MAAMA,mBAA0C;CAC/C,SAAS;CACT,SAAS,EAAE;CACX;AAED,MAAa,qBAA6C;CACzD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS,CAAC,MAAM;EAChB;CACD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS,CAAC,UAAU,QAAQ;EAC5B;CACD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS,CAAC,SAAS,SAAS;EAC5B;CACD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS;GACR;GACA;GACA;GACA;GACA;EACD;CACD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS,CAAC,UAAU;EACpB;CACD;EACC,KAAK;EACL,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS,CAAC,SAAS;EACnB;CACD;AAED,SAAgB,qCAA6C;AAG5D,QAAO,KADN,QAAQ,IAAI,mBAAmB,KAAK,SAAS,EAAE,UAAU,EACzC,SAAS,kBAAkB;;AAG7C,SAAgB,iCAA0D;CACzE,MAAM,OAAO,oCAAoC;AACjD,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,EAAE,GAAGA,kBAAgB;AAEnD,KAAI;EACH,MAAM,MAAM,aAAa,MAAM,QAAQ;EACvC,MAAM,SAAS,KAAK,MACnB,IACA;EACD,MAAM,UAA8C,EAAE;AACtD,OAAK,MAAM,aAAa,oBAAoB;GAC3C,MAAM,QAAQ,OAAO,UAAU,UAAU;AACzC,OAAI,OAAO,UAAU,UACpB,SAAQ,UAAU,OAAO;;AAI3B,SAAO;GACN,SAAS,OAAO,WAAW;GAC3B;GACA;SACM;AACP,SAAO,EAAE,GAAGA,kBAAgB;;;AAI9B,SAAgB,+BACf,QACO;CACP,MAAM,OAAO,oCAAoC;CACjD,MAAM,MAAM,QAAQ,KAAK;AACzB,KAAI,CAAC,WAAW,IAAI,CACnB,WAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAGjD,MAAM,MAAM,GAAG,KAAK,OAAO,KAAK,KAAK;AACrC,eAAc,KAAK,KAAK,UAAU,QAAQ,MAAM,IAAK,GAAG,MAAM,EAC7D,MAAM,KACN,CAAC;AACF,YAAW,KAAK,KAAK;;AAGtB,SAAgB,6BACf,QACA,KACU;AACV,QAAO,OAAO,QAAQ,QAAQ;;AAG/B,SAAgB,4BACf,QACA,KACA,iCAAmD,IAAI,KAAK,EAClD;AACV,QACC,6BAA6B,QAAQ,IAAI,IACzC,CAAC,eAAe,IAAI,IAAI;;AAI1B,SAAgB,iCACf,iCAAmD,IAAI,KAAK,EAC5D,SAAkC,gCAAgC,EACxC;AAC1B,QAAO,mBAAmB,KAAK,cAAc;EAC5C,MAAM,gBAAgB,6BACrB,QACA,UAAU,IACV;EACD,MAAM,SAAS,eAAe,IAAI,UAAU,IAAI;AAChD,SAAO;GACN,GAAG;GACH;GACA,mBAAmB,iBAAiB,CAAC;GACrC,iBAAiB;GACjB;GACA;;AAGH,SAAgB,uBACf,OACmC;CACnC,MAAM,aAAa,MAAM,MAAM,CAAC,aAAa;AAC7C,KAAI,CAAC,WAAY,QAAO,KAAA;AAExB,QAAO,mBAAmB,MAAM,cAC/B;EAAC,UAAU;EAAK,UAAU;EAAO,GAAG,UAAU;EAAQ,CAAC,MACrD,UAAU,MAAM,aAAa,KAAK,WACnC,CACD;;;;AC1KF,MAAMC,YAAU;AAChB,MAAMC,aAAW;AAMjB,SAAS,sBACR,gBACmC;AACnC,QAAO,IAAI,IAAI,kBAAkB,EAAE,CAAC;;AAGrC,SAAS,uBACR,OACS;AACT,KAAI,MAAM,kBACT,QAAO;AAER,KAAI,MAAM,gBACT,QAAO,+BAA+B,MAAM;AAE7C,QAAO;;AAGR,SAAS,uBACR,QACA,SACS;CACT,MAAM,QAAkB,EAAE;AAC1B,KAAI,SAAS,QACZ,OAAM,KAAK,QAAQ,SAAS,GAAG;CAGhC,MAAM,cAAc,OAAO,QACzB,UAAU,MAAM,kBACjB,CAAC;CACF,MAAM,eAAe,OAAO,SAAS;AACrC,OAAM,KACL,GAAG,OAAO,OAAO,wBAAwB,YAAY,gBAAgB,aAAa,iBAClF,GACA;AAED,MAAK,MAAM,SAAS,QAAQ;AAC3B,QAAM,KACL,GAAG,MAAM,gBAAgBD,YAAUC,WAAS,GAAG,MAAM,QACrD;AACD,QAAM,KAAK,YAAY,MAAM,MAAM;AACnC,QAAM,KACL,qBAAqB,MAAM,gBAAgB,YAAY,aACvD;AACD,QAAM,KACL,wBAAwB,uBAAuB,MAAM,GACrD;AACD,QAAM,KAAK,OAAO,MAAM,cAAc;;AAGvC,QAAO,MAAM,KAAK,KAAK;;AAGxB,SAASC,kBAAgB,OAA2C;CACnE,MAAM,eAAe;EACpB,MAAM;EACN,MAAM;EACN,oBAAoB,uBAAuB,MAAM;EACjD,qBAAqB,MAAM;EAC3B;AAED,QAAO;EACN,IAAI,MAAM;EACV,OAAO,MAAM;EACb,aAAa,aAAa,KAAK,KAAK;EACpC,cAAc,MAAM,gBAAgBF,YAAUC;EAC9C,QAAQ,CAACD,WAASC,WAAS;EAC3B;;AAGF,SAASE,aACR,GACA,GACU;AACV,KAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,MAAK,MAAM,SAAS,EACnB,KAAI,CAAC,EAAE,IAAI,MAAM,CAAE,QAAO;AAE3B,QAAO;;AAGR,SAAS,cACR,QACA,OAC0B;CAC1B,MAAM,aAAa,MAAM,MAAM,CAAC,aAAa;AAC7C,KAAI,CAAC,WAAY,QAAO;AAExB,QAAO,OAAO,QAAQ,UACrB;EACC,MAAM;EACN,MAAM;EACN,MAAM;EACN,GAAG,MAAM;EACT,CAAC,MAAM,UAAU,MAAM,aAAa,CAAC,SAAS,WAAW,CAAC,CAC3D;;AAGF,SAAS,uBACR,KACA,SACO;CACP,MAAM,SAAS,gCAAgC;AAC/C,QAAO,QAAQ,OAAO;AACtB,gCAA+B,OAAO;;AAGvC,SAAgB,4BACf,UAAoC,EAAE,EACrC;CACD,MAAM,iBAAiB,sBACtB,QAAQ,eACR;AAED,QAAO,eAAe,WAAW,IAAkB;EAClD,MAAM,OAAO;GAAC;GAAQ;GAAU;GAAW;GAAU;GAAS;AAE9D,KAAG,gBAAgB,cAAc;GAChC,aAAa;GACb,yBAAyB,WAAW;IACnC,MAAM,QAAQ,OAAO,MAAM,CAAC,MAAM,MAAM;AACxC,QAAI,MAAM,UAAU,EACnB,QAAO,KACL,QAAQ,QAAQ,IAAI,WAAW,MAAM,MAAM,GAAG,CAAC,CAC/C,KAAK,SAAS;KAAE,OAAO;KAAK,OAAO;KAAK,EAAE;AAG7C,QAAI;KAAC;KAAU;KAAW;KAAS,CAAC,SAAS,MAAM,GAAG,EAAE;KACvD,MAAM,IAAI,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,aAAa;AAChD,YAAO,iCAAiC,eAAe,CACrD,QACC,UACA,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,IACnC,MAAM,MAAM,aAAa,CAAC,SAAS,EAAE,CACtC,CACA,MAAM,GAAG,GAAG,CACZ,KAAK,WAAW;MAChB,OAAO,GAAG,MAAM,GAAG,GAAG,MAAM;MAC5B,OAAO,GAAG,MAAM,IAAI,GAAG,MAAM,gBAAgBH,YAAUC;MACvD,EAAE;;AAGL,WAAO;;GAER,SAAS,OAAO,MAAM,QAAQ;IAC7B,MAAM,UAAU,KAAK,MAAM;AAE3B,QAAI,CAAC,WAAW,IAAI,OAAO;KAC1B,MAAM,SACL,iCAAiC,eAAe;KACjD,MAAM,kBAAkB,IAAI,IAC3B,OACE,QAAQ,UAAU,MAAM,cAAc,CACtC,KAAK,UAAU,MAAM,IAAI,CAC3B;KACD,MAAM,kBAAkB,IAAI,IAAI,gBAAgB;AAEhD,WAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,KAAK,SAAS;MAC9C,MAAM,QAAQ,OAAO,IAAIC,kBAAgB;MACzC,MAAM,YAAY,IAAI,WAAW;AAEjC,gBAAU,SAAS;OAClB,cAAc;QACb,MAAM,gBAAgB,gBAAgB;QACtC,MAAM,iBAAiB,OAAO,SAAS;QACvC,MAAM,cAAc,CAAC,GAAG,gBAAgB,CAAC,QACvC,QACA,CAAC,eAAe,IAAI,IAA2B,CAChD,CAAC;QACF,MAAM,eAAe,OAAO,SAAS;AACrC,eAAO;SACN,MAAM,GACL,UACA,MAAM,KAAK,sBAAsB,CACjC;SACD,MAAM,GACL,SACA,GAAG,cAAc,mBAAmB,eAAe,oBAAoB,YAAY,iBAAiB,aAAa,eACjH;SACD;SACA;;OAEF,kBAAkB;OAClB,CAAC;MAEF,MAAM,gBAAgB,IAAI,aACzB,OACA,KAAK,IAAI,KAAK,IAAI,MAAM,SAAS,GAAG,EAAE,EAAE,GAAG,EAC3C;OACC,QAAQ,MAAM,GAAG,UAAU,IAAI;OAC/B,QAAQ,MAAM,aACb,WAAW,MAAM,GAAG,UAAU,KAAK,GAAG;OACvC,QAAQ,MAAM,aAAa;QAC1B,MAAM,QAAQ,SAASF,YAAU,YAAY;QAC7C,MAAM,WAAW,MAAM,GAAG,OAAO,KAAK;AACtC,eAAO,WACJ,MAAM,KAAK,MAAM,GAAG,UAAU,SAAS,CAAC,GACxC;;OAEJ,cAAc,SAAS,MAAM,GAAG,SAAS,KAAK;OAC9C,OAAO,SAAS,MAAM,GAAG,OAAO,KAAK;OACrC,GACA,IAAI,cAAc;OAClB,MAAM,MAAM;OACZ,MAAM,UAAU,cAAcA;AAC9B,WAAI,QACH,iBAAgB,IAAI,IAAI;WAExB,iBAAgB,OAAO,IAAI;AAE5B,8BAAuB,KAAK,QAAQ;eAE/B,KAAK,KAAA,EAAU,EACrB,EAAE,cAAc,MAAM,CACtB;AAED,gBAAU,SAAS,cAAc;AACjC,gBAAU,SACT,IAAI,KACH,MAAM,GACL,OACA,qGACA,EACD,GACA,EACA,CACD;AAED,aAAO;OACN,OAAO,OAAe;AACrB,eAAO,UAAU,OAAO,MAAM;;OAE/B,aAAa;AACZ,kBAAU,YAAY;;OAEvB,YAAY,MAAc;AACzB,sBAAc,YAAY,KAAK;AAC/B,YAAI,eAAe;;OAEpB;OACA;AAEF,SAAI,CAACG,aAAW,iBAAiB,gBAAgB,EAAE;AAClD,UAAI,GAAG,OACN,eAAe,OAAO,IACnB,0HACA,qDACH,OACA;AACD,YAAM,IAAI,QAAQ;AAClB;;AAGD;;IAGD,MAAM,CAAC,KAAK,GAAG,SAAS,WAAW,QAAQ,MAAM,MAAM;IACvD,MAAM,MAAM,KAAK,KAAK,IAAI;IAC1B,MAAM,SACL,iCAAiC,eAAe;AAEjD,YAAQ,KAAR;KACC,KAAK;AACJ,UAAI,GAAG,OACN,uBAAuB,QAAQ,EAC9B,SAAS,uBACT,CAAC,CACF;AACD;KAED,KAAK;KACL,KAAK;KACL,KAAK,UAAU;AACd,UAAI,CAAC,KAAK;AACT,WAAI,GAAG,OACN,sBAAsB,IAAI,SAC1B,UACA;AACD;;MAGD,MAAM,YAAY,uBAAuB,IAAI;AAC7C,UAAI,CAAC,WAAW;AACf,WAAI,GAAG,OACN,sBAAsB,IAAI,SAAS,mBAAmB,KAAK,SAAS,KAAK,IAAI,CAAC,KAAK,KAAK,IACxF,UACA;AACD;;MAGD,MAAM,gBAAgB,OAAO,MAC3B,UAAU,MAAM,QAAQ,UAAU,IACnC;MACD,MAAM,eACL,QAAQ,WACL,OACA,QAAQ,YACP,QACA,CAAC,eAAe;AACrB,6BAAuB,UAAU,KAAK,aAAa;AAEnD,UAAI,GAAG,OACN,gBAAgB,eAAe,IAAI,UAAU,IAAI,GAC9C,WAAW,UAAU,IAAI,sDAAsD,UAAU,SAAS,oDAClG,GAAG,UAAU,IAAI,GAAG,eAAe,YAAY,WAAW,qBAC7D;AACD;;KAED,KAAK,UAAU;AACd,UAAI,CAAC,KAAK;AACT,WAAI,GAAG,OACN,qCACA,UACA;AACD;;MAED,MAAM,UAAU,cAAc,QAAQ,IAAI;AAC1C,UAAI,QAAQ,WAAW,GAAG;AACzB,WAAI,GAAG,OACN,oCAAoC,IAAI,GACxC;AACD;;AAED,UAAI,GAAG,OACN,uBAAuB,SAAS,EAC/B,SAAS,iCAAiC,IAAI,IAC9C,CAAC,CACF;AACD;;KAED,QACC,KAAI,GAAG,OACN,YAAY,IAAI,SAAS,KAAK,KAAK,KAAK,IACxC,UACA;;;GAGJ,CAAC;;;AAIW,6BAA6B;;;ACnW5C,MAAM,kBAAmC;CACxC;EAAE,MAAM;EAAkB,SAAS;EAAqB;CACxD;EACC,MAAM;EACN,SACC;EACD;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SACC;EACD;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SACC;EACD;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;EACC,MAAM;EACN,SAAS;EACT;CACD;AAED,SAAS,OAAO,MAAmD;CAClE,IAAI,QAAQ;CACZ,IAAI,SAAS;AAEb,MAAK,MAAM,MAAM,iBAAiB;AAEjC,KAAG,QAAQ,YAAY;AACvB,WAAS,OAAO,QAAQ,GAAG,UAAU,UAAU;AAC9C;AAEA,UAAO,GADQ,MAAM,MAAM,GAAG,EAAE,GACb,IAAI,OAAO,KAAK,IAAI,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,YAAY,GAAG,KAAK;IACjF;;AAGH,QAAO;EAAE,UAAU;EAAQ;EAAO;;AAInC,eAA8B,cAAc,IAAkB;CAC7D,IAAI,gBAAgB;AAGpB,IAAG,GAAG,eAAwB,OAAO,UAAe;AACnD,MAAI,CAAC,MAAM,QAAS;EAEpB,IAAI,WAAW;EACf,MAAM,aAAa,MAAM,QAAQ,KAC/B,SAA0C;AAC1C,OAAI,KAAK,SAAS,UAAU,CAAC,KAAK,KAAM,QAAO;GAC/C,MAAM,EAAE,UAAU,UAAU,OAAO,KAAK,KAAK;AAC7C,OAAI,QAAQ,GAAG;AACd,eAAW;AACX,qBAAiB;;AAElB,UAAO;IAAE,GAAG;IAAM,MAAM;IAAU;IAEnC;AAED,MAAI,SACH,QAAO,EAAE,SAAS,YAAY;GAE9B;AAEF,IAAG,gBAAgB,gBAAgB;EAClC,aAAa;EACb,SAAS,OAAO,OAAO,QAAQ;AAC9B,OAAI,GAAG,OACN,kCAAkC,gBAClC;;EAEF,CAAC;;;;ACnHH,eAA8B,QAAQ,IAAkB;CACvD,MAAM,UAID,EAAE;AAGP,IAAG,GAAG,eAAe,OAAO,UAAU;EACrC,MAAM,MAAM,MAAM;AAClB,MAAI,CAAC,IAAK;EAEV,MAAM,UAAU,IAAI;AAGpB,MAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE;EAE7B,MAAM,OAAO,QACX,QAAQ,MAAM,EAAE,SAAS,OAAO,CAChC,KAAK,MAAM,EAAE,QAAQ,GAAG,CACxB,KAAK,KAAK;AAEZ,MAAI,CAAC,KAAM;EAEX,MAAM,UACL,KAAK,SAAS,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,QAAQ;AAElD,UAAQ,KAAK;GACZ,MAAO,IAAI,QAAmB;GAC9B;GACA,WAAW,KAAK,KAAK;GACrB,CAAC;GACD;AAEF,IAAG,gBAAgB,WAAW;EAC7B,aACC;EACD,SAAS,OAAO,MAAM,QAAQ;GAC7B,MAAM,OAAO,KAAK,MAAM;AAExB,OAAI,QAAQ,WAAW,GAAG;AACzB,QAAI,GAAG,OACN,uCACA,UACA;AACD;;GAOD,MAAM,UAAU;;;;;EAJA,QACd,KAAK,MAAM,IAAI,EAAE,KAAK,IAAI,EAAE,UAAU,CACtC,KAAK,OAAO,CAOP;;;EAGR,QAAQ,qDAAqD;;;;;;;GAS5D,MAAM,WAAW,WAAW,KAAK,KAAK,CAAC;AAEvC,iBADiB,KAAK,IAAI,KAAK,SAAS,EAChB,SAAS,QAAQ;AAEzC,OAAI,GAAG,OACN,sBAAsB,SAAS,mBAAmB,WAClD;;EAEF,CAAC;;;;ACxDH,IAAa,YAAb,MAAuB;CACtB,QAA6B;CAC7B;CACA,UAAU;CACV,2BAAW,IAAI,KAMZ;CACH,UAAU;CAEV,YAAY,QAAyB;AACpC,QAAA,SAAe;;CAGhB,MAAM,UAAyB;EAC9B,MAAM,EAAE,SAAS,OAAO,EAAE,EAAE,QAAQ,MAAA;AAEpC,QAAA,OAAa,MAAM,SAAS,MAAM;GACjC,OAAO;IAAC;IAAQ;IAAQ;IAAO;GAC/B,KAAK;IAAE,GAAG,QAAQ;IAAK,GAAG;IAAK;GAC/B,CAAC;AAEF,QAAA,KAAW,OAAQ,YAAY,OAAO;AACtC,QAAA,KAAW,OAAQ,GAAG,SAAS,UAAkB;AAChD,SAAA,UAAgB;GAChB,MAAM,QAAQ,MAAA,OAAa,MAAM,KAAK;AACtC,SAAA,SAAe,MAAM,KAAK,IAAI;AAE9B,QAAK,MAAM,QAAQ,OAAO;AACzB,QAAI,CAAC,KAAK,MAAM,CAAE;AAClB,QAAI;KACH,MAAM,MAAM,KAAK,MAAM,KAAK;AAC5B,SAAI,IAAI,MAAM,QAAQ,MAAA,QAAc,IAAI,IAAI,GAAG,EAAE;MAChD,MAAM,IAAI,MAAA,QAAc,IAAI,IAAI,GAAG;AACnC,YAAA,QAAc,OAAO,IAAI,GAAG;AAC5B,UAAI,IAAI,MACP,GAAE,uBACD,IAAI,MACH,aAAa,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,UAC1C,CACD;UAED,GAAE,QAAQ,IAAI,OAAO;;YAGhB;;IAIR;AAGF,QAAM,MAAA,QAAc,cAAc;GACjC,iBAAiB;GACjB,cAAc,EAAE;GAChB,YAAY;IAAE,MAAM;IAAS,SAAS;IAAS;GAC/C,CAAC;AAGF,QAAA,KAAW;GACV,SAAS;GACT,QAAQ;GACR,CAA8B;;CAGhC,MAAM,YAAoC;AAIzC,UAHgB,MAAM,MAAA,QAAc,cAAc,EAAE,CAAC,EAGvC;;CAGf,MAAM,SACL,MACA,MACmB;AACnB,SAAO,MAAA,QAAc,cAAc;GAClC;GACA,WAAW;GACX,CAAC;;CAGH,MAAM,aAA4B;AACjC,MAAI,MAAA,MAAY;AACf,SAAA,KAAW,MAAM;AACjB,SAAA,OAAa;;AAEd,QAAA,QAAc,OAAO;;CAGtB,SAAS,QAAgB,QAAmC;AAC3D,SAAO,IAAI,SAAS,SAAS,WAAW;GACvC,MAAM,KAAK,MAAA;AACX,SAAA,QAAc,IAAI,IAAI;IAAE;IAAS;IAAQ,CAAC;AAC1C,SAAA,KAAW;IAAE,SAAS;IAAO;IAAI;IAAQ;IAAQ,CAAC;AAElD,oBAAiB;AAChB,QAAI,MAAA,QAAc,IAAI,GAAG,EAAE;AAC1B,WAAA,QAAc,OAAO,GAAG;AACxB,4BAAO,IAAI,MAAM,eAAe,OAAO,YAAY,CAAC;;MAEnD,IAAO;IACT;;CAGH,MAAM,KAAqB;AAC1B,MAAI,CAAC,MAAA,MAAY,OAAO,SACvB,OAAM,IAAI,MAAM,2BAA2B;AAE5C,QAAA,KAAW,MAAM,MAAM,KAAK,UAAU,IAAI,GAAG,KAAK;;;;;AC7HpD,SAAS,YAAY,MAA2C;AAC/D,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,EAAE;CAChC,MAAM,MAAM,aAAa,MAAM,QAAQ;AAEvC,QADe,KAAK,MAAM,IAAI,CAChB,cAAc,EAAE;;AAG/B,SAAgB,gBAAgB,KAAgC;CAE/D,MAAM,iBAAiB,YACtB,KAAK,SAAS,EAAE,OAAO,SAAS,WAAW,CAC3C;CAGD,MAAM,kBAAkB,YAAY,KAAK,KAAK,WAAW,CAAC;CAE1D,MAAM,SAAS;EAAE,GAAG;EAAgB,GAAG;EAAiB;AAExD,QAAO,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,MAAM,aAAa;EACtD;EACA,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,EAAE;;;;ACxBJ,eAA8B,IAAI,IAAkB;CACnD,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,0BAAU,IAAI,KAA0B;CAC9C,MAAM,UAAU,gBAAgB,IAAI;CAGpC,MAAM,UAAU,MAAM,QAAQ,WAC7B,QAAQ,IAAI,OAAO,WAAW;EAC7B,MAAM,SAAS,IAAI,UAAU,OAAO;AACpC,QAAM,OAAO,SAAS;AAEtB,SAAO;GAAE;GAAQ;GAAQ,WADP,MAAM,OAAO,WAAW;GACN;GACnC,CACF;AAED,MAAK,MAAM,UAAU,SAAS;AAC7B,MAAI,OAAO,WAAW,YAAY;AACjC,WAAQ,MAAM,sBAAsB,OAAO,SAAS;AACpD;;EAGD,MAAM,EAAE,QAAQ,QAAQ,cAAc,OAAO;EAC7C,MAAM,aAAuB,EAAE;AAE/B,OAAK,MAAM,YAAY,WAAW;GACjC,MAAM,YAAY,QAAQ,OAAO,KAAK,IAAI,SAAS;AACnD,cAAW,KAAK,UAAU;AAE1B,MAAG,aACF,WAAW;IACV,MAAM;IACN,OAAO,GAAG,OAAO,KAAK,IAAI,SAAS;IACnC,aAAa,SAAS,eAAe,SAAS;IAC9C,YAAa,SAAS,eAAe;KACpC,MAAM;KACN,YAAY,EAAE;KACd;IACD,SAAS,OAAO,KAAK,WAAW;KAC/B,MAAM,SAAU,MAAM,OAAO,SAC5B,SAAS,MACT,OACA;AAWD,YAAO;MACN,SAAS,CAAC;OAAE,MAAM;OAAiB,MAJnC,QAAQ,SAAS,KAAK,MAAM,EAAE,QAAQ,GAAG,CAAC,KAAK,KAAK,IACpD,KAAK,UAAU,OAAO;OAGmB,CAAC;MAC1C,SAAS,EAAE;MACX;;IAEF,CAAC,CACF;;AAGF,UAAQ,IAAI,OAAO,MAAM;GACxB;GACA;GACA;GACA,SAAS;GACT,CAAC;;AAGH,IAAG,gBAAgB,OAAO;EACzB,aAAa;EACb,yBAAyB,WAAW;GACnC,MAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,OAAI,MAAM,UAAU,EACnB,QAAO;IAAC;IAAQ;IAAU;IAAU,CAClC,QAAQ,MAAM,EAAE,WAAW,OAAO,CAAC,CACnC,KAAK,OAAO;IAAE,OAAO;IAAG,OAAO;IAAG,EAAE;AAEvC,OAAI,MAAM,OAAO,YAAY,MAAM,OAAO,WAAW;IACpD,MAAM,cAAc,MAAM,MAAM;AAChC,WAAO,MAAM,KAAK,QAAQ,MAAM,CAAC,CAC/B,QAAQ,MAAM,EAAE,WAAW,YAAY,CAAC,CACxC,KAAK,OAAO;KACZ,OAAO,GAAG,MAAM,GAAG,GAAG;KACtB,OAAO;KACP,EAAE;;AAEL,UAAO;;EAER,SAAS,OAAO,MAAM,QAAQ;GAC7B,MAAM,CAAC,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,MAAM,MAAM;GAC/C,MAAM,OAAO,KAAK,KAAK,IAAI;AAE3B,WAAQ,OAAO,QAAf;IACC,KAAK,QAAQ;AACZ,SAAI,QAAQ,SAAS,GAAG;AACvB,UAAI,GAAG,OAAO,4BAA4B;AAC1C;;KAED,MAAM,QAAkB,EAAE;AAC1B,UAAK,MAAM,CAAC,OAAO,UAAU,QAAQ,SAAS,EAAE;MAC/C,MAAM,SAAS,MAAM,UAAU,YAAY;AAC3C,YAAM,KACL,GAAG,MAAM,IAAI,OAAO,MAAM,MAAM,WAAW,OAAO,QAClD;;AAEF,SAAI,GAAG,OAAO,MAAM,KAAK,KAAK,CAAC;AAC/B;;IAED,KAAK,UAAU;KACd,MAAM,SAAS,QAAQ,IAAI,KAAK;AAChC,SAAI,CAAC,QAAQ;AACZ,UAAI,GAAG,OAAO,mBAAmB,QAAQ,UAAU;AACnD;;AAED,SAAI,OAAO,SAAS;AACnB,UAAI,GAAG,OAAO,GAAG,KAAK,kBAAkB;AACxC;;AAED,YAAO,UAAU;KACjB,MAAM,SAAS,GAAG,gBAAgB;AAClC,QAAG,eAAe,CAAC,GAAG,QAAQ,GAAG,OAAO,WAAW,CAAC;AACpD,SAAI,GAAG,OAAO,WAAW,OAAO;AAChC;;IAED,KAAK,WAAW;KACf,MAAM,SAAS,QAAQ,IAAI,KAAK;AAChC,SAAI,CAAC,QAAQ;AACZ,UAAI,GAAG,OAAO,mBAAmB,QAAQ,UAAU;AACnD;;AAED,SAAI,CAAC,OAAO,SAAS;AACpB,UAAI,GAAG,OAAO,GAAG,KAAK,mBAAmB;AACzC;;AAED,YAAO,UAAU;KACjB,MAAM,WAAW,IAAI,IAAI,OAAO,WAAW;AAC3C,QAAG,eACF,GAAG,gBAAgB,CAAC,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CACnD;AACD,SAAI,GAAG,OAAO,YAAY,OAAO;AACjC;;IAED,QACC,KAAI,GAAG,OACN,uBAAuB,IAAI,kCAC3B,UACA;;;EAGJ,CAAC;AAEF,IAAG,GAAG,oBAAoB,YAAY;AACrC,OAAK,MAAM,UAAU,QAAQ,QAAQ,CACpC,OAAM,OAAO,OAAO,YAAY;GAEhC;;;;ACnKH,MAAM,kBAAkB,KAAK,QAAQ,IAAI,MAAO,OAAO,cAAc;AAGrE,eAA8B,OAAO,IAAkB;AAEtD,KAAI,WAAW,gBAAgB,CAC9B,KAAI;AACH,eAAa,OAAO;GAAC;GAAY;GAAQ;GAAS,EAAE;GACnD,UAAU;GACV,SAAS;GACT,OAAO;IAAC;IAAQ;IAAQ;IAAO;GAC/B,CAAC;SACK;AAMT,IAAG,GACF,sBACA,OAAO,UAAoC;AAC1C,SAAO,EACN,cACC,MAAM,eACN;;;;;;;;;;;;;;;;;gDAkBD;GAEF;;;;ACpCF,MAAM,iBAA+B;CACpC,SAAS;CACT,SAAS,EAAE;CACX,UAAU;CACV;AAED,SAAgB,kBAA0B;AAGzC,QAAO,KADN,QAAQ,IAAI,mBAAmB,KAAK,SAAS,EAAE,UAAU,EACzC,SAAS,cAAc;;AAGzC,SAAgB,qBAAmC;CAClD,MAAM,OAAO,iBAAiB;AAC9B,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,EAAE,GAAG,gBAAgB;AAEnD,KAAI;EACH,MAAM,MAAM,aAAa,MAAM,QAAQ;EACvC,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAO;GACN,SAAS,OAAO,WAAW;GAC3B,SAAS,OAAO,WAAW,EAAE;GAC7B,UAAU,OAAO,YAAY;GAC7B;SACM;AACP,SAAO,EAAE,GAAG,gBAAgB;;;AAI9B,SAAgB,mBAAmB,QAA4B;CAC9D,MAAM,OAAO,iBAAiB;CAC9B,MAAM,MAAM,QAAQ,KAAK;AACzB,KAAI,CAAC,WAAW,IAAI,CACnB,WAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAGjD,MAAM,MAAM,GAAG,KAAK,OAAO,KAAK,KAAK;AACrC,eAAc,KAAK,KAAK,UAAU,QAAQ,MAAM,IAAK,GAAG,MAAM,EAC7D,MAAM,KACN,CAAC;AACF,YAAW,KAAK,KAAK;;AAGtB,SAAgB,eAAe,MAAc,QAAwB;AACpE,QAAO,GAAG,KAAK,GAAG;;AAGnB,SAAgB,iBACf,QACA,KACU;AACV,KAAI,OAAO,OAAO,QAAS,QAAO,OAAO,QAAQ;AACjD,QAAO,OAAO,aAAa;;;;AC5D5B,MAAa,uBAAuB;AAgDpC,SAAS,yBAAsD;CAC9D,MAAM,OAAO,KACZ,SAAS,EACT,WACA,WACA,yBACA;AACD,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO;AAE9B,KAAI;AACH,SAAO,KAAK,MACX,aAAa,MAAM,QAAQ,CAC3B;SACM;AACP,SAAO;;;AAIT,SAAS,eACR,YAC+C;AAC/C,KAAI;EAEH,MAAM,EAAE,gBACP,iBAFe,aAAa,YAAY,QAAQ,CAEL;EAC5C,MAAM,cAAc,aAAa;AACjC,MAAI,CAAC,YAAa,QAAO;AAGzB,SAAO;GAAE,MADI,aAAa,QAAQ,SAAS,QAAQ,WAAW,CAAC;GAChD,aAAa,YAAY,MAAM;GAAE;SACzC;AACP,SAAO;;;AAIT,SAAS,qBACR,UACoC;CACpC,MAAM,gBAAgB,KAAK,UAAU,qBAAqB;AAC1D,KAAI,CAAC,WAAW,cAAc,CAAE,QAAO,KAAA;AAEvC,KAAI;AACH,SAAO,KAAK,MACX,aAAa,eAAe,QAAQ,CACpC;SACM;AACP;;;AAIF,SAAS,oBACR,KACA,SAMoB;AACpB,KAAI,CAAC,WAAW,IAAI,CAAE,QAAO,EAAE;CAE/B,MAAM,UAA6B,EAAE;CACrC,MAAM,SAAS,KAAK,KAAK,WAAW;AAIpC,MAFC,QAAQ,6BAA6B,SAEL,WAAW,OAAO,EAAE;EACpD,MAAM,SAAS,eAAe,OAAO;AACrC,MAAI,OACH,SAAQ,KAAK;GACZ,GAAG;GACH,WAAW;GACX,SAAS;GACT,QAAQ,QAAQ;GAChB,MAAM,QAAQ;GACd,QAAQ,QAAQ;GAChB,aACC,QAAQ,SAAS,YACd,qBAAqB,IAAI,GACzB,KAAA;GACJ,CAAC;AAEH,SAAO;;AAGR,KAAI;EACH,MAAM,UAAU,SAAS,cAAc,EAAE,KAAK,KAAK,CAAC;AACpD,OAAK,MAAM,SAAS,SAAS;GAC5B,MAAM,YAAY,QAAQ,KAAK,MAAM;GACrC,MAAM,SAAS,eAAe,UAAU;AACxC,OAAI,QAAQ;IACX,MAAM,WAAW,QAAQ,UAAU;AACnC,YAAQ,KAAK;KACZ,GAAG;KACH,WAAW;KACX,SAAS;KACT,QAAQ,QAAQ;KAChB,MAAM,QAAQ;KACd,QAAQ,QAAQ;KAChB,aACC,QAAQ,SAAS,YACd,qBAAqB,SAAS,GAC9B,KAAA;KACJ,CAAC;;;SAGG;AAIR,QAAO;;AAGR,SAAS,qBACR,QACoB;CACpB,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,UAA6B,EAAE;AAErC,MAAK,MAAM,SAAS,QAAQ;AAC3B,MAAI,KAAK,IAAI,MAAM,UAAU,CAAE;AAC/B,OAAK,IAAI,MAAM,UAAU;AACzB,UAAQ,KAAK,MAAM;;AAGpB,QAAO;;AAGR,SAAgB,sBAAyC;CACxD,MAAM,SAA4B,EAAE;AAEpC,MAAK,MAAM,SAAS,oBACnB,KAAK,SAAS,EAAE,WAAW,SAAS,EACpC;EACC,QAAQ;EACR,MAAM;EACN,CACD,CACA,QAAO,KAAK,MAAM;AAGnB,MAAK,MAAM,SAAS,oBACnB,KAAK,SAAS,EAAE,OAAO,SAAS,SAAS,EACzC;EACC,QAAQ;EACR,MAAM;EACN,2BAA2B;EAC3B,CACD,CACA,QAAO,KAAK,MAAM;AAGnB,QAAO,qBAAqB,OAAO;;AAGpC,SAAgB,yBAA4C;CAC3D,MAAM,SAA4B,EAAE;CACpC,MAAM,UAAU,wBAAwB;AACxC,KAAI,CAAC,SAAS,QAAS,QAAO;AAE9B,MAAK,MAAM,CAAC,WAAW,YAAY,OAAO,QACzC,QAAQ,QACR,EAAE;EACF,MAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,OAAO,eAAe,CAAC,WAAW,MAAM,YAAY,CACxD;EAED,MAAM,SAAS,UAAU;EACzB,MAAM,SAA4B;GACjC,UAAU;GACV,aAAa,MAAM;GACnB,SAAS,MAAM;GACf,cAAc,MAAM;GACpB;AAED,OAAK,MAAM,SAAS,oBACnB,KAAK,MAAM,aAAa,SAAS,EACjC;GACC;GACA,MAAM;GACN;GACA,CACD,CACA,QAAO,KAAK,MAAM;AAGnB,OAAK,MAAM,SAAS,oBACnB,KAAK,MAAM,aAAa,OAAO,SAAS,EACxC;GACC;GACA,MAAM;GACN;GACA,CACD,CACA,QAAO,KAAK,MAAM;EAGnB,MAAM,oBAAoB,KAAK,MAAM,aAAa,WAAW;AAC7D,MAAI,WAAW,kBAAkB,EAAE;GAClC,MAAM,SAAS,eAAe,kBAAkB;AAChD,OAAI,OACH,QAAO,KAAK;IACX,GAAG;IACH,WAAW;IACX,SAAS,MAAM;IACf;IACA,MAAM;IACN;IACA,CAAC;;;AAKL,QAAO,qBAAqB,OAAO;;;;AC1PpC,MAAM,0BAA0B;AAEhC,SAAS,yBAAiC;AACzC,QAAO,KAAK,SAAS,EAAE,OAAO,SAAS,SAAS;;AAGjD,SAAS,WAAW,MAAoB;AACvC,WAAU,MAAM;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;;AAGlD,SAAS,uBAAuB,KAAuB;CACtD,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,SAAS,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC,EAAE;EAC9D,MAAM,YAAY,KAAK,KAAK,MAAM,KAAK;AACvC,MAAI,MAAM,SAAA,qBAA+B;AACzC,MAAI,MAAM,aAAa,EAAE;AACxB,SAAM,KAAK,GAAG,uBAAuB,UAAU,CAAC;AAChD;;AAED,MAAI,MAAM,QAAQ,CACjB,OAAM,KAAK,UAAU;;AAIvB,QAAO,MAAM,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;;AAGhD,SAAS,eAAe,KAAqB;CAC5C,MAAM,OAAO,WAAW,SAAS;AACjC,MAAK,MAAM,QAAQ,uBAAuB,IAAI,EAAE;AAC/C,OAAK,OAAO,SAAS,KAAK,KAAK,CAAC;AAChC,OAAK,OAAO,KAAK;AACjB,OAAK,OAAO,aAAa,KAAK,CAAC;AAC/B,OAAK,OAAO,KAAK;;AAElB,QAAO,KAAK,OAAO,MAAM;;AAG1B,SAAS,cACR,UACoC;CACpC,MAAM,OAAO,KAAK,UAAU,qBAAqB;AACjD,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,KAAA;AAE9B,KAAI;AACH,SAAO,KAAK,MACX,aAAa,MAAM,QAAQ,CAC3B;SACM;AACP;;;AAIF,SAAS,eACR,UACA,UACO;AACP,eACC,KAAK,UAAU,qBAAqB,EACpC,KAAK,UAAU,UAAU,MAAM,IAAK,GAAG,MACvC,EAAE,MAAM,KAAO,CACf;;AAGF,SAAS,kBACR,YACA,UACO;CACP,MAAM,aAAa,QAAQ,SAAS;AACpC,YAAW,WAAW;CACtB,MAAM,UAAU,KACf,YACA,IAAI,QAAQ,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,KAAK,GACxD;AAED,QAAO,SAAS;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AACjD,QAAO,YAAY,SAAS;EAC3B,WAAW;EACX,oBAAoB;EACpB,kBAAkB;EAClB,CAAC;AACF,QAAO,UAAU;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAClD,QAAO,SAAS,UAAU;EACzB,WAAW;EACX,oBAAoB;EACpB,kBAAkB;EAClB,CAAC;AACF,QAAO,SAAS;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;;AAQlD,SAAgB,sBACf,OACoB;AACpB,KAAI,MAAM,SAAS,WAClB,OAAM,IAAI,MAAM,SAAS,MAAM,KAAK,oBAAoB;CAGzD,MAAM,eAAe,wBAAwB;AAC7C,YAAW,aAAa;CAExB,MAAM,YAAY,KAAK,cAAc,MAAM,KAAK;AAEhD,KADiB,WAAW,UAAU,EACxB;AAEb,MAAI,CADkB,SAAS,UAAU,CACtB,aAAa,CAC/B,OAAM,IAAI,MAAM,GAAG,UAAU,gCAAgC;AAI9D,MAAI,CADsB,cAAc,UAAU,CAEjD,OAAM,IAAI,MACT,qDAAqD,YACrD;;AAIH,mBAAkB,MAAM,SAAS,UAAU;CAE3C,MAAM,gBAAgB,eAAe,MAAM,QAAQ;CACnD,MAAM,gBAAgB,eAAe,UAAU;CAC/C,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;CACpC,MAAM,WAAkC;EACvC,SAAS;EACT,QAAQ,MAAM;EACd,qBAAqB,MAAM;EAC3B,mBAAmB,MAAM;EACzB,uBAAuB,MAAM,QAAQ;EACrC,kBAAkB,MAAM,QAAQ;EAChC,yBAAyB,MAAM,QAAQ;EACvC,aAAa;EACb,gBAAgB;EAChB;EACA;EACA;AAED,gBAAe,WAAW,SAAS;AACnC,QAAO;EACN,UAAU;EACV;EACA;;AASF,SAAgB,oBACf,OACkB;AAClB,KAAI,MAAM,SAAS,aAAa,CAAC,MAAM,YACtC,OAAM,IAAI,MACT,SAAS,MAAM,KAAK,+BACpB;CAGF,MAAM,WAAW,MAAM;AACvB,KAAI,CAAC,WAAW,SAAS,kBAAkB,CAC1C,OAAM,IAAI,MACT,qCAAqC,SAAS,oBAC9C;AAIF,KADqB,eAAe,MAAM,QAAQ,KAC7B,SAAS,cAC7B,OAAM,IAAI,MACT,oBAAoB,MAAM,KAAK,8BAA8B,MAAM,UACnE;CAGF,MAAM,gBAAgB,eAAe,SAAS,kBAAkB;AAChE,KAAI,kBAAkB,SAAS,cAC9B,QAAO;EACN,UAAU,MAAM;EAChB;EACA,SAAS;EACT;AAGF,mBAAkB,SAAS,mBAAmB,MAAM,QAAQ;CAC5D,MAAM,gBAAgB,eAAe,MAAM,QAAQ;CACnD,MAAM,UAAiC;EACtC,GAAG;EACH,iCAAgB,IAAI,MAAM,EAAC,aAAa;EACxC;EACA;EACA;AACD,gBAAe,MAAM,SAAS,QAAQ;AAEtC,QAAO;EACN,UAAU,MAAM;EAChB,UAAU;EACV,SAAS;EACT;;;;AChLF,SAAS,kBAAkB,OAAgC;AAC1D,QAAO,eAAe,MAAM,MAAM,MAAM,OAAO;;AAGhD,SAAS,2BACR,QACA,aACkB;CAClB,MAAM,YAAY,OAAO,MACvB,UAAU,kBAAkB,MAAM,KAAK,YACxC;AACD,KAAI,UAAW,QAAO;CAEtB,MAAM,UAAU,OAAO,QACrB,UAAU,MAAM,SAAS,YAC1B;AACD,KAAI,QAAQ,WAAW,EACtB,QAAO,QAAQ;AAEhB,KAAI,QAAQ,SAAS,EACpB,OAAM,IAAI,MACT,yBAAyB,YAAY,6BACrC;AAGF,OAAM,IAAI,MAAM,kBAAkB,cAAc;;AAGjD,SAAgB,wBAAuC;CACtD,IAAI,SAAuB,oBAAoB;CAC/C,IAAI,gBAA0C;CAC9C,IAAI,mBAA6C;CAEjD,SAAS,cAAiC;AACzC,MAAI,CAAC,cACJ,iBAAgB,qBAAqB;AAEtC,SAAO;;CAGR,SAAS,iBAAoC;AAC5C,MAAI,CAAC,iBACJ,oBAAmB,wBAAwB;AAE5C,SAAO;;CAGR,SAAS,WAAW,OAAsC;EACzD,MAAM,MAAM,kBAAkB,MAAM;AACpC,SAAO;GACN,GAAG;GACH;GACA,SACC,MAAM,SAAS,YACZ,iBAAiB,QAAQ,IAAI,GAC7B;GACJ;;CAGF,SAAS,6BAA6C;AACrD,SAAO,aAAa,CAClB,QAAQ,UACR,iBAAiB,QAAQ,kBAAkB,MAAM,CAAC,CAClD,CACA,IAAI,WAAW;;AAGlB,QAAO;EACN,WAA2B;AAC1B,UAAO,aAAa,CAAC,IAAI,WAAW;;EAGrC,sBAAsC;AACrC,UAAO,gBAAgB,CAAC,IAAI,WAAW;;EAGxC,oBAAoB,MAAc,UAA2B;GAC5D,MAAM,aAAa,aAAa;GAChC,MAAM,QAAQ,WAAW,MAAM,MAAM,EAAE,cAAc,SAAS;AAC9D,OAAI,MACH,QAAO,iBAAiB,QAAQ,kBAAkB,MAAM,CAAC;GAG1D,MAAM,UAAU,WAAW,MAAM,MAAM,EAAE,SAAS,KAAK;AACvD,OAAI,QACH,QAAO,iBAAiB,QAAQ,kBAAkB,QAAQ,CAAC;AAK5D,UAAO;;EAGR,0BAAoC;AACnC,UAAO,4BAA4B,CAAC,KAClC,UAAU,MAAM,QACjB;;EAGF,OAAO,KAAsB;AAC5B,UAAO,QAAQ,OAAO;AACtB,sBAAmB,OAAO;AAC1B,UAAO;;EAGR,QAAQ,KAAsB;AAC7B,UAAO,QAAQ,OAAO;AACtB,sBAAmB,OAAO;AAC1B,UAAO;;EAGR,OAAO,KAAsB;GAC5B,MAAM,UAAU,iBAAiB,QAAQ,IAAI;AAC7C,UAAO,QAAQ,OAAO,CAAC;AACvB,sBAAmB,OAAO;AAC1B,UAAO,CAAC;;EAGT,OAAO,OAA+B;GACrC,MAAM,IAAI,MAAM,aAAa;AAC7B,UAAO,KAAK,UAAU,CAAC,QACrB,MACA,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAChC,EAAE,YAAY,aAAa,CAAC,SAAS,EAAE,IACvC,EAAE,OAAO,aAAa,CAAC,SAAS,EAAE,CACnC;;EAGF,kBAAkB,OAA+B;GAChD,MAAM,IAAI,MAAM,aAAa;AAC7B,UAAO,KAAK,qBAAqB,CAAC,QAChC,MACA,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAChC,EAAE,YAAY,aAAa,CAAC,SAAS,EAAE,IACvC,EAAE,OAAO,aAAa,CAAC,SAAS,EAAE,CACnC;;EAGF,aAAa,QAA8C;AAC1D,UAAO,WAAW;AAClB,sBAAmB,OAAO;;EAG3B,aAAa,aAAqB;GACjC,MAAM,QAAQ,2BACb,gBAAgB,EAChB,YACA;GACD,MAAM,SAAS,sBAAsB,MAAM;GAC3C,MAAM,cAAc,eAAe,MAAM,MAAM,YAAY;AAC3D,UAAO,QAAQ,eAAe;AAC9B,sBAAmB,OAAO;AAC1B,QAAK,SAAS;AACd,UAAO;IACN,GAAG;IACH,KAAK;IACL;;EAGF,WAAW,aAAqB;GAC/B,MAAM,QAAQ,2BACb,aAAa,EACb,YACA;GACD,MAAM,SAAS,oBAAoB,MAAM;AACzC,QAAK,SAAS;AACd,UAAO;IACN,GAAG;IACH,KAAK,kBAAkB,MAAM;IAC7B;;EAGF,UAAgB;AACf,mBAAgB;AAChB,sBAAmB;AACnB,YAAS,oBAAoB;;EAE9B;;;;AChNF,MAAM,UAAU;AAChB,MAAM,WAAW;AACjB,MAAM,OAAO;AACb,MAAM,iBAAiB;AAEvB,SAAS,YAAY,QAAwC;AAC5D,QAAO,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM;EACjC,MAAM,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK;AAC5C,MAAI,YAAY,EAAG,QAAO;EAC1B,MAAM,YAAY,EAAE,OAAO,cAAc,EAAE,OAAO;AAClD,MAAI,cAAc,EAAG,QAAO;AAC5B,SAAO,EAAE,IAAI,cAAc,EAAE,IAAI;GAChC;;AAGH,SAAS,6BACR,gBACA,OAC2B;CAC3B,MAAM,cAAc,eAAe,MACjC,cACA,UAAU,aAAa,WAAW,MAAM,WACvC,UAAU,YAAY,wBACtB,MAAM,aACN,UAAU,YAAY,sBAAsB,MAAM,SACpD;AACD,KAAI,YAAa,QAAO;AAExB,QAAO,eAAe,MACpB,cACA,UAAU,aAAa,WAAW,MAAM,UACxC,UAAU,SAAS,MAAM,KAC1B;;AAGF,SAAS,qBACR,gBACA,OAKC;CACD,MAAM,WAAW,6BAChB,gBACA,MACA;AACD,KAAI,UAAU,aAAa;EAC1B,MAAM,kBAAkB,QACvB,MAAM,QAAQ,WACd,SAAS,YAAY,oBACrB,MAAM,OAAO,YAAY,SAAS,YAAY,iBAC9C;EACD,MAAM,cAAc,QACnB,MAAM,QAAQ,gBACd,SAAS,YAAY,2BACrB,MAAM,OAAO,iBACZ,SAAS,YAAY,wBACtB;AAED,MAAI,mBAAmB,YACtB,QAAO;GACN,OAAO;GACP,QAAQ;GACR,QAAQ;GACR;AAGF,SAAO;GACN,OAAO;GACP,QAAQ,uBAAuB,SAAS;GACxC,QAAQ;GACR;;CAGF,MAAM,mBAAmB,eAAe,MACtC,cAAc,UAAU,SAAS,MAAM,KACxC;AACD,KAAI,iBACH,QAAO;EACN,OAAO;EACP,QAAQ,sBAAsB,iBAAiB;EAC/C,QAAQ;EACR;AAGF,QAAO;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR;;AAGF,SAAS,gBAAgB,OAAkC;CAC1D,MAAM,eAAe;EACpB,GAAG,MAAM,OAAO,KAAK,MAAM;EAC3B,MAAM;EACN,MAAM;EACN;AACD,KAAI,MAAM,aAAa,iBACtB,cAAa,KACZ,aAAa,MAAM,YAAY,mBAAmB,MAAM,YAAY,0BAA0B,MAAM,MAAM,YAAY,wBAAwB,MAAM,GAAG,GAAG,KAAK,KAC/J;AAGF,QAAO;EACN,IAAI,MAAM;EACV,OAAO,MAAM;EACb,aAAa,aAAa,KAAK,KAAK;EACpC,cAAc,MAAM,UAAU,UAAU;EACxC,QAAQ,CAAC,SAAS,SAAS;EAC3B;;AAGF,SAAS,2BACR,gBACA,OACc;CACd,MAAM,QAAQ,qBAAqB,gBAAgB,MAAM;CACzD,MAAM,eAAe;EACpB,GAAG,MAAM,OAAO,KAAK,MAAM;EAC3B,MAAM;EACN,MAAM;EACN;AACD,KAAI,MAAM,QAAQ,QACjB,cAAa,KACZ,WAAW,MAAM,OAAO,UAAU,MAAM,OAAO,eAAe,MAAM,MAAM,OAAO,aAAa,MAAM,GAAG,GAAG,KAAK,KAC/G;AAGF,KAAI,MAAM,WAAW,SACpB,QAAO;EACN,IAAI,MAAM;EACV,OAAO,MAAM;EACb,aAAa,aAAa,KAAK,KAAK;EACpC,cAAc;EACd,QAAQ,CAAC,SAAS,SAAS;EAC3B;AAGF,KAAI,MAAM,WAAW,QAAQ;AAC5B,eAAa,KAAK,gBAAgB;AAClC,SAAO;GACN,IAAI,MAAM;GACV,OAAO,MAAM;GACb,aAAa,aAAa,KAAK,KAAK;GACpC,cAAc;GACd,QAAQ,CAAC,KAAK;GACd;;AAGF,cAAa,KAAK,MAAM,OAAO;AAC/B,QAAO;EACN,IAAI,MAAM;EACV,OAAO,MAAM;EACb,aAAa,aAAa,KAAK,KAAK;EACpC,cAAc;EACd;;AAGF,SAAS,WACR,GACA,GACU;AACV,KAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,MAAK,MAAM,SAAS,EACnB,KAAI,CAAC,EAAE,IAAI,MAAM,CAAE,QAAO;AAE3B,QAAO;;AAIR,eAA8B,OAAO,IAAkB;CACtD,MAAM,MAAM,uBAAuB;CAEnC,MAAM,OAAO;EAAC;EAAU;EAAQ;EAAW;EAAW;AAEtD,IAAG,gBAAgB,UAAU;EAC5B,aAAa;EACb,yBAAyB,WAAW;GACnC,MAAM,QAAQ,OAAO,MAAM,CAAC,MAAM,MAAM;AACxC,OAAI,MAAM,UAAU,EACnB,QAAO,KACL,QAAQ,MAAM,EAAE,WAAW,MAAM,MAAM,GAAG,CAAC,CAC3C,KAAK,OAAO;IAAE,OAAO;IAAG,OAAO;IAAG,EAAE;AAGvC,OAAI,MAAM,OAAO,UAAU;IAC1B,MAAM,IAAI,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,aAAa;AAChD,WAAO,YAAY,IAAI,qBAAqB,CAAC,CAC3C,QACC,MACA,EAAE,IAAI,aAAa,CAAC,SAAS,EAAE,IAC/B,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,CACjC,CACA,MAAM,GAAG,GAAG,CACZ,KAAK,OAAO;KACZ,OAAO,GAAG,MAAM,GAAG,GAAG,EAAE;KACxB,OAAO,EAAE;KACT,EAAE;;AAGL,OAAI,MAAM,OAAO,QAAQ;IACxB,MAAM,IAAI,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,aAAa;AAChD,WAAO,YACN,IACE,UAAU,CACV,QAAQ,UAAU,QAAQ,MAAM,YAAY,CAAC,CAC/C,CACC,QACC,MACA,EAAE,IAAI,aAAa,CAAC,SAAS,EAAE,IAC/B,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,CACjC,CACA,MAAM,GAAG,GAAG,CACZ,KAAK,OAAO;KACZ,OAAO,GAAG,MAAM,GAAG,GAAG,EAAE;KACxB,OAAO,EAAE;KACT,EAAE;;AAGL,UAAO;;EAER,SAAS,OAAO,MAAM,QAAQ;GAC7B,MAAM,UAAU,KAAK,MAAM;AAE3B,OAAI,CAAC,WAAW,IAAI,OAAO;IAC1B,MAAM,aAAa,YAAY,IAAI,UAAU,CAAC;IAC9C,MAAM,aAAa,YAAY,IAAI,qBAAqB,CAAC;AACzD,QAAI,WAAW,WAAW,KAAK,WAAW,WAAW,GAAG;AACvD,SAAI,GAAG,OAAO,wCAAwC;AACtD;;IAGD,MAAM,kBAAkB,IAAI,IAC3B,WACE,QAAQ,UAAU,MAAM,QAAQ,CAChC,KAAK,UAAU,MAAM,IAAI,CAC3B;IACD,MAAM,kBAAkB,IAAI,IAAI,gBAAgB;IAChD,MAAM,iCAAiB,IAAI,KAAa;IACxC,IAAI,gBAA+B;IAEnC,MAAM,gBAAgB,WAAW,IAAI,gBAAgB;IACrD,MAAM,mBAAmB,WAAW,KAAK,UACxC,2BAA2B,YAAY,MAAM,CAC7C;IAED,MAAM,YAA2B,EAAE;AACnC,QAAI,cAAc,SAAS,GAAG;AAC7B,eAAU,KAAK;MACd,IAAI;MACJ,OAAO,eAAe,cAAc,OAAO;MAC3C,aAAa;MACb,cAAc;MACd,CAAC;AACF,eAAU,KAAK,GAAG,cAAc;;AAEjC,QAAI,iBAAiB,SAAS,GAAG;AAChC,eAAU,KAAK;MACd,IAAI;MACJ,OAAO,kBAAkB,iBAAiB,OAAO;MACjD,aAAa;MACb,cAAc;MACd,CAAC;AACF,eAAU,KAAK,GAAG,iBAAiB;;IAGpC,MAAM,eAAe,IAAI,IAAI,WAAW,KAAK,MAAM,EAAE,IAAI,CAAC;IAC1D,MAAM,iBAAiB,IAAI,IAC1B,WAAW,KAAK,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CACjC;AAED,UAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,KAAK,SAAS;KAC9C,MAAM,OAAO,IAAI,aAChB,WACA,KAAK,IAAI,KAAK,IAAI,UAAU,SAAS,GAAG,EAAE,EAAE,GAAG,EAC/C;MACC,QAAQ,MAAM,GAAG,UAAU,IAAI;MAC/B,QAAQ,MAAM,aAAa;AAC1B,WAAI,KAAK,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK,CAC/C,QAAO,MAAM,GAAG,OAAO,MAAM,KAAK,KAAK,CAAC;AAEzC,cAAO,WAAW,MAAM,GAAG,UAAU,KAAK,GAAG;;MAE9C,QAAQ,MAAM,aAAa;OAC1B,MAAM,QACL,SAAS,UACL,YACD,SAAS,OACP,YACD,SAAS,iBACP,YACA;OACP,MAAM,WAAW,MAAM,GAAG,OAAO,KAAK;AACtC,cAAO,WACJ,MAAM,KAAK,MAAM,GAAG,UAAU,SAAS,CAAC,GACxC;;MAEJ,cAAc,SAAS,MAAM,GAAG,SAAS,KAAK;MAC9C,OAAO,SAAS,MAAM,GAAG,OAAO,KAAK;MACrC,GACA,IAAI,cAAc;AAClB,UAAI,GAAG,WAAW,YAAY,CAAE;AAEhC,UAAI,aAAa,IAAI,GAAG,EAAE;AACzB,WAAI,cAAc,SAAS;AAC1B,wBAAgB,IAAI,GAAG;AACvB,YAAI,OAAO,GAAG;cACR;AACN,wBAAgB,OAAO,GAAG;AAC1B,YAAI,QAAQ,GAAG;;AAEhB;;MAGD,MAAM,eAAe,eAAe,IAAI,GAAG;AAC3C,UAAI,CAAC,aAAc;MAEnB,MAAM,QAAQ,qBACb,YACA,aACA;AAED,UAAI,MAAM,WAAW,UAAU;AAC9B,WAAI,cAAc,QACjB,gBAAe,IAAI,GAAG;WAEtB,gBAAe,OAAO,GAAG;AAE1B;;AAGD,UAAI,MAAM,WAAW,QAAQ;OAC5B,MAAM,iBAAiB,6BACtB,YACA,aACA;AACD,WAAI,CAAC,gBAAgB;AACpB,YAAI,GAAG,OACN,qBAAqB,aAAa,KAAK,iBACvC,UACA;AACD;;AAED,WAAI;AAEH,YADe,IAAI,WAAW,eAAe,IAAI,CACtC,SAAS;AACnB,yBAAgB,UAAU,aAAa,KAAK;AAC5C,cAAK,KAAA,EAAU;cAEf,KAAI,GAAG,OACN,GAAG,aAAa,KAAK,0BACrB,OACA;gBAEM,OAAO;AACf,YAAI,GAAG,OACN,iBAAiB,QACd,MAAM,UACN,OAAO,MAAM,EAChB,UACA;;;cAIE,KAAK,KAAA,EAAU,EACrB,EAAE,cAAc,MAAM,CACtB;KAED,MAAM,YAAY,IAAI,WAAW;AAEjC,eAAU,SAAS;MAClB,cAAc;OACb,MAAM,UAAU,gBAAgB;OAChC,MAAM,WAAW,WAAW,SAAS;OACrC,MAAM,SAAS,eAAe;OAC9B,MAAM,QAAQ,CACb,GAAG,QAAQ,WACX,GAAG,SAAS,WACZ;AACD,WAAI,WAAW,SAAS,EACvB,OAAM,KAAK,GAAG,WAAW,OAAO,aAAa;AAE9C,WAAI,SAAS,EACZ,OAAM,KAAK,GAAG,OAAO,oBAAoB;AAE1C,cAAO;QACN,MAAM,GAAG,UAAU,MAAM,KAAK,SAAS,CAAC;QACxC,MAAM,GAAG,SAAS,MAAM,KAAK,MAAM,CAAC;QACpC;QACA;;MAEF,kBAAkB;MAClB,CAAC;AAEF,eAAU,SAAS;MAClB,OAAO,OAAe;AACrB,cAAO,KAAK,OAAO,MAAM;;MAE1B,aAAa;AACZ,YAAK,YAAY;;MAElB,CAAC;AAEF,eAAU,SACT,IAAI,KACH,MAAM,GACL,OACA,6CACA,EACD,GACA,EACA,CACD;AAED,YAAO;MACN,OAAO,OAAe;AACrB,cAAO,UAAU,OAAO,MAAM;;MAE/B,aAAa;AACZ,iBAAU,YAAY;;MAEvB,YAAY,MAAc;AACzB,YAAK,YAAY,KAAK;AACtB,WAAI,eAAe;;MAEpB;MACA;AAEF,QAAI,eAAe,OAAO,GAAG;KAC5B,MAAM,iBAA2B,EAAE;AACnC,UAAK,MAAM,OAAO,eACjB,KAAI;AACH,UAAI,aAAa,IAAI;AACrB,qBAAe,KAAK,IAAI;cAChB,OAAO;AACf,UAAI,GAAG,OACN,iBAAiB,QACd,MAAM,UACN,OAAO,MAAM,EAChB,UACA;;AAGH,SAAI,eAAe,SAAS,EAC3B,iBAAgB,YAAY,eAAe,OAAO;;AAIpD,QAAI,eAAe;AAClB,SAAI,GAAG,OAAO,eAAe,OAAO;AACpC,WAAM,IAAI,QAAQ;AAClB;;AAGD,QAAI,CAAC,WAAW,iBAAiB,gBAAgB,EAAE;AAClD,SAAI,GAAG,OACN,wCACA,OACA;AACD,WAAM,IAAI,QAAQ;AAClB;;AAGD;;GAGD,MAAM,CAAC,KAAK,GAAG,SAAS,WAAW,QAAQ,MAAM,MAAM;GACvD,MAAM,MAAM,KAAK,KAAK,IAAI;AAE1B,WAAQ,KAAR;IACC,KAAK;AACJ,SAAI,CAAC,KAAK;AACT,UAAI,GAAG,OACN,oCACA,UACA;AACD;;AAED,SAAI;MACH,MAAM,SAAS,IAAI,aAAa,IAAI;AACpC,UAAI,GAAG,OACN,YAAY,IAAI,MAAM,OAAO,SAAS,iBACtC,OACA;AACD,YAAM,IAAI,QAAQ;AAClB;cACQ,OAAO;AACf,UAAI,GAAG,OACN,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EACtD,UACA;AACD;;IAGF,KAAK;AACJ,SAAI,CAAC,KAAK;AACT,UAAI,GAAG,OACN,kCACA,UACA;AACD;;AAED,SAAI;MACH,MAAM,SAAS,IAAI,WAAW,IAAI;AAClC,UAAI,GAAG,OACN,OAAO,UACJ,UAAU,IAAI,kBACd,GAAG,IAAI,0BACV,OACA;AACD,UAAI,OAAO,QACV,OAAM,IAAI,QAAQ;AAEnB;cACQ,OAAO;AACf,UAAI,GAAG,OACN,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EACtD,UACA;AACD;;IAGF,KAAK;AACJ,SAAI,SAAS;AACb,SAAI,GAAG,OACN,cAAc,IAAI,UAAU,CAAC,OAAO,mBAAmB,IAAI,qBAAqB,CAAC,OAAO,0BACxF;AACD;IAED,KAAK;AACJ,SAAI,QAAQ,iBAAiB,QAAQ,gBAAgB;AACpD,UAAI,GAAG,OACN,sDACA,UACA;AACD;;AAED,SAAI,aAAa,IAAI;AACrB,SAAI,GAAG,OAAO,mBAAmB,MAAM;AACvC;IAED,QACC,KAAI,GAAG,OACN,YAAY,IAAI,SAAS,KAAK,KAAK,KAAK,IACxC,UACA;;;EAGJ,CAAC;;;;ACtgBH,MAAM,8BAGF;CACEQ;CACGC;CACDC;CACP,iBAAiBC;CACRC;CACDC;CACR;AAED,SAAS,4BACR,SASmC;CACnC,MAAM,iCAAiB,IAAI,KAA0B;AACrD,KAAI,CAAC,QAAQ,IAAK,gBAAe,IAAI,MAAM;AAC3C,KAAI,CAAC,QAAQ,OAAQ,gBAAe,IAAI,SAAS;AACjD,KAAI,CAAC,QAAQ,MAAO,gBAAe,IAAI,QAAQ;AAC/C,KAAI,CAAC,QAAQ,cAAe,gBAAe,IAAI,gBAAgB;AAC/D,KAAI,CAAC,QAAQ,QAAS,gBAAe,IAAI,UAAU;AACnD,KAAI,CAAC,QAAQ,OAAQ,gBAAe,IAAI,SAAS;AACjD,QAAO;;AAGR,SAAS,iCACR,KACA,WACA,gBACmB;AACnB,QAAO,OAAO,OAAO;AAEpB,MAAI,CAAC,4BADU,gCAAgC,EACN,KAAK,eAAe,CAC5D;AAED,QAAM,UAAU,GAAG;;;AAIrB,SAAS,2BACR,sBACuD;CACvD,MAAM,gBAAgB,IAAI,IAAI,qBAAqB;AACnD,SAAQ,SAAS;EAChB,MAAM,UAAU,IAAI,IACnB,KAAK,WAAW,KAAK,cAAc,CAAC,UAAU,MAAM,UAAU,CAAC,CAC/D;EACD,MAAM,kBAAkB,qBACtB,KAAK,SAAS,QAAQ,IAAI,KAAK,CAAC,CAChC,QAEC,cAEA,QAAQ,UAAU,CACnB;EACF,MAAM,SAAS,KAAK,WAAW,QAC7B,cAAc,CAAC,cAAc,IAAI,UAAU,KAAK,CACjD;AACD,SAAO;GACN,GAAG;GACH,YAAY,CAAC,GAAG,iBAAiB,GAAG,OAAO;GAC3C;;;AAIH,eAAsB,aAAa,UAA6B,EAAE,EAAE;CACnE,MAAM,EACL,MAAM,QAAQ,KAAK,EACnB,aAAa,EAAE,EACf,oBAAoB,iBAAiB,EAAE,EACvC,MAAM,MACN,SAAS,MACT,QAAQ,MACR,gBAAgB,MAChB,UAAU,MACV,SAAS,MACT,UACG;CAEJ,MAAM,sBAAsB,WAAW,KAAK,MAAM,QAAQ,KAAK,EAAE,CAAC;CAClE,MAAM,iBAAiB,4BAA4B;EAClD;EACA;EACA;EACA;EACA;EACA;EACA,CAAC;CACF,MAAM,8BAAkD,CACvD,4BAA4B,EAAE,gBAAgB,CAAC,EAC/C,GAAG,mBAAmB,KAAK,cAC1B,iCACC,UAAU,KACV,4BAA4B,UAAU,MACtC,eACA,CACD,CACD;CACD,MAAM,uBAAuB,4BAA4B,KACvD,GAAG,UAAU,WAAW,QAAQ,EAAE,GACnC;CAED,MAAM,iBAAiB,OAAO,EAC7B,KAAK,aACL,gBACA,wBAKK;EACL,MAAM,mBAAmB,eACf;GACP,MAAM,KAAK,gBAAgB,OAAO,YAAY;AAC9C,MAAG,gBAAgB,MAAM;AACzB,UAAO;MACJ,GACH,KAAA;EAEH,MAAM,WAAW,MAAM,2BAA2B;GACjD,KAAK;GACL,GAAI,mBACD,EAAE,iBAAiB,kBAAkB,GACrC,EAAE;GACL,uBAAuB;IACtB,0BAA0B,CAAC,GAAG,oBAAoB;IAClD,oBAAoB,CACnB,GAAG,6BACH,GAAG,eACH;IACD,oBAAoB,2BACnB,qBACA;IACD,iBAAiB,SAAc;AAE9B,SACC,CAAC,4BAFa,gCAAgC,EAI7C,UACA,eACA,CAED,QAAO;KAGR,MAAM,iBAAiB,uBAAuB;AAC9C,YAAO;MACN,GAAG;MACH,QAAQ,KAAK,OAAO,QAAQ,UAC3B,eAAe,oBACd,MAAM,MACN,MAAM,SACN,CACD;MACD;;IAEF;GACD,CAAC;AAEF,SAAO;GACN,GAAI,MAAM,+BAA+B;IACxC;IACA;IACmB;IACnB,CAAC;GACF;GACA,aAAa,SAAS;GACtB;;AAGF,QAAO,0BAA0B,gBAAgB;EAChD;EACA,UAAU,aAAa;EACvB,gBAAgB,eAAe,OAAO,IAAI;EAC1C,CAAC"}
|
package/dist/api.js
CHANGED
|
@@ -1,50 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
//#region src/api.ts
|
|
5
|
-
const ext_dir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "src", "extensions");
|
|
6
|
-
async function create_my_pi(options = {}) {
|
|
7
|
-
const { cwd = process.cwd(), extensions = [], extensionFactories: user_factories = [], mcp = true, skills = true, chain = true, filter_output = true, handoff = true, recall = true, model } = options;
|
|
8
|
-
const resolved_extensions = extensions.map((p) => resolve(cwd, p));
|
|
9
|
-
const builtin_extension_paths = [
|
|
10
|
-
...mcp ? [resolve(ext_dir, "mcp.ts")] : [],
|
|
11
|
-
...skills ? [resolve(ext_dir, "skills.ts")] : [],
|
|
12
|
-
...chain ? [resolve(ext_dir, "chain.ts")] : [],
|
|
13
|
-
...filter_output ? [resolve(ext_dir, "filter-output.ts")] : [],
|
|
14
|
-
...handoff ? [resolve(ext_dir, "handoff.ts")] : [],
|
|
15
|
-
...recall ? [resolve(ext_dir, "recall.ts")] : []
|
|
16
|
-
];
|
|
17
|
-
const create_runtime = async ({ cwd: runtime_cwd, sessionManager, sessionStartEvent }) => {
|
|
18
|
-
const settings_manager = model ? (() => {
|
|
19
|
-
const sm = SettingsManager.create(runtime_cwd);
|
|
20
|
-
sm.setDefaultModel(model);
|
|
21
|
-
return sm;
|
|
22
|
-
})() : void 0;
|
|
23
|
-
const services = await createAgentSessionServices({
|
|
24
|
-
cwd: runtime_cwd,
|
|
25
|
-
...settings_manager && { settingsManager: settings_manager },
|
|
26
|
-
resourceLoaderOptions: {
|
|
27
|
-
additionalExtensionPaths: [...builtin_extension_paths, ...resolved_extensions],
|
|
28
|
-
extensionFactories: [...user_factories]
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return {
|
|
32
|
-
...await createAgentSessionFromServices({
|
|
33
|
-
services,
|
|
34
|
-
sessionManager,
|
|
35
|
-
sessionStartEvent
|
|
36
|
-
}),
|
|
37
|
-
services,
|
|
38
|
-
diagnostics: services.diagnostics
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
return createAgentSessionRuntime(create_runtime, {
|
|
42
|
-
cwd,
|
|
43
|
-
agentDir: getAgentDir(),
|
|
44
|
-
sessionManager: SessionManager.create(cwd)
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
//#endregion
|
|
1
|
+
import { n as create_my_pi, r as runPrintMode, t as InteractiveMode } from "./api-B6KnhtN9.js";
|
|
48
2
|
export { InteractiveMode, create_my_pi, runPrintMode };
|
|
49
|
-
|
|
50
|
-
//# sourceMappingURL=api.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { create_my_pi } from "./api.js";
|
|
2
|
+
import { n as create_my_pi } from "./api-B6KnhtN9.js";
|
|
3
3
|
import { InteractiveMode, runPrintMode } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import { defineCommand, runMain } from "citty";
|
|
5
5
|
import { readFileSync } from "node:fs";
|
|
@@ -118,7 +118,7 @@ runMain(defineCommand({
|
|
|
118
118
|
console.log(" my-pi -e a.ts -e b.ts Stack multiple extensions");
|
|
119
119
|
console.log(" echo \"prompt\" | my-pi --json Pipe stdin as prompt");
|
|
120
120
|
console.log(" my-pi -m claude-haiku-4-5-20241022 Set initial model");
|
|
121
|
-
console.log(" my-pi --no-builtin -e ext.ts Skip
|
|
121
|
+
console.log(" my-pi --no-builtin -e ext.ts Skip all built-in extensions");
|
|
122
122
|
} else await new InteractiveMode(runtime, {
|
|
123
123
|
migratedProviders: [],
|
|
124
124
|
modelFallbackMessage: void 0,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n// CLI for my-pi — composable pi coding agent\n// Extension stacking patterns inspired by https://github.com/disler/pi-vs-claude-code\n\nimport {\n\tInteractiveMode,\n\trunPrintMode,\n} from '@mariozechner/pi-coding-agent';\nimport { defineCommand, runMain } from 'citty';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { create_my_pi } from './api.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(\n\treadFileSync(join(__dirname, '..', 'package.json'), 'utf-8'),\n);\n\n// citty can't handle repeatable args, so parse -e from argv directly\n// (citty uses strict: false, so unknown flags are silently ignored)\nfunction parse_extension_paths(argv: string[]): string[] {\n\tconst paths: string[] = [];\n\tfor (let i = 0; i < argv.length; i++) {\n\t\tif (\n\t\t\t(argv[i] === '-e' || argv[i] === '--extension') &&\n\t\t\ti + 1 < argv.length\n\t\t) {\n\t\t\tpaths.push(resolve(argv[++i]));\n\t\t}\n\t}\n\treturn paths;\n}\n\nasync function read_stdin(): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\tfor await (const chunk of process.stdin) {\n\t\tchunks.push(chunk as Buffer);\n\t}\n\treturn Buffer.concat(chunks).toString('utf-8').trim();\n}\n\nconst main = defineCommand({\n\tmeta: {\n\t\tname: 'my-pi',\n\t\tversion: pkg.version,\n\t\tdescription:\n\t\t\t'Composable pi coding agent with MCP tools and extension stacking',\n\t},\n\targs: {\n\t\tprint: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'P',\n\t\t\tdescription: 'Print mode (non-interactive, one-shot)',\n\t\t\tdefault: false,\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'j',\n\t\t\tdescription: 'Output NDJSON events (for agent consumption)',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-builtin': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable all built-in extensions',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-mcp': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in MCP extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-skills': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in skills extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-chain': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in chain extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-filter': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable secret redaction in tool output',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-handoff': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable handoff extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-recall': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable recall extension',\n\t\t\tdefault: false,\n\t\t},\n\t\tmodel: {\n\t\t\ttype: 'string',\n\t\t\talias: 'm',\n\t\t\tdescription: 'Model to use (e.g. claude-sonnet-4-5-20241022)',\n\t\t},\n\t\tprompt: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: 'Initial prompt (optional)',\n\t\t\trequired: false,\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst cwd = process.cwd();\n\t\tconst extension_paths = parse_extension_paths(process.argv);\n\n\t\t// Stdin piping: read all stdin as prompt when piped\n\t\tlet prompt = args.prompt;\n\t\tif (!prompt && !process.stdin.isTTY) {\n\t\t\tprompt = await read_stdin();\n\t\t}\n\n\t\tconst runtime = await create_my_pi({\n\t\t\tcwd,\n\t\t\textensions: extension_paths,\n\t\t\tmcp: !args['no-builtin'] && !args['no-mcp'],\n\t\t\tskills: !args['no-builtin'] && !args['no-skills'],\n\t\t\tchain: !args['no-builtin'] && !args['no-chain'],\n\t\t\tfilter_output: !args['no-builtin'] && !args['no-filter'],\n\t\t\thandoff: !args['no-builtin'] && !args['no-handoff'],\n\t\t\trecall: !args['no-builtin'] && !args['no-recall'],\n\t\t\tmodel: args.model,\n\t\t});\n\n\t\tif (args.print || args.json || prompt) {\n\t\t\tconst code = await runPrintMode(runtime, {\n\t\t\t\tmode: args.json ? 'json' : 'text',\n\t\t\t\tinitialMessage: prompt || '',\n\t\t\t\tinitialImages: [],\n\t\t\t\tmessages: [],\n\t\t\t});\n\t\t\tprocess.exit(code);\n\t\t} else if (!process.stdout.isTTY) {\n\t\t\tconsole.log(\n\t\t\t\t`my-pi v${pkg.version} — composable pi coding agent\\n`,\n\t\t\t);\n\t\t\tconsole.log('Usage:');\n\t\t\tconsole.log(\n\t\t\t\t' my-pi \"prompt\" One-shot print mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi Interactive TUI mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -P \"prompt\" Explicit print mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi --json \"prompt\" NDJSON output for agents',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -e ext.ts Stack an extension',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -e a.ts -e b.ts Stack multiple extensions',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' echo \"prompt\" | my-pi --json Pipe stdin as prompt',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -m claude-haiku-4-5-20241022 Set initial model',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi --no-builtin -e ext.ts Skip
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n// CLI for my-pi — composable pi coding agent\n// Extension stacking patterns inspired by https://github.com/disler/pi-vs-claude-code\n\nimport {\n\tInteractiveMode,\n\trunPrintMode,\n} from '@mariozechner/pi-coding-agent';\nimport { defineCommand, runMain } from 'citty';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { create_my_pi } from './api.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(\n\treadFileSync(join(__dirname, '..', 'package.json'), 'utf-8'),\n);\n\n// citty can't handle repeatable args, so parse -e from argv directly\n// (citty uses strict: false, so unknown flags are silently ignored)\nfunction parse_extension_paths(argv: string[]): string[] {\n\tconst paths: string[] = [];\n\tfor (let i = 0; i < argv.length; i++) {\n\t\tif (\n\t\t\t(argv[i] === '-e' || argv[i] === '--extension') &&\n\t\t\ti + 1 < argv.length\n\t\t) {\n\t\t\tpaths.push(resolve(argv[++i]));\n\t\t}\n\t}\n\treturn paths;\n}\n\nasync function read_stdin(): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\tfor await (const chunk of process.stdin) {\n\t\tchunks.push(chunk as Buffer);\n\t}\n\treturn Buffer.concat(chunks).toString('utf-8').trim();\n}\n\nconst main = defineCommand({\n\tmeta: {\n\t\tname: 'my-pi',\n\t\tversion: pkg.version,\n\t\tdescription:\n\t\t\t'Composable pi coding agent with MCP tools and extension stacking',\n\t},\n\targs: {\n\t\tprint: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'P',\n\t\t\tdescription: 'Print mode (non-interactive, one-shot)',\n\t\t\tdefault: false,\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'j',\n\t\t\tdescription: 'Output NDJSON events (for agent consumption)',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-builtin': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable all built-in extensions',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-mcp': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in MCP extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-skills': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in skills extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-chain': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable built-in chain extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-filter': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable secret redaction in tool output',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-handoff': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable handoff extension',\n\t\t\tdefault: false,\n\t\t},\n\t\t'no-recall': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Disable recall extension',\n\t\t\tdefault: false,\n\t\t},\n\t\tmodel: {\n\t\t\ttype: 'string',\n\t\t\talias: 'm',\n\t\t\tdescription: 'Model to use (e.g. claude-sonnet-4-5-20241022)',\n\t\t},\n\t\tprompt: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: 'Initial prompt (optional)',\n\t\t\trequired: false,\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst cwd = process.cwd();\n\t\tconst extension_paths = parse_extension_paths(process.argv);\n\n\t\t// Stdin piping: read all stdin as prompt when piped\n\t\tlet prompt = args.prompt;\n\t\tif (!prompt && !process.stdin.isTTY) {\n\t\t\tprompt = await read_stdin();\n\t\t}\n\n\t\tconst runtime = await create_my_pi({\n\t\t\tcwd,\n\t\t\textensions: extension_paths,\n\t\t\tmcp: !args['no-builtin'] && !args['no-mcp'],\n\t\t\tskills: !args['no-builtin'] && !args['no-skills'],\n\t\t\tchain: !args['no-builtin'] && !args['no-chain'],\n\t\t\tfilter_output: !args['no-builtin'] && !args['no-filter'],\n\t\t\thandoff: !args['no-builtin'] && !args['no-handoff'],\n\t\t\trecall: !args['no-builtin'] && !args['no-recall'],\n\t\t\tmodel: args.model,\n\t\t});\n\n\t\tif (args.print || args.json || prompt) {\n\t\t\tconst code = await runPrintMode(runtime, {\n\t\t\t\tmode: args.json ? 'json' : 'text',\n\t\t\t\tinitialMessage: prompt || '',\n\t\t\t\tinitialImages: [],\n\t\t\t\tmessages: [],\n\t\t\t});\n\t\t\tprocess.exit(code);\n\t\t} else if (!process.stdout.isTTY) {\n\t\t\tconsole.log(\n\t\t\t\t`my-pi v${pkg.version} — composable pi coding agent\\n`,\n\t\t\t);\n\t\t\tconsole.log('Usage:');\n\t\t\tconsole.log(\n\t\t\t\t' my-pi \"prompt\" One-shot print mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi Interactive TUI mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -P \"prompt\" Explicit print mode',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi --json \"prompt\" NDJSON output for agents',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -e ext.ts Stack an extension',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -e a.ts -e b.ts Stack multiple extensions',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' echo \"prompt\" | my-pi --json Pipe stdin as prompt',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi -m claude-haiku-4-5-20241022 Set initial model',\n\t\t\t);\n\t\t\tconsole.log(\n\t\t\t\t' my-pi --no-builtin -e ext.ts Skip all built-in extensions',\n\t\t\t);\n\t\t} else {\n\t\t\tconst mode = new InteractiveMode(runtime, {\n\t\t\t\tmigratedProviders: [],\n\t\t\t\tmodelFallbackMessage: undefined,\n\t\t\t\tinitialMessage: undefined,\n\t\t\t\tinitialImages: [],\n\t\t\t\tinitialMessages: [],\n\t\t\t});\n\t\t\tawait mode.run();\n\t\t}\n\t},\n});\n\nvoid runMain(main);\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-pi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Personal pi coding agent wrapper with MCP tool integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@mariozechner/pi-ai": "^0.66.1",
|
|
31
31
|
"@mariozechner/pi-coding-agent": "^0.66.1",
|
|
32
|
+
"@mariozechner/pi-tui": "^0.66.1",
|
|
32
33
|
"@sinclair/typebox": "^0.34.49",
|
|
33
34
|
"citty": "^0.2.2"
|
|
34
35
|
},
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
find_builtin_extension,
|
|
4
|
+
is_builtin_extension_active,
|
|
5
|
+
is_builtin_extension_enabled,
|
|
6
|
+
resolve_builtin_extension_states,
|
|
7
|
+
type BuiltinExtensionsConfig,
|
|
8
|
+
} from './config.js';
|
|
9
|
+
|
|
10
|
+
describe('find_builtin_extension', () => {
|
|
11
|
+
it('finds canonical keys', () => {
|
|
12
|
+
expect(find_builtin_extension('mcp')?.key).toBe('mcp');
|
|
13
|
+
expect(find_builtin_extension('filter-output')?.key).toBe(
|
|
14
|
+
'filter-output',
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('finds aliases', () => {
|
|
19
|
+
expect(find_builtin_extension('filter')?.key).toBe(
|
|
20
|
+
'filter-output',
|
|
21
|
+
);
|
|
22
|
+
expect(find_builtin_extension('skill')?.key).toBe('skills');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('is_builtin_extension_enabled', () => {
|
|
27
|
+
it('defaults to enabled when unset', () => {
|
|
28
|
+
const config: BuiltinExtensionsConfig = {
|
|
29
|
+
version: 1,
|
|
30
|
+
enabled: {},
|
|
31
|
+
};
|
|
32
|
+
expect(is_builtin_extension_enabled(config, 'recall')).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('returns explicit saved state', () => {
|
|
36
|
+
const config: BuiltinExtensionsConfig = {
|
|
37
|
+
version: 1,
|
|
38
|
+
enabled: { recall: false },
|
|
39
|
+
};
|
|
40
|
+
expect(is_builtin_extension_enabled(config, 'recall')).toBe(
|
|
41
|
+
false,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('is_builtin_extension_active', () => {
|
|
47
|
+
it('applies force-disabled overlay', () => {
|
|
48
|
+
const config: BuiltinExtensionsConfig = {
|
|
49
|
+
version: 1,
|
|
50
|
+
enabled: { recall: true },
|
|
51
|
+
};
|
|
52
|
+
const force_disabled = new Set(['recall'] as const);
|
|
53
|
+
expect(
|
|
54
|
+
is_builtin_extension_active(config, 'recall', force_disabled),
|
|
55
|
+
).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('resolve_builtin_extension_states', () => {
|
|
60
|
+
it('reports saved and effective state separately', () => {
|
|
61
|
+
const config: BuiltinExtensionsConfig = {
|
|
62
|
+
version: 1,
|
|
63
|
+
enabled: {
|
|
64
|
+
recall: true,
|
|
65
|
+
handoff: false,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const force_disabled = new Set(['recall'] as const);
|
|
69
|
+
const states = resolve_builtin_extension_states(
|
|
70
|
+
force_disabled,
|
|
71
|
+
config,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const recall = states.find((state) => state.key === 'recall');
|
|
75
|
+
expect(recall).toMatchObject({
|
|
76
|
+
saved_enabled: true,
|
|
77
|
+
effective_enabled: false,
|
|
78
|
+
forced_disabled: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const handoff = states.find((state) => state.key === 'handoff');
|
|
82
|
+
expect(handoff).toMatchObject({
|
|
83
|
+
saved_enabled: false,
|
|
84
|
+
effective_enabled: false,
|
|
85
|
+
forced_disabled: false,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|