@agimon-ai/doompi 0.0.1-alpha.16 → 0.0.1-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +49 -8
  2. package/dist/adapters/helpSkills.cjs +2 -0
  3. package/dist/adapters/helpSkills.cjs.map +1 -0
  4. package/dist/adapters/helpSkills.mjs +2 -0
  5. package/dist/adapters/helpSkills.mjs.map +1 -0
  6. package/dist/adapters/layerPackageInstaller.cjs +2 -0
  7. package/dist/adapters/layerPackageInstaller.cjs.map +1 -0
  8. package/dist/adapters/layerPackageInstaller.mjs +2 -0
  9. package/dist/adapters/layerPackageInstaller.mjs.map +1 -0
  10. package/dist/adapters/modules/moduleResolution.cjs +1 -1
  11. package/dist/adapters/modules/moduleResolution.cjs.map +1 -1
  12. package/dist/adapters/modules/moduleResolution.d.cts +5 -4
  13. package/dist/adapters/modules/moduleResolution.d.cts.map +1 -1
  14. package/dist/adapters/modules/moduleResolution.d.mts +5 -4
  15. package/dist/adapters/modules/moduleResolution.d.mts.map +1 -1
  16. package/dist/adapters/modules/moduleResolution.mjs +1 -1
  17. package/dist/adapters/modules/moduleResolution.mjs.map +1 -1
  18. package/dist/adapters/skillCatalog.cjs +1 -1
  19. package/dist/adapters/skillCatalog.cjs.map +1 -1
  20. package/dist/adapters/skillCatalog.d.cts +6 -1
  21. package/dist/adapters/skillCatalog.d.cts.map +1 -1
  22. package/dist/adapters/skillCatalog.d.mts +6 -1
  23. package/dist/adapters/skillCatalog.d.mts.map +1 -1
  24. package/dist/adapters/skillCatalog.mjs +1 -1
  25. package/dist/adapters/skillCatalog.mjs.map +1 -1
  26. package/dist/adapters/syncState.cjs +1 -1
  27. package/dist/adapters/syncState.cjs.map +1 -1
  28. package/dist/adapters/syncState.d.cts +3 -1
  29. package/dist/adapters/syncState.d.cts.map +1 -1
  30. package/dist/adapters/syncState.d.mts +3 -1
  31. package/dist/adapters/syncState.d.mts.map +1 -1
  32. package/dist/adapters/syncState.mjs +1 -1
  33. package/dist/adapters/syncState.mjs.map +1 -1
  34. package/dist/commands/buildCommand.cjs +2 -2
  35. package/dist/commands/buildCommand.cjs.map +1 -1
  36. package/dist/commands/buildCommand.mjs +2 -2
  37. package/dist/commands/buildCommand.mjs.map +1 -1
  38. package/dist/commands/syncCommand.cjs +1 -1
  39. package/dist/commands/syncCommand.cjs.map +1 -1
  40. package/dist/commands/syncCommand.d.cts.map +1 -1
  41. package/dist/commands/syncCommand.d.mts.map +1 -1
  42. package/dist/commands/syncCommand.mjs +4 -4
  43. package/dist/commands/syncCommand.mjs.map +1 -1
  44. package/dist/extensions/entries/skills.cjs +3 -2
  45. package/dist/extensions/entries/skills.cjs.map +1 -1
  46. package/dist/extensions/entries/skills.d.cts.map +1 -1
  47. package/dist/extensions/entries/skills.d.mts.map +1 -1
  48. package/dist/extensions/entries/skills.mjs +3 -2
  49. package/dist/extensions/entries/skills.mjs.map +1 -1
  50. package/dist/services/extensionAssembler.cjs +1 -1
  51. package/dist/services/extensionAssembler.cjs.map +1 -1
  52. package/dist/services/extensionAssembler.d.cts +2 -2
  53. package/dist/services/extensionAssembler.d.cts.map +1 -1
  54. package/dist/services/extensionAssembler.d.mts +2 -2
  55. package/dist/services/extensionAssembler.d.mts.map +1 -1
  56. package/dist/services/extensionAssembler.mjs +1 -1
  57. package/dist/services/extensionAssembler.mjs.map +1 -1
  58. package/dist/services/syncState.cjs +1 -1
  59. package/dist/services/syncState.d.cts +2 -2
  60. package/dist/services/syncState.d.mts +2 -2
  61. package/dist/services/syncState.mjs +1 -1
  62. package/package.json +19 -18
package/README.md CHANGED
@@ -13,7 +13,7 @@ MCP servers, and system prompts into config instead of background noise.
13
13
  Plugin systems scope what an agent knows. Nothing scopes what it can reach. Claude Code's
14
14
  `enableAllProjectMcpServers` and static denylist are repository-wide. Doompi draws that
15
15
  boundary around the session. Pick a major mode and some domains; add a profile if you want
16
- one. Three YAML files decide what loads; `doompi --explain` tells you what got in, why, and
16
+ one. Four YAML files decide what loads; `doompi --explain` tells you what got in, why, and
17
17
  what it costs before launch.
18
18
 
19
19
  It borrows its shape from [Doom Emacs Core](https://github.com/doomemacs/core): quick to
@@ -92,9 +92,10 @@ A major mode is the base config. It names the extension layers for development,
92
92
  or whatever else you do. Define as many as you like; only one is active at a time, and you
93
93
  can switch it without leaving the session.
94
94
 
95
- Minor modes are switches inside that base. They start off, stack freely, and bring their
96
- own tools and instructions when turned on. Doompi ships five:
95
+ Minor modes are battery-included switches inside that base. They start off, stack freely,
96
+ and keep their model tools and skills out of context until turned on. Doompi ships six:
97
97
 
98
+ - **Help mode** — expose package-owned guidance only while you need it.
98
99
  - **Plan mode** — make the repository read-only while you agree on an approach.
99
100
  - **Loop mode** — run a prompt now, then run it again on a schedule.
100
101
  - **Goal mode** — keep one objective in view until it is done or dismissed.
@@ -177,7 +178,7 @@ choices, then press the next key.
177
178
 
178
179
  When the keyboard is the wrong tool, autonomous Voice mode keeps the conversation going.
179
180
  You can talk to the agent while doing the chores instead of carrying a laptop around the
180
- house.
181
+ house, and the primary agent can speak its own opening, milestone, and final updates.
181
182
 
182
183
  ### Autopilot
183
184
 
@@ -255,7 +256,15 @@ their controls.
255
256
 
256
257
  `@agimon-ai/doompi-task` keeps a task graph on disk, not a disposable checklist in the
257
258
  transcript. Dependencies and delegation survive compaction, and work can be handed to a
258
- subagent—including a smaller model when the job does not need the expensive one.
259
+ subagent—including a smaller model when the job does not need the expensive one. Seeded
260
+ `minimal` and `copilot` modes select its `task` layer; omit that layer when a major mode
261
+ should not expose the task tool.
262
+
263
+ ### Runner
264
+
265
+ `@agimon-ai/doompi-runner` replaces Pi's blocking bash tool with supervised command execution in the default
266
+ Copilot mode. Short commands still return inline; long-running commands move into the background with durable
267
+ logs and remain inspectable through `SPC r r` or the `doom-runner` CLI.
259
268
 
260
269
  ### Auto-compact
261
270
 
@@ -270,6 +279,15 @@ Ordinary compaction waits for one summary to save an overgrown session.
270
279
  The work runs off-thread. Each checkpoint carries the live plan, task graph, team state,
271
280
  and user request with it, so coordination does not have to be guessed back out of prose.
272
281
 
282
+ ### Help mode
283
+
284
+ `@agimon-ai/doompi-help` keeps package guidance out of the default prompt. A fresh parent
285
+ session performs no Help retrieval and exposes no Help skills. Use `SPC h e`, or the existing
286
+ `minor_mode` client in headless sessions, to activate the package indexes; use the same action
287
+ to deactivate them before the next interaction. The initial contributors expose
288
+ `doompi-help`, `workflow-help`, and `doompi-config-help`. Child sessions never assemble the
289
+ Help runtime.
290
+
273
291
  ### MCP
274
292
 
275
293
  `@agimon-ai/doompi-mcp` is the gate between a session and its servers. It reads `.mcp.json`
@@ -321,13 +339,30 @@ explicit handoffs rather than one long conversation.
321
339
  ### Voice mode
322
340
 
323
341
  `@agimon-ai/doompi-voice` records and transcribes speech locally; audio stays on the
324
- machine. Use `SPC v v` for one recording or `SPC v a` to toggle autonomous capture. It
325
- replaces the keyboard without replacing the work already in progress.
342
+ machine. `SPC v v` is one-shot manual dictation and never enables Voice tools. `SPC v a`
343
+ toggles autonomous capture; only its exact-active TUI session receives the two Voice
344
+ façades plus the standalone `narrate` tool.
345
+
346
+ While `narrate` is available, the primary agent calls it before every user-facing final
347
+ response. One concise spoken answer is enough for a short conversation or clarification;
348
+ longer work also gets an opening and meaningful milestone calls. Each ready-to-speak
349
+ utterance is limited to 4,096 characters, waits for physical playback, and returns
350
+ `completed`, `interrupted`, `superseded`, or `failed`.
351
+
352
+ If the agent never attempts `narrate` during a run, exact-active Voice speaks one sanitized
353
+ turn-end fallback rather than leaving the final response silent. Finals of at most 320
354
+ characters use deterministic speech; longer finals use the configured
355
+ `voice.autoCapture.model` for one bounded summary, with deterministic degradation on
356
+ failure or timeout. Any `narrate` attempt suppresses this safety net, so it cannot duplicate
357
+ or retry direct speech. Voice does not generate automatic intent, plan, milestone, or tool
358
+ progress narration. External task, workflow, and user-feedback narration remains
359
+ available, and the same model continues to provide bounded command correction.
326
360
 
327
361
  ## Configuration
328
362
 
329
- Doompi keeps the session matrix in three files:
363
+ Doompi reads four configuration files:
330
364
 
365
+ - `config.yaml` defines runtime settings such as trust, editor, planning, and voice behavior.
331
366
  - `modes.yaml` defines extension layers and major modes.
332
367
  - `domains.yaml` catalogs plugins and sets session access.
333
368
  - `profiles.yaml` supplies persona files and environment defaults.
@@ -473,3 +508,9 @@ and estimated prompt cost. `dpi sync` resolves the repository configuration and
473
508
  DPI without registering it in normal Pi settings. `doompi sync --check` turns drift into a
474
509
  non-zero exit code for CI. If the explanation is surprising, fix the YAML before paying a model
475
510
  to be surprised with you.
511
+
512
+ ## Package release order
513
+
514
+ Publish `@agimon-ai/doompi-extension-contracts` first, then `@agimon-ai/doompi-help`, and only
515
+ then the `@agimon-ai/doompi` runtime that consumes them. Generated changelogs remain owned by
516
+ the release tooling.
@@ -0,0 +1,2 @@
1
+ require(`../_virtual/_rolldown/runtime.cjs`);let e=require(`@earendil-works/pi-coding-agent`),t=require(`@agimon-ai/doompi-extension-contracts/help`);function n(e){return e.slice(0,t.DOOM_HELP_MAX_DIAGNOSTIC_LENGTH)}function r(t){return{name:t.name,description:t.description,filePath:t.filePath,baseDir:t.baseDir,sourceInfo:(0,e.createSyntheticSourceInfo)(t.filePath,{source:t.source,scope:`temporary`,origin:`package`,baseDir:t.baseDir}),disableModelInvocation:!1}}function i(e){return!e||e.activation===`inactive`?[]:[...e.skills].sort((e,t)=>e.source.localeCompare(t.source)||e.name.localeCompare(t.name)||e.filePath.localeCompare(t.filePath))}function a(e){return e?e.diagnostics.map(e=>n(`Help ${e.source??`host`} [${e.code}]: ${e.message}`)):[]}function o(e,o,s=[]){let c=new Set([...e.normalSkills.map(e=>e.name),...e.deferredSkills.map(e=>e.name),...e.normalSkillNames??[]]),l=[],u=[...a(o),...s.map(n)];for(let e of i(o)){if(c.has(e.name)){u.push(n(`Help ${e.source} [HELP_SKILL_COLLISION]: '${e.name}' was ignored because a normal skill wins.`));continue}c.add(e.name),l.push(r(e))}let d=u.slice(0,t.DOOM_HELP_MAX_DIAGNOSTICS),f=[...e.deferredSkills,...l];return{skills:[...e.normalSkills,...f],additionalSkills:f,helpSkills:l,diagnostics:d,diagnosticKey:`${o?.hostGeneration??`absent`}:${o?.revision??0}:${d.join(``)}`}}function s(e){let r=[],i=(0,t.createDoomHelpSnapshotClient)(e,{source:`@agimon-ai/doompi`,onError(e){let t=e instanceof Error?e.message:String(e);r.splice(0,r.length,n(`Help client [HELP_SNAPSHOT_FAILED]: ${t}`))}}),a=!1;return{merge(e){return o(e,i.getSnapshot(),r)},dispose(){a||(a=!0,i.dispose(),r.splice(0))}}}exports.createActiveHelpSkillView=s;
2
+ //# sourceMappingURL=helpSkills.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpSkills.cjs","names":["DOOM_HELP_MAX_DIAGNOSTIC_LENGTH","DOOM_HELP_MAX_DIAGNOSTICS"],"sources":["../../src/adapters/helpSkills.ts"],"sourcesContent":["import type { DoomExtensionHost } from '@agimon-ai/doompi-extension-contracts/config';\nimport {\n createDoomHelpSnapshotClient,\n DOOM_HELP_MAX_DIAGNOSTIC_LENGTH,\n DOOM_HELP_MAX_DIAGNOSTICS,\n type DoomHelpSkill,\n type DoomHelpSnapshot,\n type DoomHelpSnapshotClient,\n} from '@agimon-ai/doompi-extension-contracts/help';\nimport { createSyntheticSourceInfo, type ExtensionAPI, type Skill } from '@earendil-works/pi-coding-agent';\n\nconst HELP_CLIENT_SOURCE = '@agimon-ai/doompi';\n\nexport interface SkillInventoryInput {\n normalSkills: readonly Skill[];\n deferredSkills: readonly Skill[];\n /** Names from Pi's command catalog when full normal Skill records are unavailable. */\n normalSkillNames?: readonly string[];\n}\n\nexport interface MergedSkillInventory {\n /** Static, deferred, then accepted Help skills in invocation-precedence order. */\n skills: readonly Skill[];\n /** Deferred and Help skills that Doom Pi must append to Pi's existing prompt inventory. */\n additionalSkills: readonly Skill[];\n /** Accepted Help skills, retained separately for the Help catalog group. */\n helpSkills: readonly Skill[];\n diagnostics: readonly string[];\n diagnosticKey: string;\n}\n\nexport interface ActiveHelpSkillView {\n merge(input: SkillInventoryInput): MergedSkillInventory;\n dispose(): void;\n}\n\nfunction boundedDiagnostic(message: string): string {\n return message.slice(0, DOOM_HELP_MAX_DIAGNOSTIC_LENGTH);\n}\n\nfunction toSkill(skill: DoomHelpSkill): Skill {\n return {\n name: skill.name,\n description: skill.description,\n filePath: skill.filePath,\n baseDir: skill.baseDir,\n sourceInfo: createSyntheticSourceInfo(skill.filePath, {\n source: skill.source,\n scope: 'temporary',\n origin: 'package',\n baseDir: skill.baseDir,\n }),\n disableModelInvocation: false,\n };\n}\n\nfunction activeHelpSkills(snapshot: DoomHelpSnapshot | undefined): DoomHelpSkill[] {\n if (!snapshot || snapshot.activation === 'inactive') return [];\n return [...snapshot.skills].sort(\n (left, right) =>\n left.source.localeCompare(right.source) ||\n left.name.localeCompare(right.name) ||\n left.filePath.localeCompare(right.filePath),\n );\n}\n\nfunction snapshotDiagnostics(snapshot: DoomHelpSnapshot | undefined): string[] {\n if (!snapshot) return [];\n return snapshot.diagnostics.map((entry) =>\n boundedDiagnostic(`Help ${entry.source ?? 'host'} [${entry.code}]: ${entry.message}`),\n );\n}\n\nexport function mergeActiveHelpSkills(\n input: SkillInventoryInput,\n snapshot: DoomHelpSnapshot | undefined,\n clientDiagnostics: readonly string[] = [],\n): MergedSkillInventory {\n const occupiedNames = new Set([\n ...input.normalSkills.map((skill) => skill.name),\n ...input.deferredSkills.map((skill) => skill.name),\n ...(input.normalSkillNames ?? []),\n ]);\n const helpSkills: Skill[] = [];\n const diagnostics = [...snapshotDiagnostics(snapshot), ...clientDiagnostics.map(boundedDiagnostic)];\n\n for (const candidate of activeHelpSkills(snapshot)) {\n if (occupiedNames.has(candidate.name)) {\n diagnostics.push(\n boundedDiagnostic(\n `Help ${candidate.source} [HELP_SKILL_COLLISION]: '${candidate.name}' was ignored because a normal skill wins.`,\n ),\n );\n continue;\n }\n occupiedNames.add(candidate.name);\n helpSkills.push(toSkill(candidate));\n }\n\n const boundedDiagnostics = diagnostics.slice(0, DOOM_HELP_MAX_DIAGNOSTICS);\n const additionalSkills = [...input.deferredSkills, ...helpSkills];\n return {\n skills: [...input.normalSkills, ...additionalSkills],\n additionalSkills,\n helpSkills,\n diagnostics: boundedDiagnostics,\n diagnosticKey: `${snapshot?.hostGeneration ?? 'absent'}:${snapshot?.revision ?? 0}:${boundedDiagnostics.join('\\u0001')}`,\n };\n}\n\nexport function createActiveHelpSkillView(pi: Pick<ExtensionAPI, 'events' | 'on'>): ActiveHelpSkillView {\n const clientDiagnostics: string[] = [];\n const client: DoomHelpSnapshotClient = createDoomHelpSnapshotClient(pi as unknown as DoomExtensionHost, {\n source: HELP_CLIENT_SOURCE,\n onError(error) {\n const message = error instanceof Error ? error.message : String(error);\n clientDiagnostics.splice(\n 0,\n clientDiagnostics.length,\n boundedDiagnostic(`Help client [HELP_SNAPSHOT_FAILED]: ${message}`),\n );\n },\n });\n let disposed = false;\n return {\n merge(input) {\n return mergeActiveHelpSkills(input, client.getSnapshot(), clientDiagnostics);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n client.dispose();\n clientDiagnostics.splice(0);\n },\n };\n}\n"],"mappings":"sJAoCA,SAAS,EAAkB,EAAyB,CAClD,OAAO,EAAQ,MAAM,EAAGA,EAAAA,gCAAgC,CAG1D,SAAS,EAAQ,EAA6B,CAC5C,MAAO,CACL,KAAM,EAAM,KACZ,YAAa,EAAM,YACnB,SAAU,EAAM,SAChB,QAAS,EAAM,QACf,YAAA,EAAA,EAAA,2BAAsC,EAAM,SAAU,CACpD,OAAQ,EAAM,OACd,MAAO,YACP,OAAQ,UACR,QAAS,EAAM,QAChB,CAAC,CACF,uBAAwB,GACzB,CAGH,SAAS,EAAiB,EAAyD,CAEjF,MADI,CAAC,GAAY,EAAS,aAAe,WAAmB,EAAE,CACvD,CAAC,GAAG,EAAS,OAAO,CAAC,MACzB,EAAM,IACL,EAAK,OAAO,cAAc,EAAM,OAAO,EACvC,EAAK,KAAK,cAAc,EAAM,KAAK,EACnC,EAAK,SAAS,cAAc,EAAM,SAAS,CAC9C,CAGH,SAAS,EAAoB,EAAkD,CAE7E,OADK,EACE,EAAS,YAAY,IAAK,GAC/B,EAAkB,QAAQ,EAAM,QAAU,OAAO,IAAI,EAAM,KAAK,KAAK,EAAM,UAAU,CACtF,CAHqB,EAAE,CAM1B,SAAgB,EACd,EACA,EACA,EAAuC,EAAE,CACnB,CACtB,IAAM,EAAgB,IAAI,IAAI,CAC5B,GAAG,EAAM,aAAa,IAAK,GAAU,EAAM,KAAK,CAChD,GAAG,EAAM,eAAe,IAAK,GAAU,EAAM,KAAK,CAClD,GAAI,EAAM,kBAAoB,EAAE,CACjC,CAAC,CACI,EAAsB,EAAE,CACxB,EAAc,CAAC,GAAG,EAAoB,EAAS,CAAE,GAAG,EAAkB,IAAI,EAAkB,CAAC,CAEnG,IAAK,IAAM,KAAa,EAAiB,EAAS,CAAE,CAClD,GAAI,EAAc,IAAI,EAAU,KAAK,CAAE,CACrC,EAAY,KACV,EACE,QAAQ,EAAU,OAAO,4BAA4B,EAAU,KAAK,4CACrE,CACF,CACD,SAEF,EAAc,IAAI,EAAU,KAAK,CACjC,EAAW,KAAK,EAAQ,EAAU,CAAC,CAGrC,IAAM,EAAqB,EAAY,MAAM,EAAGC,EAAAA,0BAA0B,CACpE,EAAmB,CAAC,GAAG,EAAM,eAAgB,GAAG,EAAW,CACjE,MAAO,CACL,OAAQ,CAAC,GAAG,EAAM,aAAc,GAAG,EAAiB,CACpD,mBACA,aACA,YAAa,EACb,cAAe,GAAG,GAAU,gBAAkB,SAAS,GAAG,GAAU,UAAY,EAAE,GAAG,EAAmB,KAAK,IAAS,GACvH,CAGH,SAAgB,EAA0B,EAA8D,CACtG,IAAM,EAA8B,EAAE,CAChC,GAAA,EAAA,EAAA,8BAA8D,EAAoC,CACtG,OAAQ,oBACR,QAAQ,EAAO,CACb,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CACtE,EAAkB,OAChB,EACA,EAAkB,OAClB,EAAkB,uCAAuC,IAAU,CACpE,EAEJ,CAAC,CACE,EAAW,GACf,MAAO,CACL,MAAM,EAAO,CACX,OAAO,EAAsB,EAAO,EAAO,aAAa,CAAE,EAAkB,EAE9E,SAAU,CACJ,IACJ,EAAW,GACX,EAAO,SAAS,CAChB,EAAkB,OAAO,EAAE,GAE9B"}
@@ -0,0 +1,2 @@
1
+ import{createSyntheticSourceInfo as e}from"@earendil-works/pi-coding-agent";import{DOOM_HELP_MAX_DIAGNOSTICS as t,DOOM_HELP_MAX_DIAGNOSTIC_LENGTH as n,createDoomHelpSnapshotClient as r}from"@agimon-ai/doompi-extension-contracts/help";function i(e){return e.slice(0,n)}function a(t){return{name:t.name,description:t.description,filePath:t.filePath,baseDir:t.baseDir,sourceInfo:e(t.filePath,{source:t.source,scope:`temporary`,origin:`package`,baseDir:t.baseDir}),disableModelInvocation:!1}}function o(e){return!e||e.activation===`inactive`?[]:[...e.skills].sort((e,t)=>e.source.localeCompare(t.source)||e.name.localeCompare(t.name)||e.filePath.localeCompare(t.filePath))}function s(e){return e?e.diagnostics.map(e=>i(`Help ${e.source??`host`} [${e.code}]: ${e.message}`)):[]}function c(e,n,r=[]){let c=new Set([...e.normalSkills.map(e=>e.name),...e.deferredSkills.map(e=>e.name),...e.normalSkillNames??[]]),l=[],u=[...s(n),...r.map(i)];for(let e of o(n)){if(c.has(e.name)){u.push(i(`Help ${e.source} [HELP_SKILL_COLLISION]: '${e.name}' was ignored because a normal skill wins.`));continue}c.add(e.name),l.push(a(e))}let d=u.slice(0,t),f=[...e.deferredSkills,...l];return{skills:[...e.normalSkills,...f],additionalSkills:f,helpSkills:l,diagnostics:d,diagnosticKey:`${n?.hostGeneration??`absent`}:${n?.revision??0}:${d.join(``)}`}}function l(e){let t=[],n=r(e,{source:`@agimon-ai/doompi`,onError(e){let n=e instanceof Error?e.message:String(e);t.splice(0,t.length,i(`Help client [HELP_SNAPSHOT_FAILED]: ${n}`))}}),a=!1;return{merge(e){return c(e,n.getSnapshot(),t)},dispose(){a||(a=!0,n.dispose(),t.splice(0))}}}export{l as createActiveHelpSkillView};
2
+ //# sourceMappingURL=helpSkills.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpSkills.mjs","names":[],"sources":["../../src/adapters/helpSkills.ts"],"sourcesContent":["import type { DoomExtensionHost } from '@agimon-ai/doompi-extension-contracts/config';\nimport {\n createDoomHelpSnapshotClient,\n DOOM_HELP_MAX_DIAGNOSTIC_LENGTH,\n DOOM_HELP_MAX_DIAGNOSTICS,\n type DoomHelpSkill,\n type DoomHelpSnapshot,\n type DoomHelpSnapshotClient,\n} from '@agimon-ai/doompi-extension-contracts/help';\nimport { createSyntheticSourceInfo, type ExtensionAPI, type Skill } from '@earendil-works/pi-coding-agent';\n\nconst HELP_CLIENT_SOURCE = '@agimon-ai/doompi';\n\nexport interface SkillInventoryInput {\n normalSkills: readonly Skill[];\n deferredSkills: readonly Skill[];\n /** Names from Pi's command catalog when full normal Skill records are unavailable. */\n normalSkillNames?: readonly string[];\n}\n\nexport interface MergedSkillInventory {\n /** Static, deferred, then accepted Help skills in invocation-precedence order. */\n skills: readonly Skill[];\n /** Deferred and Help skills that Doom Pi must append to Pi's existing prompt inventory. */\n additionalSkills: readonly Skill[];\n /** Accepted Help skills, retained separately for the Help catalog group. */\n helpSkills: readonly Skill[];\n diagnostics: readonly string[];\n diagnosticKey: string;\n}\n\nexport interface ActiveHelpSkillView {\n merge(input: SkillInventoryInput): MergedSkillInventory;\n dispose(): void;\n}\n\nfunction boundedDiagnostic(message: string): string {\n return message.slice(0, DOOM_HELP_MAX_DIAGNOSTIC_LENGTH);\n}\n\nfunction toSkill(skill: DoomHelpSkill): Skill {\n return {\n name: skill.name,\n description: skill.description,\n filePath: skill.filePath,\n baseDir: skill.baseDir,\n sourceInfo: createSyntheticSourceInfo(skill.filePath, {\n source: skill.source,\n scope: 'temporary',\n origin: 'package',\n baseDir: skill.baseDir,\n }),\n disableModelInvocation: false,\n };\n}\n\nfunction activeHelpSkills(snapshot: DoomHelpSnapshot | undefined): DoomHelpSkill[] {\n if (!snapshot || snapshot.activation === 'inactive') return [];\n return [...snapshot.skills].sort(\n (left, right) =>\n left.source.localeCompare(right.source) ||\n left.name.localeCompare(right.name) ||\n left.filePath.localeCompare(right.filePath),\n );\n}\n\nfunction snapshotDiagnostics(snapshot: DoomHelpSnapshot | undefined): string[] {\n if (!snapshot) return [];\n return snapshot.diagnostics.map((entry) =>\n boundedDiagnostic(`Help ${entry.source ?? 'host'} [${entry.code}]: ${entry.message}`),\n );\n}\n\nexport function mergeActiveHelpSkills(\n input: SkillInventoryInput,\n snapshot: DoomHelpSnapshot | undefined,\n clientDiagnostics: readonly string[] = [],\n): MergedSkillInventory {\n const occupiedNames = new Set([\n ...input.normalSkills.map((skill) => skill.name),\n ...input.deferredSkills.map((skill) => skill.name),\n ...(input.normalSkillNames ?? []),\n ]);\n const helpSkills: Skill[] = [];\n const diagnostics = [...snapshotDiagnostics(snapshot), ...clientDiagnostics.map(boundedDiagnostic)];\n\n for (const candidate of activeHelpSkills(snapshot)) {\n if (occupiedNames.has(candidate.name)) {\n diagnostics.push(\n boundedDiagnostic(\n `Help ${candidate.source} [HELP_SKILL_COLLISION]: '${candidate.name}' was ignored because a normal skill wins.`,\n ),\n );\n continue;\n }\n occupiedNames.add(candidate.name);\n helpSkills.push(toSkill(candidate));\n }\n\n const boundedDiagnostics = diagnostics.slice(0, DOOM_HELP_MAX_DIAGNOSTICS);\n const additionalSkills = [...input.deferredSkills, ...helpSkills];\n return {\n skills: [...input.normalSkills, ...additionalSkills],\n additionalSkills,\n helpSkills,\n diagnostics: boundedDiagnostics,\n diagnosticKey: `${snapshot?.hostGeneration ?? 'absent'}:${snapshot?.revision ?? 0}:${boundedDiagnostics.join('\\u0001')}`,\n };\n}\n\nexport function createActiveHelpSkillView(pi: Pick<ExtensionAPI, 'events' | 'on'>): ActiveHelpSkillView {\n const clientDiagnostics: string[] = [];\n const client: DoomHelpSnapshotClient = createDoomHelpSnapshotClient(pi as unknown as DoomExtensionHost, {\n source: HELP_CLIENT_SOURCE,\n onError(error) {\n const message = error instanceof Error ? error.message : String(error);\n clientDiagnostics.splice(\n 0,\n clientDiagnostics.length,\n boundedDiagnostic(`Help client [HELP_SNAPSHOT_FAILED]: ${message}`),\n );\n },\n });\n let disposed = false;\n return {\n merge(input) {\n return mergeActiveHelpSkills(input, client.getSnapshot(), clientDiagnostics);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n client.dispose();\n clientDiagnostics.splice(0);\n },\n };\n}\n"],"mappings":"0OAoCA,SAAS,EAAkB,EAAyB,CAClD,OAAO,EAAQ,MAAM,EAAG,EAAgC,CAG1D,SAAS,EAAQ,EAA6B,CAC5C,MAAO,CACL,KAAM,EAAM,KACZ,YAAa,EAAM,YACnB,SAAU,EAAM,SAChB,QAAS,EAAM,QACf,WAAY,EAA0B,EAAM,SAAU,CACpD,OAAQ,EAAM,OACd,MAAO,YACP,OAAQ,UACR,QAAS,EAAM,QAChB,CAAC,CACF,uBAAwB,GACzB,CAGH,SAAS,EAAiB,EAAyD,CAEjF,MADI,CAAC,GAAY,EAAS,aAAe,WAAmB,EAAE,CACvD,CAAC,GAAG,EAAS,OAAO,CAAC,MACzB,EAAM,IACL,EAAK,OAAO,cAAc,EAAM,OAAO,EACvC,EAAK,KAAK,cAAc,EAAM,KAAK,EACnC,EAAK,SAAS,cAAc,EAAM,SAAS,CAC9C,CAGH,SAAS,EAAoB,EAAkD,CAE7E,OADK,EACE,EAAS,YAAY,IAAK,GAC/B,EAAkB,QAAQ,EAAM,QAAU,OAAO,IAAI,EAAM,KAAK,KAAK,EAAM,UAAU,CACtF,CAHqB,EAAE,CAM1B,SAAgB,EACd,EACA,EACA,EAAuC,EAAE,CACnB,CACtB,IAAM,EAAgB,IAAI,IAAI,CAC5B,GAAG,EAAM,aAAa,IAAK,GAAU,EAAM,KAAK,CAChD,GAAG,EAAM,eAAe,IAAK,GAAU,EAAM,KAAK,CAClD,GAAI,EAAM,kBAAoB,EAAE,CACjC,CAAC,CACI,EAAsB,EAAE,CACxB,EAAc,CAAC,GAAG,EAAoB,EAAS,CAAE,GAAG,EAAkB,IAAI,EAAkB,CAAC,CAEnG,IAAK,IAAM,KAAa,EAAiB,EAAS,CAAE,CAClD,GAAI,EAAc,IAAI,EAAU,KAAK,CAAE,CACrC,EAAY,KACV,EACE,QAAQ,EAAU,OAAO,4BAA4B,EAAU,KAAK,4CACrE,CACF,CACD,SAEF,EAAc,IAAI,EAAU,KAAK,CACjC,EAAW,KAAK,EAAQ,EAAU,CAAC,CAGrC,IAAM,EAAqB,EAAY,MAAM,EAAG,EAA0B,CACpE,EAAmB,CAAC,GAAG,EAAM,eAAgB,GAAG,EAAW,CACjE,MAAO,CACL,OAAQ,CAAC,GAAG,EAAM,aAAc,GAAG,EAAiB,CACpD,mBACA,aACA,YAAa,EACb,cAAe,GAAG,GAAU,gBAAkB,SAAS,GAAG,GAAU,UAAY,EAAE,GAAG,EAAmB,KAAK,IAAS,GACvH,CAGH,SAAgB,EAA0B,EAA8D,CACtG,IAAM,EAA8B,EAAE,CAChC,EAAiC,EAA6B,EAAoC,CACtG,OAAQ,oBACR,QAAQ,EAAO,CACb,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CACtE,EAAkB,OAChB,EACA,EAAkB,OAClB,EAAkB,uCAAuC,IAAU,CACpE,EAEJ,CAAC,CACE,EAAW,GACf,MAAO,CACL,MAAM,EAAO,CACX,OAAO,EAAsB,EAAO,EAAO,aAAa,CAAE,EAAkB,EAE9E,SAAU,CACJ,IACJ,EAAW,GACX,EAAO,SAAS,CAChB,EAAkB,OAAO,EAAE,GAE9B"}
@@ -0,0 +1,2 @@
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./modules/moduleResolution.cjs`),t=require(`../services/extensionAssembler.cjs`),n=require(`./piSettings.cjs`);let r=require(`@agimon-ai/doompi-config/majorModes`),i=require(`@earendil-works/pi-coding-agent`);function a(e,t){let n=e.optionalPackageEntries?.(t);if(n!==void 0)return n;let r=e.optionalPackageEntry(t);return r?[r]:void 0}function o(e,t,n){let i=new Set;for(let o of t){let t=e.layers[o];if(!t)throw Error(`Unknown layer: ${o}`);for(let e of t.packages??[]){let t=typeof e==`string`?e:e.name;typeof e!=`string`&&e.optional===!0||(0,r.isLocalPackageSpecifier)(t)||a(n,t)===void 0&&i.add(t)}}return[...i]}function s(t){return[...new Set(t.map(t=>`npm:${e.splitPackageSpecifier(t).name}`))]}function c(e,t){let r=n.piAgentDirectory(t);return new i.DefaultPackageManager({cwd:e,agentDir:r,settingsManager:i.SettingsManager.create(e,r,{projectTrusted:!0})})}async function l(e,n={}){let r=e.environment??process.env,i=n.resolvers??t.createLayerResolvers(e.repoRoot),l=o(e.config,e.layers,i);if(l.length===0)return[];let u=s(l),d=n.packageManager??c(e.repoRoot,r);try{await d.resolveExtensionSources(u,{local:!0})}catch(e){throw Error(`Failed to install missing DoomPi layer package(s): ${u.join(`, `)}`,{cause:e})}let f=l.filter(e=>!a(i,e)?.length);if(f.length>0)throw Error(`Installed DoomPi layer package(s) did not expose the configured Pi extension: ${f.join(`, `)}`);return u}exports.ensureLayerPackages=l;
2
+ //# sourceMappingURL=layerPackageInstaller.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layerPackageInstaller.cjs","names":["splitPackageSpecifier","piAgentDirectory","DefaultPackageManager","SettingsManager","createLayerResolvers"],"sources":["../../src/adapters/layerPackageInstaller.ts"],"sourcesContent":["import { isLocalPackageSpecifier, type MajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\nimport { DefaultPackageManager, type PackageManager, SettingsManager } from '@earendil-works/pi-coding-agent';\nimport { createLayerResolvers, type ExtensionLayerResolvers } from '../services/extensionAssembler.ts';\nimport { splitPackageSpecifier } from './modules/moduleResolution.ts';\nimport { piAgentDirectory } from './piSettings.ts';\n\nconst NPM_SOURCE_PREFIX = 'npm:';\n\ntype LayerPackageManager = Pick<PackageManager, 'resolveExtensionSources'>;\n\nexport interface EnsureLayerPackagesOptions {\n repoRoot: string;\n config: MajorModesConfig;\n layers: readonly string[];\n environment?: NodeJS.ProcessEnv;\n}\n\nexport interface LayerPackageInstallerDependencies {\n packageManager?: LayerPackageManager;\n resolvers?: ExtensionLayerResolvers;\n}\n\nfunction resolvePackageEntries(resolvers: ExtensionLayerResolvers, specifier: string): string[] | undefined {\n const entries = resolvers.optionalPackageEntries?.(specifier);\n if (entries !== undefined) return entries;\n const entry = resolvers.optionalPackageEntry(specifier);\n return entry ? [entry] : undefined;\n}\n\n/** Finds required npm packages selected by the active layers that are not installed anywhere DoomPi resolves. */\nexport function missingLayerPackageSpecifiers(\n config: MajorModesConfig,\n layers: readonly string[],\n resolvers: ExtensionLayerResolvers,\n): string[] {\n const missing = new Set<string>();\n for (const layerName of layers) {\n const layer = config.layers[layerName];\n if (!layer) throw new Error(`Unknown layer: ${layerName}`);\n for (const configured of layer.packages ?? []) {\n const specifier = typeof configured === 'string' ? configured : configured.name;\n const optional = typeof configured !== 'string' && configured.optional === true;\n if (optional || isLocalPackageSpecifier(specifier)) continue;\n // An empty entry list means the package exists but declares no usable Pi\n // extension. Leave that validation to the assembler rather than masking a\n // broken install with another copy from the registry.\n if (resolvePackageEntries(resolvers, specifier) === undefined) missing.add(specifier);\n }\n }\n return [...missing];\n}\n\nfunction npmSources(specifiers: readonly string[]): string[] {\n return [...new Set(specifiers.map((specifier) => `${NPM_SOURCE_PREFIX}${splitPackageSpecifier(specifier).name}`))];\n}\n\nfunction createPackageManager(repoRoot: string, environment: NodeJS.ProcessEnv): LayerPackageManager {\n const agentDirectory = piAgentDirectory(environment);\n const settingsManager = SettingsManager.create(repoRoot, agentDirectory, { projectTrusted: true });\n return new DefaultPackageManager({ cwd: repoRoot, agentDir: agentDirectory, settingsManager });\n}\n\n/** Installs missing selected layer packages into Pi's project-local `.pi/npm` store and verifies the retry. */\nexport async function ensureLayerPackages(\n options: EnsureLayerPackagesOptions,\n dependencies: LayerPackageInstallerDependencies = {},\n): Promise<string[]> {\n const environment = options.environment ?? process.env;\n const resolvers = dependencies.resolvers ?? createLayerResolvers(options.repoRoot);\n const missing = missingLayerPackageSpecifiers(options.config, options.layers, resolvers);\n if (missing.length === 0) return [];\n\n const sources = npmSources(missing);\n const packageManager = dependencies.packageManager ?? createPackageManager(options.repoRoot, environment);\n try {\n await packageManager.resolveExtensionSources(sources, { local: true });\n } catch (error) {\n throw new Error(`Failed to install missing DoomPi layer package(s): ${sources.join(', ')}`, { cause: error });\n }\n\n const unresolved = missing.filter((specifier) => !resolvePackageEntries(resolvers, specifier)?.length);\n if (unresolved.length > 0) {\n throw new Error(\n `Installed DoomPi layer package(s) did not expose the configured Pi extension: ${unresolved.join(', ')}`,\n );\n }\n return sources;\n}\n"],"mappings":"+QAsBA,SAAS,EAAsB,EAAoC,EAAyC,CAC1G,IAAM,EAAU,EAAU,yBAAyB,EAAU,CAC7D,GAAI,IAAY,IAAA,GAAW,OAAO,EAClC,IAAM,EAAQ,EAAU,qBAAqB,EAAU,CACvD,OAAO,EAAQ,CAAC,EAAM,CAAG,IAAA,GAI3B,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAM,EAAU,IAAI,IACpB,IAAK,IAAM,KAAa,EAAQ,CAC9B,IAAM,EAAQ,EAAO,OAAO,GAC5B,GAAI,CAAC,EAAO,MAAU,MAAM,kBAAkB,IAAY,CAC1D,IAAK,IAAM,KAAc,EAAM,UAAY,EAAE,CAAE,CAC7C,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,EAAW,KAC1D,OAAO,GAAe,UAAY,EAAW,WAAa,KAAA,EAAA,EAAA,yBACnC,EAAU,EAI9C,EAAsB,EAAW,EAAU,GAAK,IAAA,IAAW,EAAQ,IAAI,EAAU,EAGzF,MAAO,CAAC,GAAG,EAAQ,CAGrB,SAAS,EAAW,EAAyC,CAC3D,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,IAAK,GAAc,OAAuBA,EAAAA,sBAAsB,EAAU,CAAC,OAAO,CAAC,CAAC,CAGpH,SAAS,EAAqB,EAAkB,EAAqD,CACnG,IAAM,EAAiBC,EAAAA,iBAAiB,EAAY,CAEpD,OAAO,IAAIC,EAAAA,sBAAsB,CAAE,IAAK,EAAU,SAAU,EAAgB,gBADpDC,EAAAA,gBAAgB,OAAO,EAAU,EAAgB,CAAE,eAAgB,GAAM,CACN,CAAE,CAAC,CAIhG,eAAsB,EACpB,EACA,EAAkD,EAAE,CACjC,CACnB,IAAM,EAAc,EAAQ,aAAe,QAAQ,IAC7C,EAAY,EAAa,WAAaC,EAAAA,qBAAqB,EAAQ,SAAS,CAC5E,EAAU,EAA8B,EAAQ,OAAQ,EAAQ,OAAQ,EAAU,CACxF,GAAI,EAAQ,SAAW,EAAG,MAAO,EAAE,CAEnC,IAAM,EAAU,EAAW,EAAQ,CAC7B,EAAiB,EAAa,gBAAkB,EAAqB,EAAQ,SAAU,EAAY,CACzG,GAAI,CACF,MAAM,EAAe,wBAAwB,EAAS,CAAE,MAAO,GAAM,CAAC,OAC/D,EAAO,CACd,MAAU,MAAM,sDAAsD,EAAQ,KAAK,KAAK,GAAI,CAAE,MAAO,EAAO,CAAC,CAG/G,IAAM,EAAa,EAAQ,OAAQ,GAAc,CAAC,EAAsB,EAAW,EAAU,EAAE,OAAO,CACtG,GAAI,EAAW,OAAS,EACtB,MAAU,MACR,iFAAiF,EAAW,KAAK,KAAK,GACvG,CAEH,OAAO"}
@@ -0,0 +1,2 @@
1
+ import{splitPackageSpecifier as e}from"./modules/moduleResolution.mjs";import{createLayerResolvers as t}from"../services/extensionAssembler.mjs";import{piAgentDirectory as n}from"./piSettings.mjs";import{isLocalPackageSpecifier as r}from"@agimon-ai/doompi-config/majorModes";import{DefaultPackageManager as i,SettingsManager as a}from"@earendil-works/pi-coding-agent";function o(e,t){let n=e.optionalPackageEntries?.(t);if(n!==void 0)return n;let r=e.optionalPackageEntry(t);return r?[r]:void 0}function s(e,t,n){let i=new Set;for(let a of t){let t=e.layers[a];if(!t)throw Error(`Unknown layer: ${a}`);for(let e of t.packages??[]){let t=typeof e==`string`?e:e.name;typeof e!=`string`&&e.optional===!0||r(t)||o(n,t)===void 0&&i.add(t)}}return[...i]}function c(t){return[...new Set(t.map(t=>`npm:${e(t).name}`))]}function l(e,t){let r=n(t);return new i({cwd:e,agentDir:r,settingsManager:a.create(e,r,{projectTrusted:!0})})}async function u(e,n={}){let r=e.environment??process.env,i=n.resolvers??t(e.repoRoot),a=s(e.config,e.layers,i);if(a.length===0)return[];let u=c(a),d=n.packageManager??l(e.repoRoot,r);try{await d.resolveExtensionSources(u,{local:!0})}catch(e){throw Error(`Failed to install missing DoomPi layer package(s): ${u.join(`, `)}`,{cause:e})}let f=a.filter(e=>!o(i,e)?.length);if(f.length>0)throw Error(`Installed DoomPi layer package(s) did not expose the configured Pi extension: ${f.join(`, `)}`);return u}export{u as ensureLayerPackages};
2
+ //# sourceMappingURL=layerPackageInstaller.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layerPackageInstaller.mjs","names":[],"sources":["../../src/adapters/layerPackageInstaller.ts"],"sourcesContent":["import { isLocalPackageSpecifier, type MajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\nimport { DefaultPackageManager, type PackageManager, SettingsManager } from '@earendil-works/pi-coding-agent';\nimport { createLayerResolvers, type ExtensionLayerResolvers } from '../services/extensionAssembler.ts';\nimport { splitPackageSpecifier } from './modules/moduleResolution.ts';\nimport { piAgentDirectory } from './piSettings.ts';\n\nconst NPM_SOURCE_PREFIX = 'npm:';\n\ntype LayerPackageManager = Pick<PackageManager, 'resolveExtensionSources'>;\n\nexport interface EnsureLayerPackagesOptions {\n repoRoot: string;\n config: MajorModesConfig;\n layers: readonly string[];\n environment?: NodeJS.ProcessEnv;\n}\n\nexport interface LayerPackageInstallerDependencies {\n packageManager?: LayerPackageManager;\n resolvers?: ExtensionLayerResolvers;\n}\n\nfunction resolvePackageEntries(resolvers: ExtensionLayerResolvers, specifier: string): string[] | undefined {\n const entries = resolvers.optionalPackageEntries?.(specifier);\n if (entries !== undefined) return entries;\n const entry = resolvers.optionalPackageEntry(specifier);\n return entry ? [entry] : undefined;\n}\n\n/** Finds required npm packages selected by the active layers that are not installed anywhere DoomPi resolves. */\nexport function missingLayerPackageSpecifiers(\n config: MajorModesConfig,\n layers: readonly string[],\n resolvers: ExtensionLayerResolvers,\n): string[] {\n const missing = new Set<string>();\n for (const layerName of layers) {\n const layer = config.layers[layerName];\n if (!layer) throw new Error(`Unknown layer: ${layerName}`);\n for (const configured of layer.packages ?? []) {\n const specifier = typeof configured === 'string' ? configured : configured.name;\n const optional = typeof configured !== 'string' && configured.optional === true;\n if (optional || isLocalPackageSpecifier(specifier)) continue;\n // An empty entry list means the package exists but declares no usable Pi\n // extension. Leave that validation to the assembler rather than masking a\n // broken install with another copy from the registry.\n if (resolvePackageEntries(resolvers, specifier) === undefined) missing.add(specifier);\n }\n }\n return [...missing];\n}\n\nfunction npmSources(specifiers: readonly string[]): string[] {\n return [...new Set(specifiers.map((specifier) => `${NPM_SOURCE_PREFIX}${splitPackageSpecifier(specifier).name}`))];\n}\n\nfunction createPackageManager(repoRoot: string, environment: NodeJS.ProcessEnv): LayerPackageManager {\n const agentDirectory = piAgentDirectory(environment);\n const settingsManager = SettingsManager.create(repoRoot, agentDirectory, { projectTrusted: true });\n return new DefaultPackageManager({ cwd: repoRoot, agentDir: agentDirectory, settingsManager });\n}\n\n/** Installs missing selected layer packages into Pi's project-local `.pi/npm` store and verifies the retry. */\nexport async function ensureLayerPackages(\n options: EnsureLayerPackagesOptions,\n dependencies: LayerPackageInstallerDependencies = {},\n): Promise<string[]> {\n const environment = options.environment ?? process.env;\n const resolvers = dependencies.resolvers ?? createLayerResolvers(options.repoRoot);\n const missing = missingLayerPackageSpecifiers(options.config, options.layers, resolvers);\n if (missing.length === 0) return [];\n\n const sources = npmSources(missing);\n const packageManager = dependencies.packageManager ?? createPackageManager(options.repoRoot, environment);\n try {\n await packageManager.resolveExtensionSources(sources, { local: true });\n } catch (error) {\n throw new Error(`Failed to install missing DoomPi layer package(s): ${sources.join(', ')}`, { cause: error });\n }\n\n const unresolved = missing.filter((specifier) => !resolvePackageEntries(resolvers, specifier)?.length);\n if (unresolved.length > 0) {\n throw new Error(\n `Installed DoomPi layer package(s) did not expose the configured Pi extension: ${unresolved.join(', ')}`,\n );\n }\n return sources;\n}\n"],"mappings":"gXAsBA,SAAS,EAAsB,EAAoC,EAAyC,CAC1G,IAAM,EAAU,EAAU,yBAAyB,EAAU,CAC7D,GAAI,IAAY,IAAA,GAAW,OAAO,EAClC,IAAM,EAAQ,EAAU,qBAAqB,EAAU,CACvD,OAAO,EAAQ,CAAC,EAAM,CAAG,IAAA,GAI3B,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAM,EAAU,IAAI,IACpB,IAAK,IAAM,KAAa,EAAQ,CAC9B,IAAM,EAAQ,EAAO,OAAO,GAC5B,GAAI,CAAC,EAAO,MAAU,MAAM,kBAAkB,IAAY,CAC1D,IAAK,IAAM,KAAc,EAAM,UAAY,EAAE,CAAE,CAC7C,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,EAAW,KAC1D,OAAO,GAAe,UAAY,EAAW,WAAa,IAC3D,EAAwB,EAAU,EAI9C,EAAsB,EAAW,EAAU,GAAK,IAAA,IAAW,EAAQ,IAAI,EAAU,EAGzF,MAAO,CAAC,GAAG,EAAQ,CAGrB,SAAS,EAAW,EAAyC,CAC3D,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,IAAK,GAAc,OAAuB,EAAsB,EAAU,CAAC,OAAO,CAAC,CAAC,CAGpH,SAAS,EAAqB,EAAkB,EAAqD,CACnG,IAAM,EAAiB,EAAiB,EAAY,CAEpD,OAAO,IAAI,EAAsB,CAAE,IAAK,EAAU,SAAU,EAAgB,gBADpD,EAAgB,OAAO,EAAU,EAAgB,CAAE,eAAgB,GAAM,CACN,CAAE,CAAC,CAIhG,eAAsB,EACpB,EACA,EAAkD,EAAE,CACjC,CACnB,IAAM,EAAc,EAAQ,aAAe,QAAQ,IAC7C,EAAY,EAAa,WAAa,EAAqB,EAAQ,SAAS,CAC5E,EAAU,EAA8B,EAAQ,OAAQ,EAAQ,OAAQ,EAAU,CACxF,GAAI,EAAQ,SAAW,EAAG,MAAO,EAAE,CAEnC,IAAM,EAAU,EAAW,EAAQ,CAC7B,EAAiB,EAAa,gBAAkB,EAAqB,EAAQ,SAAU,EAAY,CACzG,GAAI,CACF,MAAM,EAAe,wBAAwB,EAAS,CAAE,MAAO,GAAM,CAAC,OAC/D,EAAO,CACd,MAAU,MAAM,sDAAsD,EAAQ,KAAK,KAAK,GAAI,CAAE,MAAO,EAAO,CAAC,CAG/G,IAAM,EAAa,EAAQ,OAAQ,GAAc,CAAC,EAAsB,EAAW,EAAU,EAAE,OAAO,CACtG,GAAI,EAAW,OAAS,EACtB,MAAU,MACR,iFAAiF,EAAW,KAAK,KAAK,GACvG,CAEH,OAAO"}
@@ -1,2 +1,2 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.cjs`);let t=require(`node:url`),n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`minimatch`);const a=`package.json`,o=[`!`,`+`,`-`],s=/[*?[\]{}()]/,c=new Set([`.ts`,`.js`,`.mts`,`.mjs`,`.cts`,`.cjs`]),l=[`import`,`module`,`node`,`default`];function u(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function d(e){try{let t=JSON.parse(r.default.readFileSync(n.default.join(e,a),`utf8`));return u(t)?t:void 0}catch{return}}function f(e){return o.some(t=>e.startsWith(t))}function p(e,t){return n.default.relative(e,t).split(n.default.sep).join(`/`)}function m(e,t,r){let a=t.replaceAll(`\\`,`/`).replace(/^\.\//,``);return(0,i.minimatch)(p(r,e),a)||(0,i.minimatch)(n.default.basename(e),a)||(0,i.minimatch)(e.split(n.default.sep).join(`/`),a)}function h(e,t,r){let i=t.replaceAll(`\\`,`/`).replace(/^\.\//,``);return p(r,e)===i||e.split(n.default.sep).join(`/`)===i}function g(e){let t;try{t=r.default.statSync(e)}catch{return[]}if(t.isFile())return[e];if(!t.isDirectory())return[];let i=[];for(let t of r.default.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))){let a=n.default.join(e,t.name);if((t.isFile()||t.isSymbolicLink())&&c.has(n.default.extname(t.name))){i.push(a);continue}if(!(!t.isDirectory()&&!t.isSymbolicLink()))for(let e of[`index.ts`,`index.js`,`index.mts`,`index.mjs`,`index.cts`,`index.cjs`]){let t=n.default.join(a,e);if(r.default.existsSync(t)){i.push(t);break}}}return i}function _(e,t,i){if(!t||!u(t.pi)||!Object.hasOwn(t.pi,`extensions`))return;let a=t.pi.extensions;if(!Array.isArray(a)||!a.every(e=>typeof e==`string`))throw Error(`${i} package.json pi.extensions must be an array of strings.`);let o=[];for(let t of a.filter(e=>!f(e))){let i=s.test(t)?r.default.globSync(t,{cwd:e}).sort():[t];for(let t of i)for(let r of g(n.default.resolve(e,t)))o.includes(r)||o.push(r)}let c=a.filter(e=>e.startsWith(`!`)).map(e=>e.slice(1)),l=a.filter(e=>e.startsWith(`+`)).map(e=>e.slice(1)),d=a.filter(e=>e.startsWith(`-`)).map(e=>e.slice(1)),p=o.filter(t=>!c.some(n=>m(t,n,e)));for(let t of o)!p.includes(t)&&l.some(n=>h(t,n,e))&&p.push(t);return p.filter(t=>!d.some(n=>h(t,n,e)))}function v(e){return(0,t.fileURLToPath)({}.resolve(e))}function y(e){try{return v(e)}catch{return}}function b(e){let t=e.split(`/`),n=e.startsWith(`@`)?2:1,r=t.slice(0,n).join(`/`),i=t.slice(n).join(`/`);return{name:r,subpath:i?`./${i}`:`.`}}function x(e){if(typeof e==`string`)return e;if(Array.isArray(e)){for(let t of e){let e=x(t);if(e)return e}return}if(typeof e!=`object`||!e)return;let t=e;for(let e of l)if(e in t){let n=x(t[e]);if(n)return n}}function S(e,t){let i=n.default.resolve(t);for(;;){let t=n.default.join(i,`node_modules`,e);if(r.default.existsSync(n.default.join(t,a)))return t;let o=n.default.dirname(i);if(o===i)return;i=o}}function C(e){let{name:r,subpath:i}=b(e);if(i!==`.`)return[v(e)];let a=S(r,n.default.dirname((0,t.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)));return(a?_(a,d(a),r):void 0)??[v(e)]}function w(e){try{return C(e)}catch{return}}function T(e,t){let{name:n,subpath:r}=b(e),i=S(n,t);if(!i)return;if(r===`.`){let e=_(i,d(i),n);if(e!==void 0)return e}let a=E(e,t);return a?[a]:[]}function E(e,t){let{name:i,subpath:o}=b(e),s=S(i,t);if(!s)return;let c=n.default.join(s,a),l=n.default.join(s,o),u;try{u=JSON.parse(r.default.readFileSync(c,`utf8`))}catch{return r.default.existsSync(l)?l:void 0}let d=u.exports;if(d!=null){let e=x(typeof d==`object`&&!Array.isArray(d)?d[o]:o===`.`?d:void 0);if(e){let t=n.default.join(s,e);if(r.default.existsSync(t))return t}}return o===`.`?void 0:r.default.existsSync(l)?l:void 0}const D=[`module`,`main`];function O(e,t){let i=n.default.resolve(t,e);try{if(!r.default.statSync(i).isDirectory())return;let e=JSON.parse(r.default.readFileSync(n.default.join(i,a),`utf8`));return typeof e.name==`string`&&e.name.trim()?e.name.trim():void 0}catch{return}}function k(e,t){let i=n.default.resolve(t,e),a;try{a=r.default.statSync(i)}catch{return}if(a.isFile())return[i];if(!a.isDirectory())return;let o=_(i,d(i),O(e,t)??i);if(o!==void 0)return o;let s=A(e,t);return s?[s]:[]}function A(e,t){let i=n.default.resolve(t,e),o;try{let e=r.default.statSync(i);if(e.isFile())return i;o=e.isDirectory()}catch{return}if(!o)return;let s;try{s=JSON.parse(r.default.readFileSync(n.default.join(i,a),`utf8`))}catch{return}let c=s.exports,l=[x(typeof c==`object`&&c&&!Array.isArray(c)?c[`.`]:c)];for(let e of D)typeof s[e]==`string`&&l.push(s[e]);for(let e of l){if(!e)continue;let t=n.default.join(i,e);if(r.default.existsSync(t))return t}}function j(e){let r=require(`url`).pathToFileURL(__filename).href.endsWith(`.ts`)?`ts`:`mjs`,i=n.default.dirname(n.default.dirname(n.default.dirname((0,t.fileURLToPath)(require(`url`).pathToFileURL(__filename).href))));return n.default.join(i,`extensions`,`entries`,`${e}.${r}`)}function M(){return n.default.join(n.default.dirname(v(`@earendil-works/pi-coding-agent`)),`cli.js`)}exports.consumerPackageEntries=T,exports.consumerPackageEntry=E,exports.localEntries=k,exports.localEntry=A,exports.localPackageName=O,exports.optionalPackageEntries=w,exports.optionalPackageEntry=y,exports.ownEntry=j,exports.packageEntries=C,exports.packageEntry=v,exports.piCliPath=M,exports.splitPackageSpecifier=b;
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`);let t=require(`node:url`),n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`minimatch`);const a=`package.json`,o=`node_modules`,s=n.default.join(`.pi`,`npm`,o),c=[`!`,`+`,`-`],l=/[*?[\]{}()]/,u=[`index.ts`,`index.js`,`index.mts`,`index.mjs`,`index.cts`,`index.cjs`],d=new Set([`.ts`,`.js`,`.mts`,`.mjs`,`.cts`,`.cjs`]),f=[`import`,`module`,`node`,`default`];function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e){try{let t=JSON.parse(r.default.readFileSync(n.default.join(e,a),`utf8`));return p(t)?t:void 0}catch{return}}function h(e){return!!(e&&p(e.pi)&&Object.hasOwn(e.pi,`extensions`))}function g(e){return c.some(t=>e.startsWith(t))}function _(e,t){return n.default.relative(e,t).split(n.default.sep).join(`/`)}function v(e,t,r){let a=t.replaceAll(`\\`,`/`).replace(/^\.\//,``);return(0,i.minimatch)(_(r,e),a)||(0,i.minimatch)(n.default.basename(e),a)||(0,i.minimatch)(e.split(n.default.sep).join(`/`),a)}function y(e,t,r){let i=t.replaceAll(`\\`,`/`).replace(/^\.\//,``);return _(r,e)===i||e.split(n.default.sep).join(`/`)===i}function b(e){for(let t of u){let i=n.default.join(e,t);if(r.default.existsSync(i))return i}}function x(e){let t;try{t=r.default.statSync(e)}catch{return[]}if(t.isFile())return[e];if(!t.isDirectory())return[];let i=[];for(let t of r.default.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))){let r=n.default.join(e,t.name);if((t.isFile()||t.isSymbolicLink())&&d.has(n.default.extname(t.name))){i.push(r);continue}if(!t.isDirectory()&&!t.isSymbolicLink())continue;let a=b(r);a&&i.push(a)}return i}function S(e,t,i){if(!h(t)||!p(t?.pi))return;let a=t.pi.extensions;if(!Array.isArray(a)||!a.every(e=>typeof e==`string`))throw Error(`${i} package.json pi.extensions must be an array of strings.`);let o=[];for(let t of a.filter(e=>!g(e))){let i=l.test(t)?r.default.globSync(t,{cwd:e}).sort():[t];for(let t of i)for(let r of x(n.default.resolve(e,t)))o.includes(r)||o.push(r)}let s=a.filter(e=>e.startsWith(`!`)).map(e=>e.slice(1)),c=a.filter(e=>e.startsWith(`+`)).map(e=>e.slice(1)),u=a.filter(e=>e.startsWith(`-`)).map(e=>e.slice(1)),d=o.filter(t=>!s.some(n=>v(t,n,e)));for(let t of o)!d.includes(t)&&c.some(n=>y(t,n,e))&&d.push(t);let f=d.filter(t=>!u.some(n=>y(t,n,e)));return f.length>0?f:void 0}function C(e){return(0,t.fileURLToPath)({}.resolve(e))}function w(e){try{return C(e)}catch{return}}function T(e){let t=e.split(`/`),n=e.startsWith(`@`)?2:1,r=t.slice(0,n).join(`/`),i=t.slice(n).join(`/`);return{name:r,subpath:i?`./${i}`:`.`}}function E(e){if(typeof e==`string`)return e;if(Array.isArray(e)){for(let t of e){let e=E(t);if(e)return e}return}if(typeof e!=`object`||!e)return;let t=e;for(let e of f)if(e in t){let n=E(t[e]);if(n)return n}}function D(e,t){let i=n.default.resolve(t);for(;;){let t=n.default.join(i,o,e);if(r.default.existsSync(n.default.join(t,a)))return t;let s=n.default.dirname(i);if(s===i)return;i=s}}function O(e,t){let i=n.default.join(n.default.resolve(t),s,e);return r.default.existsSync(n.default.join(i,a))?i:void 0}function k(e,t){return D(e,t)??O(e,t)}function A(e){let{name:r,subpath:i}=T(e);if(i!==`.`)return[C(e)];let a=D(r,n.default.dirname((0,t.fileURLToPath)(require(`url`).pathToFileURL(__filename).href))),o=a?m(a):void 0;return(a?S(a,o,r):void 0)||[(a&&h(o)?b(a):void 0)??C(e)]}function j(e){try{return A(e)}catch{return}}function M(e,t){let{name:n,subpath:r}=T(e),i=k(n,t);if(!i)return;if(r===`.`){let e=S(i,m(i),n);if(e!==void 0)return e}let a=N(e,t);return a?[a]:[]}function N(e,t){let{name:i,subpath:o}=T(e),s=k(i,t);if(!s)return;let c=n.default.join(s,a),l=n.default.join(s,o),u;try{u=JSON.parse(r.default.readFileSync(c,`utf8`))}catch{return o===`.`?b(s):r.default.existsSync(l)?l:void 0}let d=u.exports;if(d!=null){let e=E(typeof d==`object`&&!Array.isArray(d)?d[o]:o===`.`?d:void 0);if(e){let t=n.default.join(s,e);if(r.default.existsSync(t))return t}}return o===`.`?b(s):r.default.existsSync(l)?l:void 0}const P=[`module`,`main`];function F(e,t){let i=n.default.resolve(t,e);try{if(!r.default.statSync(i).isDirectory())return;let e=JSON.parse(r.default.readFileSync(n.default.join(i,a),`utf8`));return typeof e.name==`string`&&e.name.trim()?e.name.trim():void 0}catch{return}}function I(e,t){let i=n.default.resolve(t,e),a;try{a=r.default.statSync(i)}catch{return}if(a.isFile())return[i];if(!a.isDirectory())return;let o=S(i,m(i),F(e,t)??i);if(o!==void 0)return o;let s=L(e,t);return s?[s]:x(i)}function L(e,t){let i=n.default.resolve(t,e),o;try{let e=r.default.statSync(i);if(e.isFile())return i;o=e.isDirectory()}catch{return}if(!o)return;let s;try{s=JSON.parse(r.default.readFileSync(n.default.join(i,a),`utf8`))}catch{return}let c=s.exports,l=[E(typeof c==`object`&&c&&!Array.isArray(c)?c[`.`]:c)];for(let e of P)typeof s[e]==`string`&&l.push(s[e]);for(let e of l){if(!e)continue;let t=n.default.join(i,e);if(r.default.existsSync(t))return t}return b(i)}function R(e){let r=require(`url`).pathToFileURL(__filename).href.endsWith(`.ts`)?`ts`:`mjs`,i=n.default.dirname(n.default.dirname(n.default.dirname((0,t.fileURLToPath)(require(`url`).pathToFileURL(__filename).href))));return n.default.join(i,`extensions`,`entries`,`${e}.${r}`)}function z(){return n.default.join(n.default.dirname(C(`@earendil-works/pi-coding-agent`)),`cli.js`)}exports.consumerPackageEntries=M,exports.consumerPackageEntry=N,exports.localEntries=I,exports.localEntry=L,exports.localPackageName=F,exports.optionalPackageEntries=j,exports.optionalPackageEntry=w,exports.ownEntry=R,exports.packageEntries=A,exports.packageEntry=C,exports.piCliPath=z,exports.splitPackageSpecifier=T;
2
2
  //# sourceMappingURL=moduleResolution.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"moduleResolution.cjs","names":["fs","path"],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { minimatch } from 'minimatch';\n\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst CURRENT_DIRECTORY_PREFIX = './';\nconst MANIFEST_PATTERN_PREFIXES = ['!', '+', '-'] as const;\nconst GLOB_CHARACTERS = /[*?[\\]{}()]/;\nconst EXTENSION_FILE_SUFFIXES = new Set(['.ts', '.js', '.mts', '.mjs', '.cts', '.cjs']);\n/** Import-side conditions, in the order Node prefers them for an ESM consumer. */\nconst IMPORT_CONDITIONS = ['import', 'module', 'node', 'default'] as const;\n\ninterface PackageManifest {\n name?: unknown;\n exports?: unknown;\n module?: unknown;\n main?: unknown;\n pi?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(packageRoot, PACKAGE_MANIFEST), 'utf8'));\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n // An unreadable manifest is equivalent to an absent package declaration;\n // the normal export resolver remains available as the compatibility path.\n return undefined;\n }\n}\n\nfunction isManifestPattern(entry: string): boolean {\n return MANIFEST_PATTERN_PREFIXES.some((prefix) => entry.startsWith(prefix));\n}\n\nfunction normalizedRelativePath(packageRoot: string, target: string): string {\n return path.relative(packageRoot, target).split(path.sep).join('/');\n}\n\nfunction matchesManifestPattern(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n const relative = normalizedRelativePath(packageRoot, target);\n return (\n minimatch(relative, normalizedPattern) ||\n minimatch(path.basename(target), normalizedPattern) ||\n minimatch(target.split(path.sep).join('/'), normalizedPattern)\n );\n}\n\nfunction matchesExactManifestPath(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n return (\n normalizedRelativePath(packageRoot, target) === normalizedPattern ||\n target.split(path.sep).join('/') === normalizedPattern\n );\n}\n\nfunction extensionFilesAt(target: string): string[] {\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return [];\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return [];\n\n const files: string[] = [];\n for (const entry of fs\n .readdirSync(target, { withFileTypes: true })\n .sort((left, right) => left.name.localeCompare(right.name))) {\n const entryPath = path.join(target, entry.name);\n if ((entry.isFile() || entry.isSymbolicLink()) && EXTENSION_FILE_SUFFIXES.has(path.extname(entry.name))) {\n files.push(entryPath);\n continue;\n }\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n for (const indexName of ['index.ts', 'index.js', 'index.mts', 'index.mjs', 'index.cts', 'index.cjs']) {\n const indexPath = path.join(entryPath, indexName);\n if (fs.existsSync(indexPath)) {\n files.push(indexPath);\n break;\n }\n }\n }\n return files;\n}\n\n/** Resolves the standard package.json pi.extensions declaration exactly as a layer contribution. */\nfunction manifestExtensionEntries(\n packageRoot: string,\n manifest: PackageManifest | undefined,\n packageName: string,\n): string[] | undefined {\n if (!manifest || !isRecord(manifest.pi) || !Object.hasOwn(manifest.pi, 'extensions')) return undefined;\n const configured = manifest.pi.extensions;\n if (!Array.isArray(configured) || !configured.every((entry) => typeof entry === 'string')) {\n throw new Error(`${packageName} package.json pi.extensions must be an array of strings.`);\n }\n\n const allPaths: string[] = [];\n for (const configuredEntry of configured.filter((entry) => !isManifestPattern(entry))) {\n const candidates = GLOB_CHARACTERS.test(configuredEntry)\n ? fs.globSync(configuredEntry, { cwd: packageRoot }).sort()\n : [configuredEntry];\n for (const candidate of candidates) {\n for (const target of extensionFilesAt(path.resolve(packageRoot, candidate))) {\n if (!allPaths.includes(target)) allPaths.push(target);\n }\n }\n }\n\n const excluded = configured.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1));\n const forceIncluded = configured.filter((entry) => entry.startsWith('+')).map((entry) => entry.slice(1));\n const forceExcluded = configured.filter((entry) => entry.startsWith('-')).map((entry) => entry.slice(1));\n const selected = allPaths.filter(\n (target) => !excluded.some((pattern) => matchesManifestPattern(target, pattern, packageRoot)),\n );\n for (const target of allPaths) {\n if (\n !selected.includes(target) &&\n forceIncluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot))\n ) {\n selected.push(target);\n }\n }\n return selected.filter(\n (target) => !forceExcluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot)),\n );\n}\n\n/**\n * Resolves the on-disk entry point of an installed package.\n *\n * Pi loads extensions by absolute path, so anything contributed as an\n * extension has to be resolved to a file before it can be passed along.\n */\nexport function packageEntry(name: string): string {\n return fileURLToPath(import.meta.resolve(name));\n}\n\n/** Same as packageEntry, but returns undefined when the package is absent. */\nexport function optionalPackageEntry(name: string): string | undefined {\n try {\n return packageEntry(name);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Splits `@scope/name/sub/path` into the package name and its export subpath.\n *\n * A scoped name owns two segments, an unscoped name one. Everything after that\n * is the subpath the package's own `exports` map has to answer for.\n */\nexport function splitPackageSpecifier(specifier: string): { name: string; subpath: string } {\n const segments = specifier.split('/');\n const nameSegments = specifier.startsWith('@') ? 2 : 1;\n const name = segments.slice(0, nameSegments).join('/');\n const rest = segments.slice(nameSegments).join('/');\n return { name, subpath: rest ? `${CURRENT_DIRECTORY_PREFIX}${rest}` : '.' };\n}\n\n/** Picks the import-side target out of one `exports` entry. */\nfunction selectImportTarget(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n for (const candidate of value) {\n const target = selectImportTarget(candidate);\n if (target) return target;\n }\n return undefined;\n }\n if (typeof value !== 'object' || value === null) return undefined;\n const conditions = value as Record<string, unknown>;\n for (const condition of IMPORT_CONDITIONS) {\n if (condition in conditions) {\n const target = selectImportTarget(conditions[condition]);\n if (target) return target;\n }\n }\n return undefined;\n}\n\n/**\n * Finds an installed package directory by walking the consumer's module chain.\n *\n * Node's own lookup order, so a workspace link in the repository root is found\n * exactly where the repository installed it, and nothing outside that chain can\n * answer for a specifier the repository declared.\n */\nfunction findInstalledPackage(name: string, consumerRoot: string): string | undefined {\n let directory = path.resolve(consumerRoot);\n while (true) {\n const candidate = path.join(directory, NODE_MODULES, name);\n if (fs.existsSync(path.join(candidate, PACKAGE_MANIFEST))) return candidate;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\n/** Resolves every extension declared by a bare package's standard Pi manifest. */\nexport function packageEntries(specifier: string): string[] {\n const { name, subpath } = splitPackageSpecifier(specifier);\n if (subpath !== '.') return [packageEntry(specifier)];\n\n const packageRoot = findInstalledPackage(name, path.dirname(fileURLToPath(import.meta.url)));\n const manifestEntries = packageRoot\n ? manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name)\n : undefined;\n return manifestEntries ?? [packageEntry(specifier)];\n}\n\n/** Same as packageEntries, but returns undefined when the package is absent. */\nexport function optionalPackageEntries(specifier: string): string[] | undefined {\n try {\n return packageEntries(specifier);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves manifest entries from the consumer repository's dependency tree.\n *\n * The meta-package cannot resolve what the repository declares: under an\n * isolated node_modules layout Doom Pi only sees its own dependencies. Walking\n * the consumer's module chain lets its package manifest answer first without\n * accidentally falling through to DoomPi's dependency tree.\n */\nexport function consumerPackageEntries(specifier: string, consumerRoot: string): string[] | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findInstalledPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n if (subpath === '.') {\n const manifestEntries = manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name);\n if (manifestEntries !== undefined) return manifestEntries;\n }\n const entry = consumerPackageEntry(specifier, consumerRoot);\n return entry ? [entry] : [];\n}\n\n/** Resolves one explicit package export or direct package-relative path from the consumer. */\nexport function consumerPackageEntry(specifier: string, consumerRoot: string): string | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findInstalledPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n\n const manifestPath = path.join(packageRoot, PACKAGE_MANIFEST);\n // A relative subpath that the package does not export is still loadable by\n // path, which is how layers point at a file inside a package (`.../index.ts`).\n const directTarget = path.join(packageRoot, subpath);\n let manifest: { exports?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as { exports?: unknown };\n } catch {\n return fs.existsSync(directTarget) ? directTarget : undefined;\n }\n\n const exports = manifest.exports;\n if (exports !== undefined && exports !== null) {\n const entry =\n typeof exports === 'object' && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)[subpath]\n : subpath === '.'\n ? exports\n : undefined;\n const target = selectImportTarget(entry);\n if (target) {\n const resolved = path.join(packageRoot, target);\n if (fs.existsSync(resolved)) return resolved;\n }\n }\n\n return subpath === '.' ? undefined : fs.existsSync(directTarget) ? directTarget : undefined;\n}\n\n/** Manifest fields consulted when a local package declares no `exports`. */\nconst MAIN_FIELDS = ['module', 'main'] as const;\n\n/**\n * Returns the canonical name of a path-style package directory.\n *\n * A direct file is intentionally anonymous: treating the repository manifest\n * above it as the file's identity would collapse every local extension in that\n * repository. Only a directory with its own named manifest represents a package\n * that can replace another installed version by logical identity.\n */\nexport function localPackageName(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n try {\n if (!fs.statSync(target).isDirectory()) return undefined;\n const manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as {\n name?: unknown;\n };\n return typeof manifest.name === 'string' && manifest.name.trim() ? manifest.name.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves all standard Pi manifest entries from a path-style package.\n *\n * A file is taken as the extension entry as written. A package directory uses\n * its native `pi.extensions` declaration. This lets unpublished extensions live\n * in the repository, or beside the global config in `~/.pi/.doom`, and still\n * load in manifest order.\n */\nexport function localEntries(specifier: string, baseDirectory: string): string[] | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return undefined;\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return undefined;\n\n const manifest = readPackageManifest(target);\n const manifestEntries = manifestExtensionEntries(\n target,\n manifest,\n localPackageName(specifier, baseDirectory) ?? target,\n );\n if (manifestEntries !== undefined) return manifestEntries;\n const entry = localEntry(specifier, baseDirectory);\n return entry ? [entry] : [];\n}\n\n/** Resolves the legacy single entry from a local package's exports, module, or main field. */\nexport function localEntry(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let isDirectory: boolean;\n try {\n const stats = fs.statSync(target);\n if (stats.isFile()) return target;\n isDirectory = stats.isDirectory();\n } catch {\n return undefined;\n }\n if (!isDirectory) return undefined;\n\n let manifest: { exports?: unknown; module?: unknown; main?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as typeof manifest;\n } catch {\n return undefined;\n }\n\n const exports = manifest.exports;\n const rootExport =\n typeof exports === 'object' && exports !== null && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)['.']\n : exports;\n const candidates = [selectImportTarget(rootExport)];\n for (const field of MAIN_FIELDS) {\n if (typeof manifest[field] === 'string') candidates.push(manifest[field]);\n }\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const resolved = path.join(target, candidate);\n if (fs.existsSync(resolved)) return resolved;\n }\n return undefined;\n}\n\n/**\n * Resolves one of this package's own extensions in src/extensions/entries.\n *\n * The file extension differs between running from source (.ts, how the shell\n * launchers invoke this) and running the build output (.mjs), so it is derived\n * from this module's own URL rather than assumed.\n */\nexport function ownEntry(name: string): string {\n const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'mjs';\n // This file sits in src/adapters/modules, so the source root is two directories up.\n const sourceRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));\n return path.join(sourceRoot, 'extensions', 'entries', `${name}.${extension}`);\n}\n\n/** Path to Pi's own CLI, which the launch command spawns. */\nexport function piCliPath(): string {\n return path.join(path.dirname(packageEntry('@earendil-works/pi-coding-agent')), 'cli.js');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"moduleResolution.cjs","names":["path","fs"],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { minimatch } from 'minimatch';\n\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst PI_MANAGED_NPM_DIRECTORY = path.join('.pi', 'npm', NODE_MODULES);\nconst CURRENT_DIRECTORY_PREFIX = './';\nconst MANIFEST_PATTERN_PREFIXES = ['!', '+', '-'] as const;\nconst GLOB_CHARACTERS = /[*?[\\]{}()]/;\nconst EXTENSION_INDEX_NAMES = ['index.ts', 'index.js', 'index.mts', 'index.mjs', 'index.cts', 'index.cjs'] as const;\nconst EXTENSION_FILE_SUFFIXES = new Set(['.ts', '.js', '.mts', '.mjs', '.cts', '.cjs']);\n/** Import-side conditions, in the order Node prefers them for an ESM consumer. */\nconst IMPORT_CONDITIONS = ['import', 'module', 'node', 'default'] as const;\n\ninterface PackageManifest {\n name?: unknown;\n exports?: unknown;\n module?: unknown;\n main?: unknown;\n pi?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(packageRoot, PACKAGE_MANIFEST), 'utf8'));\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n // An unreadable manifest is equivalent to an absent package declaration;\n // the normal export resolver remains available as the compatibility path.\n return undefined;\n }\n}\n\nfunction manifestDeclaresExtensions(manifest: PackageManifest | undefined): boolean {\n return Boolean(manifest && isRecord(manifest.pi) && Object.hasOwn(manifest.pi, 'extensions'));\n}\n\nfunction isManifestPattern(entry: string): boolean {\n return MANIFEST_PATTERN_PREFIXES.some((prefix) => entry.startsWith(prefix));\n}\n\nfunction normalizedRelativePath(packageRoot: string, target: string): string {\n return path.relative(packageRoot, target).split(path.sep).join('/');\n}\n\nfunction matchesManifestPattern(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n const relative = normalizedRelativePath(packageRoot, target);\n return (\n minimatch(relative, normalizedPattern) ||\n minimatch(path.basename(target), normalizedPattern) ||\n minimatch(target.split(path.sep).join('/'), normalizedPattern)\n );\n}\n\nfunction matchesExactManifestPath(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n return (\n normalizedRelativePath(packageRoot, target) === normalizedPattern ||\n target.split(path.sep).join('/') === normalizedPattern\n );\n}\n\nfunction extensionIndexEntry(directory: string): string | undefined {\n for (const indexName of EXTENSION_INDEX_NAMES) {\n const candidate = path.join(directory, indexName);\n if (fs.existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction extensionFilesAt(target: string): string[] {\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return [];\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return [];\n\n const files: string[] = [];\n for (const entry of fs\n .readdirSync(target, { withFileTypes: true })\n .sort((left, right) => left.name.localeCompare(right.name))) {\n const entryPath = path.join(target, entry.name);\n if ((entry.isFile() || entry.isSymbolicLink()) && EXTENSION_FILE_SUFFIXES.has(path.extname(entry.name))) {\n files.push(entryPath);\n continue;\n }\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n const indexEntry = extensionIndexEntry(entryPath);\n if (indexEntry) files.push(indexEntry);\n }\n return files;\n}\n\n/** Resolves the standard package.json pi.extensions declaration exactly as a layer contribution. */\nfunction manifestExtensionEntries(\n packageRoot: string,\n manifest: PackageManifest | undefined,\n packageName: string,\n): string[] | undefined {\n if (!manifestDeclaresExtensions(manifest) || !isRecord(manifest?.pi)) return undefined;\n const configured = manifest.pi.extensions;\n if (!Array.isArray(configured) || !configured.every((entry) => typeof entry === 'string')) {\n throw new Error(`${packageName} package.json pi.extensions must be an array of strings.`);\n }\n\n const allPaths: string[] = [];\n for (const configuredEntry of configured.filter((entry) => !isManifestPattern(entry))) {\n const candidates = GLOB_CHARACTERS.test(configuredEntry)\n ? fs.globSync(configuredEntry, { cwd: packageRoot }).sort()\n : [configuredEntry];\n for (const candidate of candidates) {\n for (const target of extensionFilesAt(path.resolve(packageRoot, candidate))) {\n if (!allPaths.includes(target)) allPaths.push(target);\n }\n }\n }\n\n const excluded = configured.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1));\n const forceIncluded = configured.filter((entry) => entry.startsWith('+')).map((entry) => entry.slice(1));\n const forceExcluded = configured.filter((entry) => entry.startsWith('-')).map((entry) => entry.slice(1));\n const selected = allPaths.filter(\n (target) => !excluded.some((pattern) => matchesManifestPattern(target, pattern, packageRoot)),\n );\n for (const target of allPaths) {\n if (\n !selected.includes(target) &&\n forceIncluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot))\n ) {\n selected.push(target);\n }\n }\n const filtered = selected.filter(\n (target) => !forceExcluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot)),\n );\n return filtered.length > 0 ? filtered : undefined;\n}\n\n/**\n * Resolves the on-disk entry point of an installed package.\n *\n * Pi loads extensions by absolute path, so anything contributed as an\n * extension has to be resolved to a file before it can be passed along.\n */\nexport function packageEntry(name: string): string {\n return fileURLToPath(import.meta.resolve(name));\n}\n\n/** Same as packageEntry, but returns undefined when the package is absent. */\nexport function optionalPackageEntry(name: string): string | undefined {\n try {\n return packageEntry(name);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Splits `@scope/name/sub/path` into the package name and its export subpath.\n *\n * A scoped name owns two segments, an unscoped name one. Everything after that\n * is the subpath the package's own `exports` map has to answer for.\n */\nexport function splitPackageSpecifier(specifier: string): { name: string; subpath: string } {\n const segments = specifier.split('/');\n const nameSegments = specifier.startsWith('@') ? 2 : 1;\n const name = segments.slice(0, nameSegments).join('/');\n const rest = segments.slice(nameSegments).join('/');\n return { name, subpath: rest ? `${CURRENT_DIRECTORY_PREFIX}${rest}` : '.' };\n}\n\n/** Picks the import-side target out of one `exports` entry. */\nfunction selectImportTarget(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n for (const candidate of value) {\n const target = selectImportTarget(candidate);\n if (target) return target;\n }\n return undefined;\n }\n if (typeof value !== 'object' || value === null) return undefined;\n const conditions = value as Record<string, unknown>;\n for (const condition of IMPORT_CONDITIONS) {\n if (condition in conditions) {\n const target = selectImportTarget(conditions[condition]);\n if (target) return target;\n }\n }\n return undefined;\n}\n\n/**\n * Finds an installed package directory by walking the consumer's module chain.\n *\n * Node's own lookup order, so a workspace link in the repository root is found\n * exactly where the repository installed it, and nothing outside that chain can\n * answer for a specifier the repository declared.\n */\nfunction findInstalledPackage(name: string, consumerRoot: string): string | undefined {\n let directory = path.resolve(consumerRoot);\n while (true) {\n const candidate = path.join(directory, NODE_MODULES, name);\n if (fs.existsSync(path.join(candidate, PACKAGE_MANIFEST))) return candidate;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\n/** Finds a package provisioned by Pi without mutating the consumer's package manifest. */\nfunction findManagedPackage(name: string, consumerRoot: string): string | undefined {\n const candidate = path.join(path.resolve(consumerRoot), PI_MANAGED_NPM_DIRECTORY, name);\n return fs.existsSync(path.join(candidate, PACKAGE_MANIFEST)) ? candidate : undefined;\n}\n\nfunction findConsumerPackage(name: string, consumerRoot: string): string | undefined {\n return findInstalledPackage(name, consumerRoot) ?? findManagedPackage(name, consumerRoot);\n}\n\n/** Resolves every extension declared by a bare package's standard Pi manifest. */\nexport function packageEntries(specifier: string): string[] {\n const { name, subpath } = splitPackageSpecifier(specifier);\n if (subpath !== '.') return [packageEntry(specifier)];\n\n const packageRoot = findInstalledPackage(name, path.dirname(fileURLToPath(import.meta.url)));\n const manifest = packageRoot ? readPackageManifest(packageRoot) : undefined;\n const manifestEntries = packageRoot ? manifestExtensionEntries(packageRoot, manifest, name) : undefined;\n if (manifestEntries) return manifestEntries;\n const indexEntry = packageRoot && manifestDeclaresExtensions(manifest) ? extensionIndexEntry(packageRoot) : undefined;\n return [indexEntry ?? packageEntry(specifier)];\n}\n\n/** Same as packageEntries, but returns undefined when the package is absent. */\nexport function optionalPackageEntries(specifier: string): string[] | undefined {\n try {\n return packageEntries(specifier);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves manifest entries from the consumer repository's dependency tree.\n *\n * The meta-package cannot resolve what the repository declares: under an\n * isolated node_modules layout Doom Pi only sees its own dependencies. Walking\n * the consumer's module chain lets its package manifest answer first without\n * accidentally falling through to DoomPi's dependency tree.\n */\nexport function consumerPackageEntries(specifier: string, consumerRoot: string): string[] | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findConsumerPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n if (subpath === '.') {\n const manifestEntries = manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name);\n if (manifestEntries !== undefined) return manifestEntries;\n }\n const entry = consumerPackageEntry(specifier, consumerRoot);\n return entry ? [entry] : [];\n}\n\n/** Resolves one explicit package export or direct package-relative path from the consumer. */\nexport function consumerPackageEntry(specifier: string, consumerRoot: string): string | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findConsumerPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n\n const manifestPath = path.join(packageRoot, PACKAGE_MANIFEST);\n // A relative subpath that the package does not export is still loadable by\n // path, which is how layers point at a file inside a package (`.../index.ts`).\n const directTarget = path.join(packageRoot, subpath);\n let manifest: { exports?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as { exports?: unknown };\n } catch {\n return subpath === '.' ? extensionIndexEntry(packageRoot) : fs.existsSync(directTarget) ? directTarget : undefined;\n }\n\n const exports = manifest.exports;\n if (exports !== undefined && exports !== null) {\n const entry =\n typeof exports === 'object' && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)[subpath]\n : subpath === '.'\n ? exports\n : undefined;\n const target = selectImportTarget(entry);\n if (target) {\n const resolved = path.join(packageRoot, target);\n if (fs.existsSync(resolved)) return resolved;\n }\n }\n\n return subpath === '.' ? extensionIndexEntry(packageRoot) : fs.existsSync(directTarget) ? directTarget : undefined;\n}\n\n/** Manifest fields consulted when a local package declares no `exports`. */\nconst MAIN_FIELDS = ['module', 'main'] as const;\n\n/**\n * Returns the canonical name of a path-style package directory.\n *\n * A direct file is intentionally anonymous: treating the repository manifest\n * above it as the file's identity would collapse every local extension in that\n * repository. Only a directory with its own named manifest represents a package\n * that can replace another installed version by logical identity.\n */\nexport function localPackageName(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n try {\n if (!fs.statSync(target).isDirectory()) return undefined;\n const manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as {\n name?: unknown;\n };\n return typeof manifest.name === 'string' && manifest.name.trim() ? manifest.name.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves Pi extension entries from a local file, extension directory, or package.\n *\n * A file is taken as the extension entry as written. A package directory uses\n * its native `pi.extensions` declaration or legacy root entry. A plain directory\n * follows Pi's extension discovery convention for scripts and child `index`\n * modules. This lets unpublished extensions live in the repository, or beside\n * the global config in `~/.pi/.doom`, and still load in deterministic order.\n */\nexport function localEntries(specifier: string, baseDirectory: string): string[] | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return undefined;\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return undefined;\n\n const manifest = readPackageManifest(target);\n const manifestEntries = manifestExtensionEntries(\n target,\n manifest,\n localPackageName(specifier, baseDirectory) ?? target,\n );\n if (manifestEntries !== undefined) return manifestEntries;\n const entry = localEntry(specifier, baseDirectory);\n return entry ? [entry] : extensionFilesAt(target);\n}\n\n/** Resolves the legacy single entry from a local package's exports, module, or main field. */\nexport function localEntry(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let isDirectory: boolean;\n try {\n const stats = fs.statSync(target);\n if (stats.isFile()) return target;\n isDirectory = stats.isDirectory();\n } catch {\n return undefined;\n }\n if (!isDirectory) return undefined;\n\n let manifest: { exports?: unknown; module?: unknown; main?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as typeof manifest;\n } catch {\n return undefined;\n }\n\n const exports = manifest.exports;\n const rootExport =\n typeof exports === 'object' && exports !== null && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)['.']\n : exports;\n const candidates = [selectImportTarget(rootExport)];\n for (const field of MAIN_FIELDS) {\n if (typeof manifest[field] === 'string') candidates.push(manifest[field]);\n }\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const resolved = path.join(target, candidate);\n if (fs.existsSync(resolved)) return resolved;\n }\n return extensionIndexEntry(target);\n}\n\n/**\n * Resolves one of this package's own extensions in src/extensions/entries.\n *\n * The file extension differs between running from source (.ts, how the shell\n * launchers invoke this) and running the build output (.mjs), so it is derived\n * from this module's own URL rather than assumed.\n */\nexport function ownEntry(name: string): string {\n const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'mjs';\n // This file sits in src/adapters/modules, so the source root is two directories up.\n const sourceRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));\n return path.join(sourceRoot, 'extensions', 'entries', `${name}.${extension}`);\n}\n\n/** Path to Pi's own CLI, which the launch command spawns. */\nexport function piCliPath(): string {\n return path.join(path.dirname(packageEntry('@earendil-works/pi-coding-agent')), 'cli.js');\n}\n"],"mappings":"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"}
@@ -43,12 +43,13 @@ declare function consumerPackageEntry(specifier: string, consumerRoot: string):
43
43
  */
44
44
  declare function localPackageName(specifier: string, baseDirectory: string): string | undefined;
45
45
  /**
46
- * Resolves all standard Pi manifest entries from a path-style package.
46
+ * Resolves Pi extension entries from a local file, extension directory, or package.
47
47
  *
48
48
  * A file is taken as the extension entry as written. A package directory uses
49
- * its native `pi.extensions` declaration. This lets unpublished extensions live
50
- * in the repository, or beside the global config in `~/.pi/.doom`, and still
51
- * load in manifest order.
49
+ * its native `pi.extensions` declaration or legacy root entry. A plain directory
50
+ * follows Pi's extension discovery convention for scripts and child `index`
51
+ * modules. This lets unpublished extensions live in the repository, or beside
52
+ * the global config in `~/.pi/.doom`, and still load in deterministic order.
52
53
  */
53
54
  declare function localEntries(specifier: string, baseDirectory: string): string[] | undefined;
54
55
  /** Resolves the legacy single entry from a local package's exports, module, or main field. */
@@ -1 +1 @@
1
- {"version":3,"file":"moduleResolution.d.cts","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"mappings":";;AA+IA;;;;;iBAAgB,YAAA,CAAa,IAAA;;iBAKb,oBAAA,CAAqB,IAAA;;;AAcrC;;;;iBAAgB,qBAAA,CAAsB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;iBAgD1D,cAAA,CAAe,SAAA;;iBAYf,sBAAA,CAAuB,SAAA;;;AAAvC;;;;;AAgBA;iBAAgB,sBAAA,CAAuB,SAAA,UAAmB,YAAA;;iBAa1C,oBAAA,CAAqB,SAAA,UAAmB,YAAA;;AAAxD;;;;;AA6CA;;iBAAgB,gBAAA,CAAiB,SAAA,UAAmB,aAAA;;;AAqBpD;;;;;AAuBA;iBAvBgB,YAAA,CAAa,SAAA,UAAmB,aAAA;;iBAuBhC,UAAA,CAAW,SAAA,UAAmB,aAAA;;AA4C9C;;;;;AAQA;iBARgB,QAAA,CAAS,IAAA;;iBAQT,SAAA,CAAA"}
1
+ {"version":3,"file":"moduleResolution.d.cts","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"mappings":";;AAyJA;;;;;iBAAgB,YAAA,CAAa,IAAA;;iBAKb,oBAAA,CAAqB,IAAA;;;AAcrC;;;;iBAAgB,qBAAA,CAAsB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;iBA0D1D,cAAA,CAAe,SAAA;;iBAaf,sBAAA,CAAuB,SAAA;;;AAAvC;;;;;AAgBA;iBAAgB,sBAAA,CAAuB,SAAA,UAAmB,YAAA;;iBAa1C,oBAAA,CAAqB,SAAA,UAAmB,YAAA;;AAAxD;;;;;AA6CA;;iBAAgB,gBAAA,CAAiB,SAAA,UAAmB,aAAA;;;AAsBpD;;;;;AAuBA;;iBAvBgB,YAAA,CAAa,SAAA,UAAmB,aAAA;;iBAuBhC,UAAA,CAAW,SAAA,UAAmB,aAAA;AA4C9C;;;;;AAQA;;AARA,iBAAgB,QAAA,CAAS,IAAA;;iBAQT,SAAA,CAAA"}
@@ -43,12 +43,13 @@ declare function consumerPackageEntry(specifier: string, consumerRoot: string):
43
43
  */
44
44
  declare function localPackageName(specifier: string, baseDirectory: string): string | undefined;
45
45
  /**
46
- * Resolves all standard Pi manifest entries from a path-style package.
46
+ * Resolves Pi extension entries from a local file, extension directory, or package.
47
47
  *
48
48
  * A file is taken as the extension entry as written. A package directory uses
49
- * its native `pi.extensions` declaration. This lets unpublished extensions live
50
- * in the repository, or beside the global config in `~/.pi/.doom`, and still
51
- * load in manifest order.
49
+ * its native `pi.extensions` declaration or legacy root entry. A plain directory
50
+ * follows Pi's extension discovery convention for scripts and child `index`
51
+ * modules. This lets unpublished extensions live in the repository, or beside
52
+ * the global config in `~/.pi/.doom`, and still load in deterministic order.
52
53
  */
53
54
  declare function localEntries(specifier: string, baseDirectory: string): string[] | undefined;
54
55
  /** Resolves the legacy single entry from a local package's exports, module, or main field. */
@@ -1 +1 @@
1
- {"version":3,"file":"moduleResolution.d.mts","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"mappings":";;AA+IA;;;;;iBAAgB,YAAA,CAAa,IAAA;;iBAKb,oBAAA,CAAqB,IAAA;;;AAcrC;;;;iBAAgB,qBAAA,CAAsB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;iBAgD1D,cAAA,CAAe,SAAA;;iBAYf,sBAAA,CAAuB,SAAA;;;AAAvC;;;;;AAgBA;iBAAgB,sBAAA,CAAuB,SAAA,UAAmB,YAAA;;iBAa1C,oBAAA,CAAqB,SAAA,UAAmB,YAAA;;AAAxD;;;;;AA6CA;;iBAAgB,gBAAA,CAAiB,SAAA,UAAmB,aAAA;;;AAqBpD;;;;;AAuBA;iBAvBgB,YAAA,CAAa,SAAA,UAAmB,aAAA;;iBAuBhC,UAAA,CAAW,SAAA,UAAmB,aAAA;;AA4C9C;;;;;AAQA;iBARgB,QAAA,CAAS,IAAA;;iBAQT,SAAA,CAAA"}
1
+ {"version":3,"file":"moduleResolution.d.mts","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"mappings":";;AAyJA;;;;;iBAAgB,YAAA,CAAa,IAAA;;iBAKb,oBAAA,CAAqB,IAAA;;;AAcrC;;;;iBAAgB,qBAAA,CAAsB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;iBA0D1D,cAAA,CAAe,SAAA;;iBAaf,sBAAA,CAAuB,SAAA;;;AAAvC;;;;;AAgBA;iBAAgB,sBAAA,CAAuB,SAAA,UAAmB,YAAA;;iBAa1C,oBAAA,CAAqB,SAAA,UAAmB,YAAA;;AAAxD;;;;;AA6CA;;iBAAgB,gBAAA,CAAiB,SAAA,UAAmB,aAAA;;;AAsBpD;;;;;AAuBA;;iBAvBgB,YAAA,CAAa,SAAA,UAAmB,aAAA;;iBAuBhC,UAAA,CAAW,SAAA,UAAmB,aAAA;AA4C9C;;;;;AAQA;;AARA,iBAAgB,QAAA,CAAS,IAAA;;iBAQT,SAAA,CAAA"}
@@ -1,2 +1,2 @@
1
- import{fileURLToPath as e}from"node:url";import t from"node:path";import n from"node:fs";import{minimatch as r}from"minimatch";const i=`package.json`,a=[`!`,`+`,`-`],o=/[*?[\]{}()]/,s=new Set([`.ts`,`.js`,`.mts`,`.mjs`,`.cts`,`.cjs`]),c=[`import`,`module`,`node`,`default`];function l(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function u(e){try{let r=JSON.parse(n.readFileSync(t.join(e,i),`utf8`));return l(r)?r:void 0}catch{return}}function d(e){return a.some(t=>e.startsWith(t))}function f(e,n){return t.relative(e,n).split(t.sep).join(`/`)}function p(e,n,i){let a=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);return r(f(i,e),a)||r(t.basename(e),a)||r(e.split(t.sep).join(`/`),a)}function m(e,n,r){let i=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);return f(r,e)===i||e.split(t.sep).join(`/`)===i}function h(e){let r;try{r=n.statSync(e)}catch{return[]}if(r.isFile())return[e];if(!r.isDirectory())return[];let i=[];for(let r of n.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))){let a=t.join(e,r.name);if((r.isFile()||r.isSymbolicLink())&&s.has(t.extname(r.name))){i.push(a);continue}if(!(!r.isDirectory()&&!r.isSymbolicLink()))for(let e of[`index.ts`,`index.js`,`index.mts`,`index.mjs`,`index.cts`,`index.cjs`]){let r=t.join(a,e);if(n.existsSync(r)){i.push(r);break}}}return i}function g(e,r,i){if(!r||!l(r.pi)||!Object.hasOwn(r.pi,`extensions`))return;let a=r.pi.extensions;if(!Array.isArray(a)||!a.every(e=>typeof e==`string`))throw Error(`${i} package.json pi.extensions must be an array of strings.`);let s=[];for(let r of a.filter(e=>!d(e))){let i=o.test(r)?n.globSync(r,{cwd:e}).sort():[r];for(let n of i)for(let r of h(t.resolve(e,n)))s.includes(r)||s.push(r)}let c=a.filter(e=>e.startsWith(`!`)).map(e=>e.slice(1)),u=a.filter(e=>e.startsWith(`+`)).map(e=>e.slice(1)),f=a.filter(e=>e.startsWith(`-`)).map(e=>e.slice(1)),g=s.filter(t=>!c.some(n=>p(t,n,e)));for(let t of s)!g.includes(t)&&u.some(n=>m(t,n,e))&&g.push(t);return g.filter(t=>!f.some(n=>m(t,n,e)))}function _(t){return e(import.meta.resolve(t))}function v(e){try{return _(e)}catch{return}}function y(e){let t=e.split(`/`),n=e.startsWith(`@`)?2:1,r=t.slice(0,n).join(`/`),i=t.slice(n).join(`/`);return{name:r,subpath:i?`./${i}`:`.`}}function b(e){if(typeof e==`string`)return e;if(Array.isArray(e)){for(let t of e){let e=b(t);if(e)return e}return}if(typeof e!=`object`||!e)return;let t=e;for(let e of c)if(e in t){let n=b(t[e]);if(n)return n}}function x(e,r){let a=t.resolve(r);for(;;){let r=t.join(a,`node_modules`,e);if(n.existsSync(t.join(r,i)))return r;let o=t.dirname(a);if(o===a)return;a=o}}function S(n){let{name:r,subpath:i}=y(n);if(i!==`.`)return[_(n)];let a=x(r,t.dirname(e(import.meta.url)));return(a?g(a,u(a),r):void 0)??[_(n)]}function C(e){try{return S(e)}catch{return}}function w(e,t){let{name:n,subpath:r}=y(e),i=x(n,t);if(!i)return;if(r===`.`){let e=g(i,u(i),n);if(e!==void 0)return e}let a=T(e,t);return a?[a]:[]}function T(e,r){let{name:a,subpath:o}=y(e),s=x(a,r);if(!s)return;let c=t.join(s,i),l=t.join(s,o),u;try{u=JSON.parse(n.readFileSync(c,`utf8`))}catch{return n.existsSync(l)?l:void 0}let d=u.exports;if(d!=null){let e=b(typeof d==`object`&&!Array.isArray(d)?d[o]:o===`.`?d:void 0);if(e){let r=t.join(s,e);if(n.existsSync(r))return r}}return o===`.`?void 0:n.existsSync(l)?l:void 0}const E=[`module`,`main`];function D(e,r){let a=t.resolve(r,e);try{if(!n.statSync(a).isDirectory())return;let e=JSON.parse(n.readFileSync(t.join(a,i),`utf8`));return typeof e.name==`string`&&e.name.trim()?e.name.trim():void 0}catch{return}}function O(e,r){let i=t.resolve(r,e),a;try{a=n.statSync(i)}catch{return}if(a.isFile())return[i];if(!a.isDirectory())return;let o=g(i,u(i),D(e,r)??i);if(o!==void 0)return o;let s=k(e,r);return s?[s]:[]}function k(e,r){let a=t.resolve(r,e),o;try{let e=n.statSync(a);if(e.isFile())return a;o=e.isDirectory()}catch{return}if(!o)return;let s;try{s=JSON.parse(n.readFileSync(t.join(a,i),`utf8`))}catch{return}let c=s.exports,l=[b(typeof c==`object`&&c&&!Array.isArray(c)?c[`.`]:c)];for(let e of E)typeof s[e]==`string`&&l.push(s[e]);for(let e of l){if(!e)continue;let r=t.join(a,e);if(n.existsSync(r))return r}}function A(n){let r=import.meta.url.endsWith(`.ts`)?`ts`:`mjs`,i=t.dirname(t.dirname(t.dirname(e(import.meta.url))));return t.join(i,`extensions`,`entries`,`${n}.${r}`)}function j(){return t.join(t.dirname(_(`@earendil-works/pi-coding-agent`)),`cli.js`)}export{w as consumerPackageEntries,T as consumerPackageEntry,O as localEntries,k as localEntry,D as localPackageName,C as optionalPackageEntries,v as optionalPackageEntry,A as ownEntry,S as packageEntries,_ as packageEntry,j as piCliPath,y as splitPackageSpecifier};
1
+ import{fileURLToPath as e}from"node:url";import t from"node:path";import n from"node:fs";import{minimatch as r}from"minimatch";const i=`package.json`,a=`node_modules`,o=t.join(`.pi`,`npm`,a),s=[`!`,`+`,`-`],c=/[*?[\]{}()]/,l=[`index.ts`,`index.js`,`index.mts`,`index.mjs`,`index.cts`,`index.cjs`],u=new Set([`.ts`,`.js`,`.mts`,`.mjs`,`.cts`,`.cjs`]),d=[`import`,`module`,`node`,`default`];function f(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function p(e){try{let r=JSON.parse(n.readFileSync(t.join(e,i),`utf8`));return f(r)?r:void 0}catch{return}}function m(e){return!!(e&&f(e.pi)&&Object.hasOwn(e.pi,`extensions`))}function h(e){return s.some(t=>e.startsWith(t))}function g(e,n){return t.relative(e,n).split(t.sep).join(`/`)}function _(e,n,i){let a=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);return r(g(i,e),a)||r(t.basename(e),a)||r(e.split(t.sep).join(`/`),a)}function v(e,n,r){let i=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);return g(r,e)===i||e.split(t.sep).join(`/`)===i}function y(e){for(let r of l){let i=t.join(e,r);if(n.existsSync(i))return i}}function b(e){let r;try{r=n.statSync(e)}catch{return[]}if(r.isFile())return[e];if(!r.isDirectory())return[];let i=[];for(let r of n.readdirSync(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))){let n=t.join(e,r.name);if((r.isFile()||r.isSymbolicLink())&&u.has(t.extname(r.name))){i.push(n);continue}if(!r.isDirectory()&&!r.isSymbolicLink())continue;let a=y(n);a&&i.push(a)}return i}function x(e,r,i){if(!m(r)||!f(r?.pi))return;let a=r.pi.extensions;if(!Array.isArray(a)||!a.every(e=>typeof e==`string`))throw Error(`${i} package.json pi.extensions must be an array of strings.`);let o=[];for(let r of a.filter(e=>!h(e))){let i=c.test(r)?n.globSync(r,{cwd:e}).sort():[r];for(let n of i)for(let r of b(t.resolve(e,n)))o.includes(r)||o.push(r)}let s=a.filter(e=>e.startsWith(`!`)).map(e=>e.slice(1)),l=a.filter(e=>e.startsWith(`+`)).map(e=>e.slice(1)),u=a.filter(e=>e.startsWith(`-`)).map(e=>e.slice(1)),d=o.filter(t=>!s.some(n=>_(t,n,e)));for(let t of o)!d.includes(t)&&l.some(n=>v(t,n,e))&&d.push(t);let p=d.filter(t=>!u.some(n=>v(t,n,e)));return p.length>0?p:void 0}function S(t){return e(import.meta.resolve(t))}function C(e){try{return S(e)}catch{return}}function w(e){let t=e.split(`/`),n=e.startsWith(`@`)?2:1,r=t.slice(0,n).join(`/`),i=t.slice(n).join(`/`);return{name:r,subpath:i?`./${i}`:`.`}}function T(e){if(typeof e==`string`)return e;if(Array.isArray(e)){for(let t of e){let e=T(t);if(e)return e}return}if(typeof e!=`object`||!e)return;let t=e;for(let e of d)if(e in t){let n=T(t[e]);if(n)return n}}function E(e,r){let o=t.resolve(r);for(;;){let r=t.join(o,a,e);if(n.existsSync(t.join(r,i)))return r;let s=t.dirname(o);if(s===o)return;o=s}}function D(e,r){let a=t.join(t.resolve(r),o,e);return n.existsSync(t.join(a,i))?a:void 0}function O(e,t){return E(e,t)??D(e,t)}function k(n){let{name:r,subpath:i}=w(n);if(i!==`.`)return[S(n)];let a=E(r,t.dirname(e(import.meta.url))),o=a?p(a):void 0;return(a?x(a,o,r):void 0)||[(a&&m(o)?y(a):void 0)??S(n)]}function A(e){try{return k(e)}catch{return}}function j(e,t){let{name:n,subpath:r}=w(e),i=O(n,t);if(!i)return;if(r===`.`){let e=x(i,p(i),n);if(e!==void 0)return e}let a=M(e,t);return a?[a]:[]}function M(e,r){let{name:a,subpath:o}=w(e),s=O(a,r);if(!s)return;let c=t.join(s,i),l=t.join(s,o),u;try{u=JSON.parse(n.readFileSync(c,`utf8`))}catch{return o===`.`?y(s):n.existsSync(l)?l:void 0}let d=u.exports;if(d!=null){let e=T(typeof d==`object`&&!Array.isArray(d)?d[o]:o===`.`?d:void 0);if(e){let r=t.join(s,e);if(n.existsSync(r))return r}}return o===`.`?y(s):n.existsSync(l)?l:void 0}const N=[`module`,`main`];function P(e,r){let a=t.resolve(r,e);try{if(!n.statSync(a).isDirectory())return;let e=JSON.parse(n.readFileSync(t.join(a,i),`utf8`));return typeof e.name==`string`&&e.name.trim()?e.name.trim():void 0}catch{return}}function F(e,r){let i=t.resolve(r,e),a;try{a=n.statSync(i)}catch{return}if(a.isFile())return[i];if(!a.isDirectory())return;let o=x(i,p(i),P(e,r)??i);if(o!==void 0)return o;let s=I(e,r);return s?[s]:b(i)}function I(e,r){let a=t.resolve(r,e),o;try{let e=n.statSync(a);if(e.isFile())return a;o=e.isDirectory()}catch{return}if(!o)return;let s;try{s=JSON.parse(n.readFileSync(t.join(a,i),`utf8`))}catch{return}let c=s.exports,l=[T(typeof c==`object`&&c&&!Array.isArray(c)?c[`.`]:c)];for(let e of N)typeof s[e]==`string`&&l.push(s[e]);for(let e of l){if(!e)continue;let r=t.join(a,e);if(n.existsSync(r))return r}return y(a)}function L(n){let r=import.meta.url.endsWith(`.ts`)?`ts`:`mjs`,i=t.dirname(t.dirname(t.dirname(e(import.meta.url))));return t.join(i,`extensions`,`entries`,`${n}.${r}`)}function R(){return t.join(t.dirname(S(`@earendil-works/pi-coding-agent`)),`cli.js`)}export{j as consumerPackageEntries,M as consumerPackageEntry,F as localEntries,I as localEntry,P as localPackageName,A as optionalPackageEntries,C as optionalPackageEntry,L as ownEntry,k as packageEntries,S as packageEntry,R as piCliPath,w as splitPackageSpecifier};
2
2
  //# sourceMappingURL=moduleResolution.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"moduleResolution.mjs","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { minimatch } from 'minimatch';\n\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst CURRENT_DIRECTORY_PREFIX = './';\nconst MANIFEST_PATTERN_PREFIXES = ['!', '+', '-'] as const;\nconst GLOB_CHARACTERS = /[*?[\\]{}()]/;\nconst EXTENSION_FILE_SUFFIXES = new Set(['.ts', '.js', '.mts', '.mjs', '.cts', '.cjs']);\n/** Import-side conditions, in the order Node prefers them for an ESM consumer. */\nconst IMPORT_CONDITIONS = ['import', 'module', 'node', 'default'] as const;\n\ninterface PackageManifest {\n name?: unknown;\n exports?: unknown;\n module?: unknown;\n main?: unknown;\n pi?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(packageRoot, PACKAGE_MANIFEST), 'utf8'));\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n // An unreadable manifest is equivalent to an absent package declaration;\n // the normal export resolver remains available as the compatibility path.\n return undefined;\n }\n}\n\nfunction isManifestPattern(entry: string): boolean {\n return MANIFEST_PATTERN_PREFIXES.some((prefix) => entry.startsWith(prefix));\n}\n\nfunction normalizedRelativePath(packageRoot: string, target: string): string {\n return path.relative(packageRoot, target).split(path.sep).join('/');\n}\n\nfunction matchesManifestPattern(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n const relative = normalizedRelativePath(packageRoot, target);\n return (\n minimatch(relative, normalizedPattern) ||\n minimatch(path.basename(target), normalizedPattern) ||\n minimatch(target.split(path.sep).join('/'), normalizedPattern)\n );\n}\n\nfunction matchesExactManifestPath(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n return (\n normalizedRelativePath(packageRoot, target) === normalizedPattern ||\n target.split(path.sep).join('/') === normalizedPattern\n );\n}\n\nfunction extensionFilesAt(target: string): string[] {\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return [];\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return [];\n\n const files: string[] = [];\n for (const entry of fs\n .readdirSync(target, { withFileTypes: true })\n .sort((left, right) => left.name.localeCompare(right.name))) {\n const entryPath = path.join(target, entry.name);\n if ((entry.isFile() || entry.isSymbolicLink()) && EXTENSION_FILE_SUFFIXES.has(path.extname(entry.name))) {\n files.push(entryPath);\n continue;\n }\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n for (const indexName of ['index.ts', 'index.js', 'index.mts', 'index.mjs', 'index.cts', 'index.cjs']) {\n const indexPath = path.join(entryPath, indexName);\n if (fs.existsSync(indexPath)) {\n files.push(indexPath);\n break;\n }\n }\n }\n return files;\n}\n\n/** Resolves the standard package.json pi.extensions declaration exactly as a layer contribution. */\nfunction manifestExtensionEntries(\n packageRoot: string,\n manifest: PackageManifest | undefined,\n packageName: string,\n): string[] | undefined {\n if (!manifest || !isRecord(manifest.pi) || !Object.hasOwn(manifest.pi, 'extensions')) return undefined;\n const configured = manifest.pi.extensions;\n if (!Array.isArray(configured) || !configured.every((entry) => typeof entry === 'string')) {\n throw new Error(`${packageName} package.json pi.extensions must be an array of strings.`);\n }\n\n const allPaths: string[] = [];\n for (const configuredEntry of configured.filter((entry) => !isManifestPattern(entry))) {\n const candidates = GLOB_CHARACTERS.test(configuredEntry)\n ? fs.globSync(configuredEntry, { cwd: packageRoot }).sort()\n : [configuredEntry];\n for (const candidate of candidates) {\n for (const target of extensionFilesAt(path.resolve(packageRoot, candidate))) {\n if (!allPaths.includes(target)) allPaths.push(target);\n }\n }\n }\n\n const excluded = configured.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1));\n const forceIncluded = configured.filter((entry) => entry.startsWith('+')).map((entry) => entry.slice(1));\n const forceExcluded = configured.filter((entry) => entry.startsWith('-')).map((entry) => entry.slice(1));\n const selected = allPaths.filter(\n (target) => !excluded.some((pattern) => matchesManifestPattern(target, pattern, packageRoot)),\n );\n for (const target of allPaths) {\n if (\n !selected.includes(target) &&\n forceIncluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot))\n ) {\n selected.push(target);\n }\n }\n return selected.filter(\n (target) => !forceExcluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot)),\n );\n}\n\n/**\n * Resolves the on-disk entry point of an installed package.\n *\n * Pi loads extensions by absolute path, so anything contributed as an\n * extension has to be resolved to a file before it can be passed along.\n */\nexport function packageEntry(name: string): string {\n return fileURLToPath(import.meta.resolve(name));\n}\n\n/** Same as packageEntry, but returns undefined when the package is absent. */\nexport function optionalPackageEntry(name: string): string | undefined {\n try {\n return packageEntry(name);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Splits `@scope/name/sub/path` into the package name and its export subpath.\n *\n * A scoped name owns two segments, an unscoped name one. Everything after that\n * is the subpath the package's own `exports` map has to answer for.\n */\nexport function splitPackageSpecifier(specifier: string): { name: string; subpath: string } {\n const segments = specifier.split('/');\n const nameSegments = specifier.startsWith('@') ? 2 : 1;\n const name = segments.slice(0, nameSegments).join('/');\n const rest = segments.slice(nameSegments).join('/');\n return { name, subpath: rest ? `${CURRENT_DIRECTORY_PREFIX}${rest}` : '.' };\n}\n\n/** Picks the import-side target out of one `exports` entry. */\nfunction selectImportTarget(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n for (const candidate of value) {\n const target = selectImportTarget(candidate);\n if (target) return target;\n }\n return undefined;\n }\n if (typeof value !== 'object' || value === null) return undefined;\n const conditions = value as Record<string, unknown>;\n for (const condition of IMPORT_CONDITIONS) {\n if (condition in conditions) {\n const target = selectImportTarget(conditions[condition]);\n if (target) return target;\n }\n }\n return undefined;\n}\n\n/**\n * Finds an installed package directory by walking the consumer's module chain.\n *\n * Node's own lookup order, so a workspace link in the repository root is found\n * exactly where the repository installed it, and nothing outside that chain can\n * answer for a specifier the repository declared.\n */\nfunction findInstalledPackage(name: string, consumerRoot: string): string | undefined {\n let directory = path.resolve(consumerRoot);\n while (true) {\n const candidate = path.join(directory, NODE_MODULES, name);\n if (fs.existsSync(path.join(candidate, PACKAGE_MANIFEST))) return candidate;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\n/** Resolves every extension declared by a bare package's standard Pi manifest. */\nexport function packageEntries(specifier: string): string[] {\n const { name, subpath } = splitPackageSpecifier(specifier);\n if (subpath !== '.') return [packageEntry(specifier)];\n\n const packageRoot = findInstalledPackage(name, path.dirname(fileURLToPath(import.meta.url)));\n const manifestEntries = packageRoot\n ? manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name)\n : undefined;\n return manifestEntries ?? [packageEntry(specifier)];\n}\n\n/** Same as packageEntries, but returns undefined when the package is absent. */\nexport function optionalPackageEntries(specifier: string): string[] | undefined {\n try {\n return packageEntries(specifier);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves manifest entries from the consumer repository's dependency tree.\n *\n * The meta-package cannot resolve what the repository declares: under an\n * isolated node_modules layout Doom Pi only sees its own dependencies. Walking\n * the consumer's module chain lets its package manifest answer first without\n * accidentally falling through to DoomPi's dependency tree.\n */\nexport function consumerPackageEntries(specifier: string, consumerRoot: string): string[] | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findInstalledPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n if (subpath === '.') {\n const manifestEntries = manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name);\n if (manifestEntries !== undefined) return manifestEntries;\n }\n const entry = consumerPackageEntry(specifier, consumerRoot);\n return entry ? [entry] : [];\n}\n\n/** Resolves one explicit package export or direct package-relative path from the consumer. */\nexport function consumerPackageEntry(specifier: string, consumerRoot: string): string | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findInstalledPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n\n const manifestPath = path.join(packageRoot, PACKAGE_MANIFEST);\n // A relative subpath that the package does not export is still loadable by\n // path, which is how layers point at a file inside a package (`.../index.ts`).\n const directTarget = path.join(packageRoot, subpath);\n let manifest: { exports?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as { exports?: unknown };\n } catch {\n return fs.existsSync(directTarget) ? directTarget : undefined;\n }\n\n const exports = manifest.exports;\n if (exports !== undefined && exports !== null) {\n const entry =\n typeof exports === 'object' && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)[subpath]\n : subpath === '.'\n ? exports\n : undefined;\n const target = selectImportTarget(entry);\n if (target) {\n const resolved = path.join(packageRoot, target);\n if (fs.existsSync(resolved)) return resolved;\n }\n }\n\n return subpath === '.' ? undefined : fs.existsSync(directTarget) ? directTarget : undefined;\n}\n\n/** Manifest fields consulted when a local package declares no `exports`. */\nconst MAIN_FIELDS = ['module', 'main'] as const;\n\n/**\n * Returns the canonical name of a path-style package directory.\n *\n * A direct file is intentionally anonymous: treating the repository manifest\n * above it as the file's identity would collapse every local extension in that\n * repository. Only a directory with its own named manifest represents a package\n * that can replace another installed version by logical identity.\n */\nexport function localPackageName(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n try {\n if (!fs.statSync(target).isDirectory()) return undefined;\n const manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as {\n name?: unknown;\n };\n return typeof manifest.name === 'string' && manifest.name.trim() ? manifest.name.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves all standard Pi manifest entries from a path-style package.\n *\n * A file is taken as the extension entry as written. A package directory uses\n * its native `pi.extensions` declaration. This lets unpublished extensions live\n * in the repository, or beside the global config in `~/.pi/.doom`, and still\n * load in manifest order.\n */\nexport function localEntries(specifier: string, baseDirectory: string): string[] | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return undefined;\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return undefined;\n\n const manifest = readPackageManifest(target);\n const manifestEntries = manifestExtensionEntries(\n target,\n manifest,\n localPackageName(specifier, baseDirectory) ?? target,\n );\n if (manifestEntries !== undefined) return manifestEntries;\n const entry = localEntry(specifier, baseDirectory);\n return entry ? [entry] : [];\n}\n\n/** Resolves the legacy single entry from a local package's exports, module, or main field. */\nexport function localEntry(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let isDirectory: boolean;\n try {\n const stats = fs.statSync(target);\n if (stats.isFile()) return target;\n isDirectory = stats.isDirectory();\n } catch {\n return undefined;\n }\n if (!isDirectory) return undefined;\n\n let manifest: { exports?: unknown; module?: unknown; main?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as typeof manifest;\n } catch {\n return undefined;\n }\n\n const exports = manifest.exports;\n const rootExport =\n typeof exports === 'object' && exports !== null && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)['.']\n : exports;\n const candidates = [selectImportTarget(rootExport)];\n for (const field of MAIN_FIELDS) {\n if (typeof manifest[field] === 'string') candidates.push(manifest[field]);\n }\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const resolved = path.join(target, candidate);\n if (fs.existsSync(resolved)) return resolved;\n }\n return undefined;\n}\n\n/**\n * Resolves one of this package's own extensions in src/extensions/entries.\n *\n * The file extension differs between running from source (.ts, how the shell\n * launchers invoke this) and running the build output (.mjs), so it is derived\n * from this module's own URL rather than assumed.\n */\nexport function ownEntry(name: string): string {\n const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'mjs';\n // This file sits in src/adapters/modules, so the source root is two directories up.\n const sourceRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));\n return path.join(sourceRoot, 'extensions', 'entries', `${name}.${extension}`);\n}\n\n/** Path to Pi's own CLI, which the launch command spawns. */\nexport function piCliPath(): string {\n return path.join(path.dirname(packageEntry('@earendil-works/pi-coding-agent')), 'cli.js');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"moduleResolution.mjs","names":[],"sources":["../../../src/adapters/modules/moduleResolution.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { minimatch } from 'minimatch';\n\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst PI_MANAGED_NPM_DIRECTORY = path.join('.pi', 'npm', NODE_MODULES);\nconst CURRENT_DIRECTORY_PREFIX = './';\nconst MANIFEST_PATTERN_PREFIXES = ['!', '+', '-'] as const;\nconst GLOB_CHARACTERS = /[*?[\\]{}()]/;\nconst EXTENSION_INDEX_NAMES = ['index.ts', 'index.js', 'index.mts', 'index.mjs', 'index.cts', 'index.cjs'] as const;\nconst EXTENSION_FILE_SUFFIXES = new Set(['.ts', '.js', '.mts', '.mjs', '.cts', '.cjs']);\n/** Import-side conditions, in the order Node prefers them for an ESM consumer. */\nconst IMPORT_CONDITIONS = ['import', 'module', 'node', 'default'] as const;\n\ninterface PackageManifest {\n name?: unknown;\n exports?: unknown;\n module?: unknown;\n main?: unknown;\n pi?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(packageRoot, PACKAGE_MANIFEST), 'utf8'));\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n // An unreadable manifest is equivalent to an absent package declaration;\n // the normal export resolver remains available as the compatibility path.\n return undefined;\n }\n}\n\nfunction manifestDeclaresExtensions(manifest: PackageManifest | undefined): boolean {\n return Boolean(manifest && isRecord(manifest.pi) && Object.hasOwn(manifest.pi, 'extensions'));\n}\n\nfunction isManifestPattern(entry: string): boolean {\n return MANIFEST_PATTERN_PREFIXES.some((prefix) => entry.startsWith(prefix));\n}\n\nfunction normalizedRelativePath(packageRoot: string, target: string): string {\n return path.relative(packageRoot, target).split(path.sep).join('/');\n}\n\nfunction matchesManifestPattern(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n const relative = normalizedRelativePath(packageRoot, target);\n return (\n minimatch(relative, normalizedPattern) ||\n minimatch(path.basename(target), normalizedPattern) ||\n minimatch(target.split(path.sep).join('/'), normalizedPattern)\n );\n}\n\nfunction matchesExactManifestPath(target: string, pattern: string, packageRoot: string): boolean {\n const normalizedPattern = pattern.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n return (\n normalizedRelativePath(packageRoot, target) === normalizedPattern ||\n target.split(path.sep).join('/') === normalizedPattern\n );\n}\n\nfunction extensionIndexEntry(directory: string): string | undefined {\n for (const indexName of EXTENSION_INDEX_NAMES) {\n const candidate = path.join(directory, indexName);\n if (fs.existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction extensionFilesAt(target: string): string[] {\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return [];\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return [];\n\n const files: string[] = [];\n for (const entry of fs\n .readdirSync(target, { withFileTypes: true })\n .sort((left, right) => left.name.localeCompare(right.name))) {\n const entryPath = path.join(target, entry.name);\n if ((entry.isFile() || entry.isSymbolicLink()) && EXTENSION_FILE_SUFFIXES.has(path.extname(entry.name))) {\n files.push(entryPath);\n continue;\n }\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n const indexEntry = extensionIndexEntry(entryPath);\n if (indexEntry) files.push(indexEntry);\n }\n return files;\n}\n\n/** Resolves the standard package.json pi.extensions declaration exactly as a layer contribution. */\nfunction manifestExtensionEntries(\n packageRoot: string,\n manifest: PackageManifest | undefined,\n packageName: string,\n): string[] | undefined {\n if (!manifestDeclaresExtensions(manifest) || !isRecord(manifest?.pi)) return undefined;\n const configured = manifest.pi.extensions;\n if (!Array.isArray(configured) || !configured.every((entry) => typeof entry === 'string')) {\n throw new Error(`${packageName} package.json pi.extensions must be an array of strings.`);\n }\n\n const allPaths: string[] = [];\n for (const configuredEntry of configured.filter((entry) => !isManifestPattern(entry))) {\n const candidates = GLOB_CHARACTERS.test(configuredEntry)\n ? fs.globSync(configuredEntry, { cwd: packageRoot }).sort()\n : [configuredEntry];\n for (const candidate of candidates) {\n for (const target of extensionFilesAt(path.resolve(packageRoot, candidate))) {\n if (!allPaths.includes(target)) allPaths.push(target);\n }\n }\n }\n\n const excluded = configured.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1));\n const forceIncluded = configured.filter((entry) => entry.startsWith('+')).map((entry) => entry.slice(1));\n const forceExcluded = configured.filter((entry) => entry.startsWith('-')).map((entry) => entry.slice(1));\n const selected = allPaths.filter(\n (target) => !excluded.some((pattern) => matchesManifestPattern(target, pattern, packageRoot)),\n );\n for (const target of allPaths) {\n if (\n !selected.includes(target) &&\n forceIncluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot))\n ) {\n selected.push(target);\n }\n }\n const filtered = selected.filter(\n (target) => !forceExcluded.some((pattern) => matchesExactManifestPath(target, pattern, packageRoot)),\n );\n return filtered.length > 0 ? filtered : undefined;\n}\n\n/**\n * Resolves the on-disk entry point of an installed package.\n *\n * Pi loads extensions by absolute path, so anything contributed as an\n * extension has to be resolved to a file before it can be passed along.\n */\nexport function packageEntry(name: string): string {\n return fileURLToPath(import.meta.resolve(name));\n}\n\n/** Same as packageEntry, but returns undefined when the package is absent. */\nexport function optionalPackageEntry(name: string): string | undefined {\n try {\n return packageEntry(name);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Splits `@scope/name/sub/path` into the package name and its export subpath.\n *\n * A scoped name owns two segments, an unscoped name one. Everything after that\n * is the subpath the package's own `exports` map has to answer for.\n */\nexport function splitPackageSpecifier(specifier: string): { name: string; subpath: string } {\n const segments = specifier.split('/');\n const nameSegments = specifier.startsWith('@') ? 2 : 1;\n const name = segments.slice(0, nameSegments).join('/');\n const rest = segments.slice(nameSegments).join('/');\n return { name, subpath: rest ? `${CURRENT_DIRECTORY_PREFIX}${rest}` : '.' };\n}\n\n/** Picks the import-side target out of one `exports` entry. */\nfunction selectImportTarget(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n for (const candidate of value) {\n const target = selectImportTarget(candidate);\n if (target) return target;\n }\n return undefined;\n }\n if (typeof value !== 'object' || value === null) return undefined;\n const conditions = value as Record<string, unknown>;\n for (const condition of IMPORT_CONDITIONS) {\n if (condition in conditions) {\n const target = selectImportTarget(conditions[condition]);\n if (target) return target;\n }\n }\n return undefined;\n}\n\n/**\n * Finds an installed package directory by walking the consumer's module chain.\n *\n * Node's own lookup order, so a workspace link in the repository root is found\n * exactly where the repository installed it, and nothing outside that chain can\n * answer for a specifier the repository declared.\n */\nfunction findInstalledPackage(name: string, consumerRoot: string): string | undefined {\n let directory = path.resolve(consumerRoot);\n while (true) {\n const candidate = path.join(directory, NODE_MODULES, name);\n if (fs.existsSync(path.join(candidate, PACKAGE_MANIFEST))) return candidate;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\n/** Finds a package provisioned by Pi without mutating the consumer's package manifest. */\nfunction findManagedPackage(name: string, consumerRoot: string): string | undefined {\n const candidate = path.join(path.resolve(consumerRoot), PI_MANAGED_NPM_DIRECTORY, name);\n return fs.existsSync(path.join(candidate, PACKAGE_MANIFEST)) ? candidate : undefined;\n}\n\nfunction findConsumerPackage(name: string, consumerRoot: string): string | undefined {\n return findInstalledPackage(name, consumerRoot) ?? findManagedPackage(name, consumerRoot);\n}\n\n/** Resolves every extension declared by a bare package's standard Pi manifest. */\nexport function packageEntries(specifier: string): string[] {\n const { name, subpath } = splitPackageSpecifier(specifier);\n if (subpath !== '.') return [packageEntry(specifier)];\n\n const packageRoot = findInstalledPackage(name, path.dirname(fileURLToPath(import.meta.url)));\n const manifest = packageRoot ? readPackageManifest(packageRoot) : undefined;\n const manifestEntries = packageRoot ? manifestExtensionEntries(packageRoot, manifest, name) : undefined;\n if (manifestEntries) return manifestEntries;\n const indexEntry = packageRoot && manifestDeclaresExtensions(manifest) ? extensionIndexEntry(packageRoot) : undefined;\n return [indexEntry ?? packageEntry(specifier)];\n}\n\n/** Same as packageEntries, but returns undefined when the package is absent. */\nexport function optionalPackageEntries(specifier: string): string[] | undefined {\n try {\n return packageEntries(specifier);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves manifest entries from the consumer repository's dependency tree.\n *\n * The meta-package cannot resolve what the repository declares: under an\n * isolated node_modules layout Doom Pi only sees its own dependencies. Walking\n * the consumer's module chain lets its package manifest answer first without\n * accidentally falling through to DoomPi's dependency tree.\n */\nexport function consumerPackageEntries(specifier: string, consumerRoot: string): string[] | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findConsumerPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n if (subpath === '.') {\n const manifestEntries = manifestExtensionEntries(packageRoot, readPackageManifest(packageRoot), name);\n if (manifestEntries !== undefined) return manifestEntries;\n }\n const entry = consumerPackageEntry(specifier, consumerRoot);\n return entry ? [entry] : [];\n}\n\n/** Resolves one explicit package export or direct package-relative path from the consumer. */\nexport function consumerPackageEntry(specifier: string, consumerRoot: string): string | undefined {\n const { name, subpath } = splitPackageSpecifier(specifier);\n const packageRoot = findConsumerPackage(name, consumerRoot);\n if (!packageRoot) return undefined;\n\n const manifestPath = path.join(packageRoot, PACKAGE_MANIFEST);\n // A relative subpath that the package does not export is still loadable by\n // path, which is how layers point at a file inside a package (`.../index.ts`).\n const directTarget = path.join(packageRoot, subpath);\n let manifest: { exports?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as { exports?: unknown };\n } catch {\n return subpath === '.' ? extensionIndexEntry(packageRoot) : fs.existsSync(directTarget) ? directTarget : undefined;\n }\n\n const exports = manifest.exports;\n if (exports !== undefined && exports !== null) {\n const entry =\n typeof exports === 'object' && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)[subpath]\n : subpath === '.'\n ? exports\n : undefined;\n const target = selectImportTarget(entry);\n if (target) {\n const resolved = path.join(packageRoot, target);\n if (fs.existsSync(resolved)) return resolved;\n }\n }\n\n return subpath === '.' ? extensionIndexEntry(packageRoot) : fs.existsSync(directTarget) ? directTarget : undefined;\n}\n\n/** Manifest fields consulted when a local package declares no `exports`. */\nconst MAIN_FIELDS = ['module', 'main'] as const;\n\n/**\n * Returns the canonical name of a path-style package directory.\n *\n * A direct file is intentionally anonymous: treating the repository manifest\n * above it as the file's identity would collapse every local extension in that\n * repository. Only a directory with its own named manifest represents a package\n * that can replace another installed version by logical identity.\n */\nexport function localPackageName(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n try {\n if (!fs.statSync(target).isDirectory()) return undefined;\n const manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as {\n name?: unknown;\n };\n return typeof manifest.name === 'string' && manifest.name.trim() ? manifest.name.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves Pi extension entries from a local file, extension directory, or package.\n *\n * A file is taken as the extension entry as written. A package directory uses\n * its native `pi.extensions` declaration or legacy root entry. A plain directory\n * follows Pi's extension discovery convention for scripts and child `index`\n * modules. This lets unpublished extensions live in the repository, or beside\n * the global config in `~/.pi/.doom`, and still load in deterministic order.\n */\nexport function localEntries(specifier: string, baseDirectory: string): string[] | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let stats: fs.Stats;\n try {\n stats = fs.statSync(target);\n } catch {\n return undefined;\n }\n if (stats.isFile()) return [target];\n if (!stats.isDirectory()) return undefined;\n\n const manifest = readPackageManifest(target);\n const manifestEntries = manifestExtensionEntries(\n target,\n manifest,\n localPackageName(specifier, baseDirectory) ?? target,\n );\n if (manifestEntries !== undefined) return manifestEntries;\n const entry = localEntry(specifier, baseDirectory);\n return entry ? [entry] : extensionFilesAt(target);\n}\n\n/** Resolves the legacy single entry from a local package's exports, module, or main field. */\nexport function localEntry(specifier: string, baseDirectory: string): string | undefined {\n const target = path.resolve(baseDirectory, specifier);\n let isDirectory: boolean;\n try {\n const stats = fs.statSync(target);\n if (stats.isFile()) return target;\n isDirectory = stats.isDirectory();\n } catch {\n return undefined;\n }\n if (!isDirectory) return undefined;\n\n let manifest: { exports?: unknown; module?: unknown; main?: unknown };\n try {\n manifest = JSON.parse(fs.readFileSync(path.join(target, PACKAGE_MANIFEST), 'utf8')) as typeof manifest;\n } catch {\n return undefined;\n }\n\n const exports = manifest.exports;\n const rootExport =\n typeof exports === 'object' && exports !== null && !Array.isArray(exports)\n ? (exports as Record<string, unknown>)['.']\n : exports;\n const candidates = [selectImportTarget(rootExport)];\n for (const field of MAIN_FIELDS) {\n if (typeof manifest[field] === 'string') candidates.push(manifest[field]);\n }\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const resolved = path.join(target, candidate);\n if (fs.existsSync(resolved)) return resolved;\n }\n return extensionIndexEntry(target);\n}\n\n/**\n * Resolves one of this package's own extensions in src/extensions/entries.\n *\n * The file extension differs between running from source (.ts, how the shell\n * launchers invoke this) and running the build output (.mjs), so it is derived\n * from this module's own URL rather than assumed.\n */\nexport function ownEntry(name: string): string {\n const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'mjs';\n // This file sits in src/adapters/modules, so the source root is two directories up.\n const sourceRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));\n return path.join(sourceRoot, 'extensions', 'entries', `${name}.${extension}`);\n}\n\n/** Path to Pi's own CLI, which the launch command spawns. */\nexport function piCliPath(): string {\n return path.join(path.dirname(packageEntry('@earendil-works/pi-coding-agent')), 'cli.js');\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./pluginMaterializer.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`@agimon-ai/doompi-config/domains`),a=require(`@earendil-works/pi-coding-agent`);const o=`skills`,s=`.claude/skills`;let c;async function l(){return c??=import(`gpt-tokenizer`),(await c).countTokens}function u(e){let t=e.map(e=>n.default.resolve(e));return e=>{let r=n.default.resolve(e);return t.some(e=>e===r||e.startsWith(`${r}${n.default.sep}`)||r.startsWith(`${e}${n.default.sep}`))}}function d(e,t,r,i,o,s,c=`recursive`){let l=(0,a.loadSkillsFromDir)({dir:e,source:r});for(let t of l.diagnostics)s.push(`${t.path??e}: ${t.message}`);let u=n.default.resolve(e),d=l.skills.filter(e=>{let t=n.default.dirname(e.filePath);return c===`direct-children`&&n.default.dirname(t)!==u?!1:i(t)});return o.push(...d),d.map(e=>({name:e.name,description:e.description,filePath:e.filePath,baseDir:e.baseDir,group:t,owner:r,modelInvocable:!e.disableModelInvocation})).sort((e,t)=>e.name.localeCompare(t.name))}function f(e){return e.sort((e,t)=>e.owner.localeCompare(t.owner))}async function p(e){let{repoRoot:c}=e,p=u(e.activeSkillDirectories),m=[],h=[],g=[];for(let t of e.extensionSources){let e=t.directories.flatMap(e=>d(e,`extensions`,t.source,()=>!0,h,m));e.length>0&&g.push({owner:t.source,skills:e})}let _=[],v=await t.materializePluginEntries((0,i.resolvePluginEntries)(c,(0,i.listDomainNames)(c),[]));for(let e of v){let t=n.default.join(e.directory,o);if(!r.default.existsSync(t))continue;let i=n.default.basename(e.directory),a=d(t,`plugins`,i,p,h,m,e.skillDiscovery);a.length>0&&_.push({owner:i,skills:a})}let y=d(n.default.join(c,`.claude`,o),`default`,s,p,h,m),b=y.length>0?[{owner:s,skills:y}]:[],x=[{key:`extensions`,label:`extensions`,owners:f(g)},{key:`plugins`,label:`plugins`,owners:f(_)},{key:`default`,label:`default`,owners:b}],S=await l(),C=(0,a.formatSkillsForPrompt)(h),w=0;for(let e of h)try{w+=S(r.default.readFileSync(e.filePath,`utf8`))}catch(t){m.push(`${e.filePath}: ${t instanceof Error?t.message:String(t)}`)}return{groups:x,skillCount:h.length,promptTokens:C?S(C):0,bodyTokens:w,diagnostics:m}}function m(e,t){for(let n of e.groups)for(let e of n.owners){let n=e.skills.find(e=>e.name===t);if(n)return n}}exports.buildSkillCatalog=p,exports.counter=l,exports.findSkill=m;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./pluginMaterializer.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`@agimon-ai/doompi-config/domains`),a=require(`@earendil-works/pi-coding-agent`);const o=`skills`,s=`.claude/skills`;let c;async function l(){return c??=import(`gpt-tokenizer`),(await c).countTokens}function u(e){let t=e.map(e=>n.default.resolve(e));return e=>{let r=n.default.resolve(e);return t.some(e=>e===r||e.startsWith(`${r}${n.default.sep}`)||r.startsWith(`${e}${n.default.sep}`))}}function d(e,t,r,i,o,s,c=`recursive`){let l=(0,a.loadSkillsFromDir)({dir:e,source:r});for(let t of l.diagnostics)s.push(`${t.path??e}: ${t.message}`);let u=n.default.resolve(e),d=l.skills.filter(e=>{let t=n.default.dirname(e.filePath);return c===`direct-children`&&n.default.dirname(t)!==u?!1:i(t)});return o.push(...d),d.map(e=>({name:e.name,description:e.description,filePath:e.filePath,baseDir:e.baseDir,group:t,owner:r,modelInvocable:!e.disableModelInvocation})).sort((e,t)=>e.name.localeCompare(t.name))}function f(e){return e.sort((e,t)=>e.owner.localeCompare(t.owner))}function p(e,t,n){let r=new Set(t.map(e=>e.name)),i=new Map,a=[...e].sort((e,t)=>e.sourceInfo.source.localeCompare(t.sourceInfo.source)||e.name.localeCompare(t.name)||e.filePath.localeCompare(t.filePath));for(let e of a){if(r.has(e.name)){n.push(`Help ${e.sourceInfo.source} [HELP_SKILL_COLLISION]: '${e.name}' was ignored because a normal skill wins.`);continue}r.add(e.name),t.push(e);let a=e.sourceInfo.source,o=i.get(a)??[];o.push({name:e.name,description:e.description,filePath:e.filePath,baseDir:e.baseDir,group:`help`,owner:a,modelInvocable:!e.disableModelInvocation}),i.set(a,o)}return f([...i.entries()].map(([e,t])=>({owner:e,skills:t.sort((e,t)=>e.name.localeCompare(t.name))})))}async function m(e){let{repoRoot:c}=e,m=u(e.activeSkillDirectories),h=[...e.helpDiagnostics??[]],g=[],_=[];for(let t of e.extensionSources){let e=t.directories.flatMap(e=>d(e,`extensions`,t.source,()=>!0,g,h));e.length>0&&_.push({owner:t.source,skills:e})}let v=[],y=await t.materializePluginEntries((0,i.resolvePluginEntries)(c,(0,i.listDomainNames)(c),[]));for(let e of y){let t=n.default.join(e.directory,o);if(!r.default.existsSync(t))continue;let i=n.default.basename(e.directory),a=d(t,`plugins`,i,m,g,h,e.skillDiscovery);a.length>0&&v.push({owner:i,skills:a})}let b=d(n.default.join(c,`.claude`,o),`default`,s,m,g,h),x=b.length>0?[{owner:s,skills:b}]:[],S=p(e.helpSkills??[],g,h),C=[{key:`extensions`,label:`extensions`,owners:f(_)},{key:`help`,label:`Help`,owners:S},{key:`plugins`,label:`plugins`,owners:f(v)},{key:`default`,label:`default`,owners:x}],w=await l(),T=(0,a.formatSkillsForPrompt)(g),E=0;for(let e of g)try{E+=w(r.default.readFileSync(e.filePath,`utf8`))}catch(t){h.push(`${e.filePath}: ${t instanceof Error?t.message:String(t)}`)}return{groups:C,skillCount:g.length,promptTokens:T?w(T):0,bodyTokens:E,diagnostics:h}}function h(e,t){for(let n of e.groups)for(let e of n.owners){let n=e.skills.find(e=>e.name===t);if(n)return n}}exports.buildSkillCatalog=m,exports.counter=l,exports.findSkill=h;
2
2
  //# sourceMappingURL=skillCatalog.cjs.map