@agimon-ai/doompi 0.0.1-alpha.15 → 0.0.1-alpha.17

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 (193) hide show
  1. package/README.md +280 -19
  2. package/dist/adapters/compatibility/process.cjs +1 -1
  3. package/dist/adapters/compatibility/process.mjs +1 -1
  4. package/dist/adapters/compatibilityContext.cjs +1 -1
  5. package/dist/adapters/compatibilityContext.cjs.map +1 -1
  6. package/dist/adapters/compatibilityContext.d.cts.map +1 -1
  7. package/dist/adapters/compatibilityContext.d.mts.map +1 -1
  8. package/dist/adapters/compatibilityContext.mjs +1 -1
  9. package/dist/adapters/compatibilityContext.mjs.map +1 -1
  10. package/dist/adapters/composer.cjs +1 -1
  11. package/dist/adapters/composer.mjs +1 -1
  12. package/dist/adapters/dpiRunner.cjs +3 -0
  13. package/dist/adapters/dpiRunner.cjs.map +1 -0
  14. package/dist/adapters/dpiRunner.mjs +3 -0
  15. package/dist/adapters/dpiRunner.mjs.map +1 -0
  16. package/dist/adapters/dpiSettings.cjs +2 -0
  17. package/dist/adapters/dpiSettings.cjs.map +1 -0
  18. package/dist/adapters/dpiSettings.mjs +2 -0
  19. package/dist/adapters/dpiSettings.mjs.map +1 -0
  20. package/dist/adapters/harnessContext.cjs +1 -1
  21. package/dist/adapters/harnessContext.cjs.map +1 -1
  22. package/dist/adapters/harnessContext.d.cts.map +1 -1
  23. package/dist/adapters/harnessContext.d.mts.map +1 -1
  24. package/dist/adapters/harnessContext.mjs +1 -1
  25. package/dist/adapters/harnessContext.mjs.map +1 -1
  26. package/dist/adapters/helpSkills.cjs +2 -0
  27. package/dist/adapters/helpSkills.cjs.map +1 -0
  28. package/dist/adapters/helpSkills.mjs +2 -0
  29. package/dist/adapters/helpSkills.mjs.map +1 -0
  30. package/dist/adapters/matrixSwitcher.cjs +1 -1
  31. package/dist/adapters/matrixSwitcher.cjs.map +1 -1
  32. package/dist/adapters/matrixSwitcher.d.cts.map +1 -1
  33. package/dist/adapters/matrixSwitcher.d.mts.map +1 -1
  34. package/dist/adapters/matrixSwitcher.mjs +1 -1
  35. package/dist/adapters/matrixSwitcher.mjs.map +1 -1
  36. package/dist/adapters/modules/moduleResolution.cjs +1 -1
  37. package/dist/adapters/modules/moduleResolution.cjs.map +1 -1
  38. package/dist/adapters/modules/moduleResolution.d.cts +5 -4
  39. package/dist/adapters/modules/moduleResolution.d.cts.map +1 -1
  40. package/dist/adapters/modules/moduleResolution.d.mts +5 -4
  41. package/dist/adapters/modules/moduleResolution.d.mts.map +1 -1
  42. package/dist/adapters/modules/moduleResolution.mjs +1 -1
  43. package/dist/adapters/modules/moduleResolution.mjs.map +1 -1
  44. package/dist/adapters/pluginMaterializer.cjs +2 -0
  45. package/dist/adapters/pluginMaterializer.cjs.map +1 -0
  46. package/dist/adapters/pluginMaterializer.mjs +2 -0
  47. package/dist/adapters/pluginMaterializer.mjs.map +1 -0
  48. package/dist/adapters/resourceCollector.cjs +2 -2
  49. package/dist/adapters/resourceCollector.cjs.map +1 -1
  50. package/dist/adapters/resourceCollector.d.cts +3 -3
  51. package/dist/adapters/resourceCollector.d.cts.map +1 -1
  52. package/dist/adapters/resourceCollector.d.mts +3 -3
  53. package/dist/adapters/resourceCollector.d.mts.map +1 -1
  54. package/dist/adapters/resourceCollector.mjs +2 -2
  55. package/dist/adapters/resourceCollector.mjs.map +1 -1
  56. package/dist/adapters/skillCatalog.cjs +1 -1
  57. package/dist/adapters/skillCatalog.cjs.map +1 -1
  58. package/dist/adapters/skillCatalog.d.cts +6 -1
  59. package/dist/adapters/skillCatalog.d.cts.map +1 -1
  60. package/dist/adapters/skillCatalog.d.mts +6 -1
  61. package/dist/adapters/skillCatalog.d.mts.map +1 -1
  62. package/dist/adapters/skillCatalog.mjs +1 -1
  63. package/dist/adapters/skillCatalog.mjs.map +1 -1
  64. package/dist/adapters/startupPrecompiler.cjs.map +1 -1
  65. package/dist/adapters/startupPrecompiler.d.cts +1 -1
  66. package/dist/adapters/startupPrecompiler.d.mts +1 -1
  67. package/dist/adapters/startupPrecompiler.mjs.map +1 -1
  68. package/dist/adapters/syncState.cjs +1 -1
  69. package/dist/adapters/syncState.cjs.map +1 -1
  70. package/dist/adapters/syncState.d.cts +5 -2
  71. package/dist/adapters/syncState.d.cts.map +1 -1
  72. package/dist/adapters/syncState.d.mts +5 -2
  73. package/dist/adapters/syncState.d.mts.map +1 -1
  74. package/dist/adapters/syncState.mjs +1 -1
  75. package/dist/adapters/syncState.mjs.map +1 -1
  76. package/dist/adapters/syncedRuntimeBuilder.cjs +1 -1
  77. package/dist/adapters/syncedRuntimeBuilder.cjs.map +1 -1
  78. package/dist/adapters/syncedRuntimeBuilder.d.cts +1 -1
  79. package/dist/adapters/syncedRuntimeBuilder.d.mts +1 -1
  80. package/dist/adapters/syncedRuntimeBuilder.mjs +1 -1
  81. package/dist/adapters/syncedRuntimeBuilder.mjs.map +1 -1
  82. package/dist/bin/cli.cjs +1 -1
  83. package/dist/bin/cli.cjs.map +1 -1
  84. package/dist/bin/cli.mjs +1 -1
  85. package/dist/bin/cli.mjs.map +1 -1
  86. package/dist/bin/dpi.cjs +3 -0
  87. package/dist/bin/dpi.cjs.map +1 -0
  88. package/dist/bin/dpi.d.cts +1 -0
  89. package/dist/bin/dpi.d.mts +1 -0
  90. package/dist/bin/dpi.mjs +3 -0
  91. package/dist/bin/dpi.mjs.map +1 -0
  92. package/dist/commands/buildCommand.cjs +2 -2
  93. package/dist/commands/buildCommand.cjs.map +1 -1
  94. package/dist/commands/buildCommand.mjs +2 -2
  95. package/dist/commands/buildCommand.mjs.map +1 -1
  96. package/dist/commands/cli/cliApp.cjs +1 -1
  97. package/dist/commands/cli/cliApp.cjs.map +1 -1
  98. package/dist/commands/cli/cliApp.d.cts.map +1 -1
  99. package/dist/commands/cli/cliApp.d.mts.map +1 -1
  100. package/dist/commands/cli/cliApp.mjs +1 -1
  101. package/dist/commands/cli/cliApp.mjs.map +1 -1
  102. package/dist/commands/cli/help.cjs +1 -3
  103. package/dist/commands/cli/help.cjs.map +1 -1
  104. package/dist/commands/cli/help.mjs +1 -3
  105. package/dist/commands/cli/help.mjs.map +1 -1
  106. package/dist/commands/compatibilityCommand.cjs +1 -1
  107. package/dist/commands/compatibilityCommand.mjs +1 -1
  108. package/dist/commands/index.cjs +1 -1
  109. package/dist/commands/index.d.cts +2 -3
  110. package/dist/commands/index.d.mts +2 -3
  111. package/dist/commands/index.mjs +1 -1
  112. package/dist/commands/initCommand.cjs +1 -1
  113. package/dist/commands/initCommand.mjs +1 -1
  114. package/dist/commands/initPresenter.cjs +1 -1
  115. package/dist/commands/initPresenter.cjs.map +1 -1
  116. package/dist/commands/initPresenter.mjs +1 -1
  117. package/dist/commands/initPresenter.mjs.map +1 -1
  118. package/dist/commands/launchCommand.cjs +1 -1
  119. package/dist/commands/launchCommand.mjs +1 -1
  120. package/dist/commands/syncCommand.cjs +4 -4
  121. package/dist/commands/syncCommand.cjs.map +1 -1
  122. package/dist/commands/syncCommand.d.cts +11 -4
  123. package/dist/commands/syncCommand.d.cts.map +1 -1
  124. package/dist/commands/syncCommand.d.mts +11 -4
  125. package/dist/commands/syncCommand.d.mts.map +1 -1
  126. package/dist/commands/syncCommand.mjs +4 -4
  127. package/dist/commands/syncCommand.mjs.map +1 -1
  128. package/dist/commands/syncPipeline.cjs +2 -0
  129. package/dist/commands/syncPipeline.cjs.map +1 -0
  130. package/dist/commands/syncPipeline.mjs +2 -0
  131. package/dist/commands/syncPipeline.mjs.map +1 -0
  132. package/dist/entries/majorMode.cjs +1 -1
  133. package/dist/entries/majorMode.d.cts +2 -2
  134. package/dist/entries/majorMode.d.mts +2 -2
  135. package/dist/entries/majorMode.mjs +1 -1
  136. package/dist/extensions/entries/domains.cjs +1 -1
  137. package/dist/extensions/entries/domains.cjs.map +1 -1
  138. package/dist/extensions/entries/domains.d.cts +1 -1
  139. package/dist/extensions/entries/domains.d.cts.map +1 -1
  140. package/dist/extensions/entries/domains.d.mts +1 -1
  141. package/dist/extensions/entries/domains.d.mts.map +1 -1
  142. package/dist/extensions/entries/domains.mjs +1 -1
  143. package/dist/extensions/entries/domains.mjs.map +1 -1
  144. package/dist/extensions/entries/majorMode.cjs +4 -4
  145. package/dist/extensions/entries/majorMode.cjs.map +1 -1
  146. package/dist/extensions/entries/majorMode.d.cts +1 -3
  147. package/dist/extensions/entries/majorMode.d.cts.map +1 -1
  148. package/dist/extensions/entries/majorMode.d.mts +1 -3
  149. package/dist/extensions/entries/majorMode.d.mts.map +1 -1
  150. package/dist/extensions/entries/majorMode.mjs +4 -4
  151. package/dist/extensions/entries/majorMode.mjs.map +1 -1
  152. package/dist/extensions/entries/repositoryHooks.cjs +1 -1
  153. package/dist/extensions/entries/repositoryHooks.mjs +1 -1
  154. package/dist/extensions/entries/skills.cjs +3 -2
  155. package/dist/extensions/entries/skills.cjs.map +1 -1
  156. package/dist/extensions/entries/skills.d.cts.map +1 -1
  157. package/dist/extensions/entries/skills.d.mts.map +1 -1
  158. package/dist/extensions/entries/skills.mjs +3 -2
  159. package/dist/extensions/entries/skills.mjs.map +1 -1
  160. package/dist/extensions/entries/styleSystem.cjs +2 -2
  161. package/dist/extensions/entries/styleSystem.cjs.map +1 -1
  162. package/dist/extensions/entries/styleSystem.mjs +2 -2
  163. package/dist/index.cjs +1 -1
  164. package/dist/index.d.cts +2 -3
  165. package/dist/index.d.mts +2 -3
  166. package/dist/index.mjs +1 -1
  167. package/dist/pi-cache-optimizer-D9beVnnH.mjs.map +1 -1
  168. package/dist/schemas/majorModeVoiceTools.cjs +2 -0
  169. package/dist/schemas/majorModeVoiceTools.cjs.map +1 -0
  170. package/dist/schemas/majorModeVoiceTools.mjs +2 -0
  171. package/dist/schemas/majorModeVoiceTools.mjs.map +1 -0
  172. package/dist/services/config/index.d.mts +2 -2
  173. package/dist/services/extensionAssembler.cjs +1 -1
  174. package/dist/services/extensionAssembler.cjs.map +1 -1
  175. package/dist/services/extensionAssembler.d.cts +2 -2
  176. package/dist/services/extensionAssembler.d.cts.map +1 -1
  177. package/dist/services/extensionAssembler.d.mts +2 -2
  178. package/dist/services/extensionAssembler.d.mts.map +1 -1
  179. package/dist/services/extensionAssembler.mjs +1 -1
  180. package/dist/services/extensionAssembler.mjs.map +1 -1
  181. package/dist/services/index.cjs +1 -1
  182. package/dist/services/index.mjs +1 -1
  183. package/dist/services/syncState.cjs +1 -1
  184. package/dist/services/syncState.d.cts +2 -2
  185. package/dist/services/syncState.d.mts +2 -2
  186. package/dist/services/syncState.mjs +1 -1
  187. package/dist/types/interfaces/harness.d.cts +1 -1
  188. package/dist/types/interfaces/harness.d.mts +1 -1
  189. package/package.json +37 -32
  190. package/dist/commands/buildCommand.d.cts +0 -27
  191. package/dist/commands/buildCommand.d.cts.map +0 -1
  192. package/dist/commands/buildCommand.d.mts +0 -27
  193. package/dist/commands/buildCommand.d.mts.map +0 -1
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
@@ -23,23 +23,56 @@ not. Use it as-is, build your own config on top, or raid it for parts.
23
23
  ## Install
24
24
 
25
25
  ```bash
26
- npm install -g @agimon-ai/doompi @earendil-works/pi-coding-agent
26
+ npm install -g @agimon-ai/doompi
27
27
  ```
28
28
 
29
- ## Quickstart
29
+ The package pins and installs the upstream Pi version used by `dpi`.
30
+
31
+ ## Try DoomPi without replacing your Pi setup
32
+
33
+ `dpi` is the comparison runner. Use it to try DoomPi beside your current `pi` customization
34
+ before registering anything in Pi's settings:
30
35
 
31
36
  ```bash
32
- doompi init # seed ~/.pi/.doom, once per machine
33
- mkdir .doom && cp ~/.pi/.doom/*.yaml .doom/ # the repository config Doompi reads
34
- doompi --explain # what would load, and why
35
- doompi # start a session
37
+ dpi init # create this repository's .doom configuration
38
+ dpi sync # resolve and synchronize the DoomPi experiment
39
+ dpi # run the DoomPi experiment
40
+ pi # run your existing Pi setup for comparison
41
+ ```
42
+
43
+ `dpi init` creates `.doom/config.yaml`, `.doom/modes.yaml`, `.doom/domains.yaml`, and
44
+ `.doom/profiles.yaml` in the current repository. It preserves existing files unless you pass
45
+ `--force` and does not create or change `.pi/settings.json`.
46
+
47
+ `dpi sync` writes DoomPi's generated state, package alias, and theme resource, but it does
48
+ not register DoomPi in either normal Pi settings file.
49
+
50
+ For a fair comparison, `dpi` lets Pi merge the same ordinary settings from
51
+ `~/.pi/agent/settings.json` and `<repo>/.pi/settings.json`. It then overlays only these
52
+ DoomPi-owned values in memory:
53
+
54
+ ```json
55
+ {
56
+ "extensions": ["@agimon-ai/doompi", "!extensions/**"],
57
+ "themes": ["themes/doom-pi-dark.json"],
58
+ "theme": "doom-pi-dark",
59
+ "quietStartup": true
60
+ }
36
61
  ```
37
62
 
38
- `doompi init` is the one machine-wide step. It seeds `~/.pi/.doom`; copy those files into
39
- a repository when the repository needs its own agent. Commit `.doom/`. Now the config
40
- follows the code instead of living in someone's shell history.
63
+ Those four values are never written by `dpi`, including when Pi saves an unrelated option.
64
+ Every other value keeps Pi's normal global/project precedence and trust handling.
41
65
 
42
- Flags override the defaults for one session:
66
+ When you are comfortable with DoomPi and no longer need the side-by-side experiment, register
67
+ it for normal Pi:
68
+
69
+ ```bash
70
+ doompi init # seed ~/.pi/.doom and Pi integration resources
71
+ doompi sync # register DoomPi in normal Pi settings
72
+ pi # DoomPi now starts through the regular Pi command
73
+ ```
74
+
75
+ `doompi` remains available as an explicit harness when you want one-run matrix flags:
43
76
 
44
77
  ```bash
45
78
  doompi --major-mode dev --domains development
@@ -60,8 +93,9 @@ or whatever else you do. Define as many as you like; only one is active at a tim
60
93
  can switch it without leaving the session.
61
94
 
62
95
  Minor modes are switches inside that base. They start off, stack freely, and bring their
63
- own tools and instructions when turned on. Doompi ships five:
96
+ own tools and instructions when turned on. Doompi ships six:
64
97
 
98
+ - **Help mode** — expose package-owned guidance only while you need it.
65
99
  - **Plan mode** — make the repository read-only while you agree on an approach.
66
100
  - **Loop mode** — run a prompt now, then run it again on a schedule.
67
101
  - **Goal mode** — keep one objective in view until it is done or dismissed.
@@ -73,6 +107,31 @@ own tools and instructions when turned on. Doompi ships five:
73
107
  A domain is a named group of Pi plugins. It carries the skills and MCP servers for one
74
108
  kind of work, and `/domains` switches it while the session is running.
75
109
 
110
+ Plugins are catalogued once and domains refer to their names. A configured root may be a
111
+ Codex-compatible marketplace or a folder whose direct children are plugins, so a repository
112
+ with many plugins does not need one entry per directory:
113
+
114
+ ```yaml
115
+ plugins:
116
+ roots: [plugins]
117
+ entries:
118
+ remote-review:
119
+ source: url
120
+ url: https://github.com/acme/review-plugin.git
121
+ ref: v1.2.0
122
+
123
+ domains:
124
+ development:
125
+ description: Implementation and code-review tools.
126
+ plugins: [pi-development, remote-review]
127
+ ```
128
+
129
+ DoomPi also checks personal and repository Codex marketplace layouts. Marketplace IDs use
130
+ `plugin@marketplace`. Remote Git and npm sources are downloaded once into the persistent
131
+ `~/.pi/.doom/plugin-cache` directory. Cache entries are reused until their source descriptor
132
+ changes; use a Git SHA or exact npm version for reproducible installs. Home and repository
133
+ catalogs merge, and repository names replace matching home names.
134
+
76
135
  A blog is not one task. Research it, draft it, make the assets, then review it. Turn on the
77
136
  `visual` domain while making assets; the other three steps have no reason to carry it.
78
137
 
@@ -81,6 +140,25 @@ A blog is not one task. Research it, draft it, make the assets, then review it.
81
140
  An LLM has no house style until you give it one. A profile can supply a narrative, brand
82
141
  rules, or a different voice. It is optional; no profile is a perfectly good profile.
83
142
 
143
+ Profile roots remove the need to list every persona folder. A root may itself contain the
144
+ persona files, or its direct-child folders become profiles named after those folders. DoomPi
145
+ recognizes `profile.md`, `SOUL.md`, and `AGENTS.md` and never searches deeper directories.
146
+
147
+ ```yaml
148
+ profiles:
149
+ roots: [agents/acme]
150
+ entries:
151
+ editor:
152
+ persona: agents/special/editor
153
+ env:
154
+ EDITOR_MODE: strict
155
+ ```
156
+
157
+ Roots from the home and repository files accumulate relative to their declaring config.
158
+ Repository discoveries replace same-named home discoveries. Explicit entries override
159
+ discovery and can add string environment defaults; repository entries replace matching home
160
+ entries. Select one at launch with `--profile editor` or switch with `/profile`.
161
+
84
162
  ## What this buys you
85
163
 
86
164
  Every tool schema and skill name competes for the same context. Loading less has two
@@ -100,7 +178,7 @@ choices, then press the next key.
100
178
 
101
179
  When the keyboard is the wrong tool, autonomous Voice mode keeps the conversation going.
102
180
  You can talk to the agent while doing the chores instead of carrying a laptop around the
103
- house.
181
+ house, and the primary agent can speak its own opening, milestone, and final updates.
104
182
 
105
183
  ### Autopilot
106
184
 
@@ -155,10 +233,11 @@ them one at a time.
155
233
 
156
234
  ### Configuration and composition
157
235
 
158
- `@agimon-ai/doompi` is both an extension and the command-line config compiler. The
159
- `doompi init` command writes the config; `doompi sync` resolves every major mode and
160
- domain into a distribution Pi can load quickly. A large major mode with 15 extensions
161
- adds only 400 ms of code startup time.
236
+ `@agimon-ai/doompi` is both an extension and the command-line config compiler. `dpi init`
237
+ creates repository config for an isolated experiment, while `doompi init` creates the personal
238
+ config and registers the permanent Pi integration. The sync commands resolve every major mode
239
+ and domain into a distribution Pi can load quickly. A large major mode with 15 extensions adds
240
+ only 400 ms of code startup time.
162
241
 
163
242
  ### Leader key
164
243
 
@@ -192,6 +271,15 @@ Ordinary compaction waits for one summary to save an overgrown session.
192
271
  The work runs off-thread. Each checkpoint carries the live plan, task graph, team state,
193
272
  and user request with it, so coordination does not have to be guessed back out of prose.
194
273
 
274
+ ### Help mode
275
+
276
+ `@agimon-ai/doompi-help` keeps package guidance out of the default prompt. A fresh parent
277
+ session performs no Help retrieval and exposes no Help skills. Use `SPC h e`, or the existing
278
+ `minor_mode` client in headless sessions, to activate the package indexes; use the same action
279
+ to deactivate them before the next interaction. The initial contributors expose
280
+ `doompi-help`, `workflow-help`, and `doompi-config-help`. Child sessions never assemble the
281
+ Help runtime.
282
+
195
283
  ### MCP
196
284
 
197
285
  `@agimon-ai/doompi-mcp` is the gate between a session and its servers. It reads `.mcp.json`
@@ -243,5 +331,178 @@ explicit handoffs rather than one long conversation.
243
331
  ### Voice mode
244
332
 
245
333
  `@agimon-ai/doompi-voice` records and transcribes speech locally; audio stays on the
246
- machine. Use `SPC v v` for one recording or `SPC v a` to toggle autonomous capture. It
247
- replaces the keyboard without replacing the work already in progress.
334
+ machine. `SPC v v` is one-shot manual dictation and never enables Voice tools. `SPC v a`
335
+ toggles autonomous capture; only its exact-active TUI session receives the two Voice
336
+ façades plus the standalone `narrate` tool.
337
+
338
+ While `narrate` is available, the primary agent calls it before every user-facing final
339
+ response. One concise spoken answer is enough for a short conversation or clarification;
340
+ longer work also gets an opening and meaningful milestone calls. Each ready-to-speak
341
+ utterance is limited to 4,096 characters, waits for physical playback, and returns
342
+ `completed`, `interrupted`, `superseded`, or `failed`.
343
+
344
+ If the agent never attempts `narrate` during a run, exact-active Voice speaks one sanitized
345
+ turn-end fallback rather than leaving the final response silent. Finals of at most 320
346
+ characters use deterministic speech; longer finals use the configured
347
+ `voice.autoCapture.model` for one bounded summary, with deterministic degradation on
348
+ failure or timeout. Any `narrate` attempt suppresses this safety net, so it cannot duplicate
349
+ or retry direct speech. Voice does not generate automatic intent, plan, milestone, or tool
350
+ progress narration. External task, workflow, and user-feedback narration remains
351
+ available, and the same model continues to provide bounded command correction.
352
+
353
+ ## Configuration
354
+
355
+ Doompi reads four configuration files:
356
+
357
+ - `config.yaml` defines runtime settings such as trust, editor, planning, and voice behavior.
358
+ - `modes.yaml` defines extension layers and major modes.
359
+ - `domains.yaml` catalogs plugins and sets session access.
360
+ - `profiles.yaml` supplies persona files and environment defaults.
361
+
362
+ Each matrix file has two optional layers: personal defaults in `~/.pi/.doom/` and repository
363
+ overrides in `<repository>/.doom/`. Doompi loads both. Unique named entries from either layer
364
+ remain available; a same-named repository entry replaces the complete personal entry. Plugin
365
+ and profile roots from both layers are retained. Relative paths in personal config resolve
366
+ from `~/.pi/.doom/`; relative paths in repository config resolve from the repository root.
367
+
368
+ ### `modes.yaml`: choose behavior
369
+
370
+ A layer is an ordered bundle of extension packages and hook groups. A major mode names the
371
+ layers that should run together. Packages may be bare strings, or mappings when the package
372
+ accepts configuration:
373
+
374
+ ```yaml
375
+ layers:
376
+ team:
377
+ packages:
378
+ - name: '@agimon-ai/doompi-team'
379
+ config:
380
+ models:
381
+ - model: provider/model-id
382
+ thinking: high
383
+ review:
384
+ packages:
385
+ - '@scope/review-extension'
386
+
387
+ defaultMajorMode: copilot
388
+ majorMode:
389
+ minimal:
390
+ description: Lean sessions with delegation and little else.
391
+ layers: [team]
392
+ copilot:
393
+ description: General coding with delegation and review tools.
394
+ layers: [team, review]
395
+ ```
396
+
397
+ Order matters: Doompi assembles layers and their packages from left to right. Put settings
398
+ under the package that consumes them; a layer is composition, not a mystery bag of shared
399
+ configuration. Home and repository `layers` and `majorMode` records merge by name, with the
400
+ repository definition winning a collision.
401
+
402
+ Choose a mode with `--major-mode copilot`, switch it with `/mode`, or change
403
+ `defaultMajorMode` when one mode should be the ordinary starting point.
404
+
405
+ ### `domains.yaml`: choose content and access
406
+
407
+ Plugins are catalogued once, then domains refer to their names. A root can be a marketplace,
408
+ a single plugin, or a container whose direct-child folders are plugins. Discovery is
409
+ intentionally nonrecursive: a tool buried five directories down should not load by accident.
410
+
411
+ ```yaml
412
+ defaultDomains: [development]
413
+
414
+ plugins:
415
+ roots: [plugins]
416
+ entries:
417
+ remote-review:
418
+ source: url
419
+ url: https://github.com/acme/review-plugin.git
420
+ ref: v1.2.0
421
+ published-research:
422
+ source: npm
423
+ package: '@acme/research-plugin'
424
+ version: 1.4.0
425
+
426
+ domains:
427
+ development:
428
+ description: Repository implementation tools.
429
+ plugins: [coding-tools]
430
+ review:
431
+ description: Focused review skills with a narrow MCP boundary.
432
+ plugins:
433
+ - name: remote-review
434
+ skills: [typescript]
435
+ agents: [reviewer]
436
+ hooks: false
437
+ mcp: true
438
+ mcp:
439
+ servers: [filesystem]
440
+ proxy: [github]
441
+
442
+ aliases:
443
+ work: [development, review]
444
+ ```
445
+
446
+ Here, `coding-tools` is discovered from `plugins/coding-tools`; its manifest name, or its
447
+ folder name when no manifest name exists, becomes the catalog ID. Local roots and entries
448
+ resolve beside the declaring file. Git and npm entries are cached in
449
+ `~/.pi/.doom/plugin-cache`; pin a Git SHA or exact package version when reproducibility
450
+ matters. Domains may load an entire plugin or select only its skills, agents, hooks, and MCP
451
+ configuration. The optional `mcp` mapping is an allowlist, not a request to start every server
452
+ in the repository.
453
+
454
+ Select one or more domains with `--domains development,review`, use an alias such as
455
+ `--domains work`, or switch them with `/domains`. `--no-domains` is useful when the right
456
+ amount of repository context is none.
457
+
458
+ ### `profiles.yaml`: choose a point of view
459
+
460
+ A profile directory becomes discoverable when it directly contains `profile.md`, `SOUL.md`,
461
+ or `AGENTS.md`. A root may be one profile or a container of direct-child profiles. The folder
462
+ name becomes the profile name; Doompi concatenates those three files in that order.
463
+
464
+ ```yaml
465
+ profiles:
466
+ roots: [personas]
467
+ entries:
468
+ release-writer:
469
+ persona: personas/release-writer
470
+ env:
471
+ BRAND: acme
472
+ TONE: concise
473
+ ```
474
+
475
+ With that config, `personas/release-writer/profile.md` is enough to discover
476
+ `release-writer`. The explicit entry is optional; use one when the profile needs another name,
477
+ an exact persona path, or string environment defaults. Explicit entries override discovered
478
+ folders. Already exported environment values win, so selecting a profile never quietly
479
+ replaces a value supplied by the caller.
480
+
481
+ Discovery never recurses. Persona paths must remain under `agents/` or a root declared in the
482
+ same file, and symlinks may not escape the persona boundary. Legacy profiles written directly
483
+ under `profiles` still load, but new configuration should use `roots` and `entries`.
484
+
485
+ Select a profile with `--profile release-writer` or switch it with `/profile`. Leaving the
486
+ catalog empty is valid; no profile remains a first-class choice.
487
+
488
+ ### Check the matrix before launch
489
+
490
+ The fastest configuration debugger is the one that does not start a model:
491
+
492
+ ```bash
493
+ doompi --major-mode copilot --domains work --profile release-writer --explain
494
+ dpi sync
495
+ doompi sync --check
496
+ ```
497
+
498
+ `--explain` prints the resolved mode, domains, profile, plugins, skills, agents, MCP boundary,
499
+ and estimated prompt cost. `dpi sync` resolves the repository configuration and synchronizes
500
+ DPI without registering it in normal Pi settings. `doompi sync --check` turns drift into a
501
+ non-zero exit code for CI. If the explanation is surprising, fix the YAML before paying a model
502
+ to be surprised with you.
503
+
504
+ ## Package release order
505
+
506
+ Publish `@agimon-ai/doompi-extension-contracts` first, then `@agimon-ai/doompi-help`, and only
507
+ then the `@agimon-ai/doompi` runtime that consumes them. Generated changelogs remain owned by
508
+ the release tooling.
@@ -1,2 +1,2 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../serialization/json.cjs`);require(`../../utils/index.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`node:os`),a=require(`node:child_process`),o=require(`node:timers/promises`),s=require(`cross-spawn`);s=e.__toESM(s,1);const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let i=(0,a.spawnSync)(e,t,{cwd:n,encoding:`utf8`,env:r});if(i.error)throw i.error;if(i.stderr&&process.stderr.write(i.stderr),i.status!==0)throw Error(`${e} exited with status ${i.status??1}`);return i.stdout.trim()}function d(e,t,n,r){let i=(0,a.spawnSync)(e,t,{cwd:n,env:r,stdio:`inherit`});if(i.error)throw i.error;if(i.status!==0)throw Error(`${e} exited with status ${i.status??1}`)}function f(e){if(!e)return 1;let t=i.constants.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=(0,s.default)(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(e){let r=t.readJson(n.default.join(e,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.default.mkdirSync(n.default.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.default.promises.mkdir(e);try{t.writeJson(n.default.join(e,l),{pid:process.pid})}catch(t){throw await r.default.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.default.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.default.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.default.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await(0,o.setTimeout)(25)}}function y(e,t){let r=n.default.relative(e,t);return r===``||!r.startsWith(`..${n.default.sep}`)&&r!==`..`&&!n.default.isAbsolute(r)}exports.acquireDirectoryLock=v,exports.forwardSignals=p,exports.isFileSystemError=g,exports.lockOwnerIsRunning=_,exports.pathInside=y,exports.runCaptured=u,exports.runChecked=d,exports.runInteractive=h,exports.signalExitCode=f,exports.waitForExit=m;
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../serialization/json.cjs`);require(`../../utils/index.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`node:child_process`),a=require(`node:os`),o=require(`node:timers/promises`),s=require(`cross-spawn`);s=e.__toESM(s,1);const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let a=(0,i.spawnSync)(e,t,{cwd:n,encoding:`utf8`,env:r});if(a.error)throw a.error;if(a.stderr&&process.stderr.write(a.stderr),a.status!==0)throw Error(`${e} exited with status ${a.status??1}`);return a.stdout.trim()}function d(e,t,n,r){let a=(0,i.spawnSync)(e,t,{cwd:n,env:r,stdio:`inherit`});if(a.error)throw a.error;if(a.status!==0)throw Error(`${e} exited with status ${a.status??1}`)}function f(e){if(!e)return 1;let t=a.constants.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=(0,s.default)(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(e){let r=t.readJson(n.default.join(e,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.default.mkdirSync(n.default.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.default.promises.mkdir(e);try{t.writeJson(n.default.join(e,l),{pid:process.pid})}catch(t){throw await r.default.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.default.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.default.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.default.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await(0,o.setTimeout)(25)}}function y(e,t){let r=n.default.relative(e,t);return r===``||!r.startsWith(`..${n.default.sep}`)&&r!==`..`&&!n.default.isAbsolute(r)}exports.acquireDirectoryLock=v,exports.forwardSignals=p,exports.isFileSystemError=g,exports.lockOwnerIsRunning=_,exports.pathInside=y,exports.runCaptured=u,exports.runChecked=d,exports.runInteractive=h,exports.signalExitCode=f,exports.waitForExit=m;
2
2
  //# sourceMappingURL=process.cjs.map
@@ -1,2 +1,2 @@
1
- import{readJson as e,writeJson as t}from"../serialization/json.mjs";import"../../utils/index.mjs";import n from"node:path";import r from"node:fs";import{constants as i}from"node:os";import{spawnSync as a}from"node:child_process";import{setTimeout as o}from"node:timers/promises";import s from"cross-spawn";const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let i=a(e,t,{cwd:n,encoding:`utf8`,env:r});if(i.error)throw i.error;if(i.stderr&&process.stderr.write(i.stderr),i.status!==0)throw Error(`${e} exited with status ${i.status??1}`);return i.stdout.trim()}function d(e,t,n,r){let i=a(e,t,{cwd:n,env:r,stdio:`inherit`});if(i.error)throw i.error;if(i.status!==0)throw Error(`${e} exited with status ${i.status??1}`)}function f(e){if(!e)return 1;let t=i.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=s(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(t){let r=e(n.join(t,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.mkdirSync(n.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.promises.mkdir(e);try{t(n.join(e,l),{pid:process.pid})}catch(t){throw await r.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await o(25)}}function y(e,t){let r=n.relative(e,t);return r===``||!r.startsWith(`..${n.sep}`)&&r!==`..`&&!n.isAbsolute(r)}export{v as acquireDirectoryLock,p as forwardSignals,g as isFileSystemError,_ as lockOwnerIsRunning,y as pathInside,u as runCaptured,d as runChecked,h as runInteractive,f as signalExitCode,m as waitForExit};
1
+ import{readJson as e,writeJson as t}from"../serialization/json.mjs";import"../../utils/index.mjs";import n from"node:path";import r from"node:fs";import{spawnSync as i}from"node:child_process";import{constants as a}from"node:os";import{setTimeout as o}from"node:timers/promises";import s from"cross-spawn";const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let a=i(e,t,{cwd:n,encoding:`utf8`,env:r});if(a.error)throw a.error;if(a.stderr&&process.stderr.write(a.stderr),a.status!==0)throw Error(`${e} exited with status ${a.status??1}`);return a.stdout.trim()}function d(e,t,n,r){let a=i(e,t,{cwd:n,env:r,stdio:`inherit`});if(a.error)throw a.error;if(a.status!==0)throw Error(`${e} exited with status ${a.status??1}`)}function f(e){if(!e)return 1;let t=a.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=s(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(t){let r=e(n.join(t,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.mkdirSync(n.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.promises.mkdir(e);try{t(n.join(e,l),{pid:process.pid})}catch(t){throw await r.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await o(25)}}function y(e,t){let r=n.relative(e,t);return r===``||!r.startsWith(`..${n.sep}`)&&r!==`..`&&!n.isAbsolute(r)}export{v as acquireDirectoryLock,p as forwardSignals,g as isFileSystemError,_ as lockOwnerIsRunning,y as pathInside,u as runCaptured,d as runChecked,h as runInteractive,f as signalExitCode,m as waitForExit};
2
2
  //# sourceMappingURL=process.mjs.map
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`);require(`../services/config/index.cjs`);const t=require(`./mcpFilter.cjs`),n=require(`./resourceCollector.cjs`);let r=require(`node:path`);r=e.__toESM(r,1);let i=require(`node:fs`);i=e.__toESM(i,1);let a=require(`node:os`);a=e.__toESM(a,1);let o=require(`@agimon-ai/doompi-config/majorModes`),s=require(`@agimon-ai/doompi-config/profiles`),c=require(`@agimon-ai/doompi-config/domains`),l=require(`@agimon-ai/doompi-config/harnessState`);const u=`.mcp.json`;function d(e,t){let n=[r.default.join(e,u)];for(let e of t){if(e.mcp===!1)continue;let t=r.default.join(e.directory,u);i.default.existsSync(t)&&n.push(t)}return n}function f(e,n){let i=(e.mcpServers??{})[t.PROXY_SERVER_NAME],a=Array.isArray(i?.args)?i.args.map(String):[],o=a.indexOf(`--config`),s=o===-1?void 0:a[o+1];return s?r.default.resolve(n,s):r.default.join(n,`mcp-config.yaml`)}async function p(e,a,o,s){let c=await t.applyMcpAllowlist(n.mergeMcpConfigs(d(e,a)),o,e,s),l=r.default.join(s,`mcp.json`);return await i.default.promises.writeFile(l,`${JSON.stringify(c,null,2)}\n`,{mode:384}),{mcpConfigPath:l,proxyConfigPath:f(c,e)}}async function m(e){let n=(0,o.loadMajorModesConfig)(e.repoRoot),u=(0,o.resolveLayers)(n,e.majorMode),d=(0,o.layerHookGroups)(n,u),f=await i.default.promises.mkdtemp(r.default.join(a.default.tmpdir(),`doom-pi-compat-`));await i.default.promises.chmod(f,448);try{let n=e.profile?(0,s.resolveProfile)(e.repoRoot,e.profile):void 0,a=(0,c.resolvePluginEntries)(e.repoRoot,e.domains,[]),o=t.resolveMcpAllowlist(e.repoRoot,e.domains),m=await p(e.repoRoot,a,o,f),h={...process.env};h.NX_DAEMON??=`false`;let g=(0,s.applyProfileEnvironment)(h,n?.env??{}),_=n?.persona?(0,s.buildPersonaPrompt)(n.personaRoot,n.persona):void 0,v;return _&&(v=r.default.join(f,`persona.md`),await i.default.promises.writeFile(v,`${_}\n`,{mode:384})),(0,l.projectHarnessEnvironment)({root:e.repoRoot,majorMode:e.majorMode,temporaryDirectory:f,domains:e.domains,layers:u,profile:n?.name,profileEnvironment:g,hookGroups:d,mcpConfigPath:m.mcpConfigPath,personaFile:v,additionalDirectories:e.additionalDirectories,hooks:!0},h),h.DOOMPI_ADDITIONAL_DIRS=e.additionalDirectories.join(r.default.delimiter),h.CLAUDE_PROJECT_DIR=e.repoRoot,h.CODEX_REPO_ROOT=e.repoRoot,h.AGY_REPO_ROOT=e.repoRoot,h.ORIGINAL_REPO_PATH||=e.repoRoot,{options:e,environment:h,plugins:a,profile:n,personaFile:v,mcpAllowlist:o,mcpConfigPath:m.mcpConfigPath,proxyConfigPath:m.proxyConfigPath,selectedLayers:u,hookGroups:d,sharedSkills:(0,c.resolveSharedSkills)(e.repoRoot,e.domains),cleanup:()=>i.default.promises.rm(f,{recursive:!0,force:!0})}}catch(e){throw await i.default.promises.rm(f,{recursive:!0,force:!0}),e}}exports.buildCompatibilityContext=m;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`);require(`../services/config/index.cjs`);const t=require(`./mcpFilter.cjs`),n=require(`./pluginMaterializer.cjs`),r=require(`./resourceCollector.cjs`);let i=require(`node:path`);i=e.__toESM(i,1);let a=require(`node:fs`);a=e.__toESM(a,1);let o=require(`node:os`);o=e.__toESM(o,1);let s=require(`@agimon-ai/doompi-config/majorModes`),c=require(`@agimon-ai/doompi-config/profiles`),l=require(`@agimon-ai/doompi-config/domains`),u=require(`@agimon-ai/doompi-config/harnessState`);const d=`.mcp.json`;function f(e,t){let n=[i.default.join(e,d)];for(let e of t){if(e.mcp===!1)continue;let t=i.default.join(e.directory,d);a.default.existsSync(t)&&n.push(t)}return n}function p(e,n){let r=(e.mcpServers??{})[t.PROXY_SERVER_NAME],a=Array.isArray(r?.args)?r.args.map(String):[],o=a.indexOf(`--config`),s=o===-1?void 0:a[o+1];return s?i.default.resolve(n,s):i.default.join(n,`mcp-config.yaml`)}async function m(e,n,o,s){let c=await t.applyMcpAllowlist(r.mergeMcpConfigs(f(e,n)),o,e,s),l=i.default.join(s,`mcp.json`);return await a.default.promises.writeFile(l,`${JSON.stringify(c,null,2)}\n`,{mode:384}),{mcpConfigPath:l,proxyConfigPath:p(c,e)}}async function h(e){let r=(0,s.loadMajorModesConfig)(e.repoRoot),d=(0,s.resolveLayers)(r,e.majorMode),f=(0,s.layerHookGroups)(r,d),p=await a.default.promises.mkdtemp(i.default.join(o.default.tmpdir(),`doom-pi-compat-`));await a.default.promises.chmod(p,448);try{let r=e.profile?(0,c.resolveProfile)(e.repoRoot,e.profile):void 0,o=await n.materializePluginEntries((0,l.resolvePluginEntries)(e.repoRoot,e.domains,[])),s=t.resolveMcpAllowlist(e.repoRoot,e.domains),h=await m(e.repoRoot,o,s,p),g={...process.env};g.NX_DAEMON??=`false`;let _=(0,c.applyProfileEnvironment)(g,r?.env??{}),v=r?.persona?(0,c.buildPersonaPrompt)(r.personaRoot,r.persona):void 0,y;return v&&(y=i.default.join(p,`persona.md`),await a.default.promises.writeFile(y,`${v}\n`,{mode:384})),(0,u.projectHarnessEnvironment)({root:e.repoRoot,majorMode:e.majorMode,temporaryDirectory:p,domains:e.domains,layers:d,profile:r?.name,profileEnvironment:_,hookGroups:f,mcpConfigPath:h.mcpConfigPath,personaFile:y,additionalDirectories:e.additionalDirectories,hooks:!0},g),g.DOOMPI_ADDITIONAL_DIRS=e.additionalDirectories.join(i.default.delimiter),g.CLAUDE_PROJECT_DIR=e.repoRoot,g.CODEX_REPO_ROOT=e.repoRoot,g.AGY_REPO_ROOT=e.repoRoot,g.ORIGINAL_REPO_PATH||=e.repoRoot,{options:e,environment:g,plugins:o,profile:r,personaFile:y,mcpAllowlist:s,mcpConfigPath:h.mcpConfigPath,proxyConfigPath:h.proxyConfigPath,selectedLayers:d,hookGroups:f,sharedSkills:(0,l.resolveSharedSkills)(e.repoRoot,e.domains),cleanup:()=>a.default.promises.rm(p,{recursive:!0,force:!0})}}catch(e){throw await a.default.promises.rm(p,{recursive:!0,force:!0}),e}}exports.buildCompatibilityContext=h;
2
2
  //# sourceMappingURL=compatibilityContext.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"compatibilityContext.cjs","names":["path","fs","PROXY_SERVER_NAME","applyMcpAllowlist","mergeMcpConfigs","os","resolveMcpAllowlist"],"sources":["../../src/adapters/compatibilityContext.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { CompatibilityOptions } from '../types/interfaces/index.ts';\nimport {\n type AgentProfile,\n applyProfileEnvironment,\n buildPersonaPrompt,\n type DomainMcpAllowlist,\n layerHookGroups,\n loadMajorModesConfig,\n type PluginEntry,\n projectHarnessEnvironment,\n resolveLayers,\n resolvePluginEntries,\n resolveProfile,\n resolveSharedSkills,\n} from '../services/config/index.ts';\nimport { applyMcpAllowlist, PROXY_SERVER_NAME, resolveMcpAllowlist } from './mcpFilter.ts';\nimport { mergeMcpConfigs } from './resourceCollector.ts';\n\ntype JsonObject = Record<string, unknown>;\n\nconst MCP_CONFIG_FILENAME = '.mcp.json';\nconst GENERATED_MCP_CONFIG_FILENAME = 'mcp.json';\nconst PROXY_CONFIG_FILENAME = 'mcp-config.yaml';\nconst PERSONA_FILENAME = 'persona.md';\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst CONFIG_OPTION = '--config';\nconst TEMPORARY_DIRECTORY_PREFIX = 'doom-pi-compat-';\nconst ADDITIONAL_DIRS_ENV = 'DOOMPI_ADDITIONAL_DIRS';\nconst CLAUDE_PROJECT_DIR_ENV = 'CLAUDE_PROJECT_DIR';\nconst CODEX_REPO_ROOT_ENV = 'CODEX_REPO_ROOT';\nconst AGY_REPO_ROOT_ENV = 'AGY_REPO_ROOT';\nconst ORIGINAL_REPO_PATH_ENV = 'ORIGINAL_REPO_PATH';\n\nexport interface CompatibilityContext {\n options: CompatibilityOptions;\n environment: NodeJS.ProcessEnv;\n plugins: PluginEntry[];\n profile?: AgentProfile;\n personaFile?: string;\n mcpAllowlist?: DomainMcpAllowlist;\n mcpConfigPath: string;\n proxyConfigPath: string;\n selectedLayers: string[];\n hookGroups: string[];\n sharedSkills: boolean;\n cleanup(): Promise<void>;\n}\n\nfunction pluginMcpPaths(repoRoot: string, plugins: PluginEntry[]): string[] {\n const paths = [path.join(repoRoot, MCP_CONFIG_FILENAME)];\n for (const plugin of plugins) {\n if (plugin.mcp === false) continue;\n const configPath = path.join(plugin.directory, MCP_CONFIG_FILENAME);\n if (fs.existsSync(configPath)) paths.push(configPath);\n }\n return paths;\n}\n\nfunction resolveProxyConfigPath(config: JsonObject, repoRoot: string): string {\n const servers = (config.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n const args = Array.isArray(proxy?.args) ? proxy.args.map(String) : [];\n const configIndex = args.indexOf(CONFIG_OPTION);\n const selected = configIndex === -1 ? undefined : args[configIndex + 1];\n return selected ? path.resolve(repoRoot, selected) : path.join(repoRoot, PROXY_CONFIG_FILENAME);\n}\n\nasync function writeCompatibilityMcpConfig(\n repoRoot: string,\n plugins: PluginEntry[],\n allowlist: DomainMcpAllowlist | undefined,\n temporaryDirectory: string,\n): Promise<{ mcpConfigPath: string; proxyConfigPath: string }> {\n const config = await applyMcpAllowlist(\n mergeMcpConfigs(pluginMcpPaths(repoRoot, plugins)),\n allowlist,\n repoRoot,\n temporaryDirectory,\n );\n const mcpConfigPath = path.join(temporaryDirectory, GENERATED_MCP_CONFIG_FILENAME);\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n return { mcpConfigPath, proxyConfigPath: resolveProxyConfigPath(config, repoRoot) };\n}\n\n/** Resolves only the resources shared by Pi and compatibility frontends. */\nexport async function buildCompatibilityContext(options: CompatibilityOptions): Promise<CompatibilityContext> {\n const majorModesConfig = loadMajorModesConfig(options.repoRoot);\n const selectedLayers = resolveLayers(majorModesConfig, options.majorMode);\n const hookGroups = layerHookGroups(majorModesConfig, selectedLayers);\n const temporaryDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), TEMPORARY_DIRECTORY_PREFIX));\n await fs.promises.chmod(temporaryDirectory, PRIVATE_DIRECTORY_MODE);\n\n try {\n const profile = options.profile ? resolveProfile(options.repoRoot, options.profile) : undefined;\n const plugins = resolvePluginEntries(options.repoRoot, options.domains, []);\n const mcpAllowlist = resolveMcpAllowlist(options.repoRoot, options.domains);\n const mcp = await writeCompatibilityMcpConfig(options.repoRoot, plugins, mcpAllowlist, temporaryDirectory);\n const environment = { ...process.env };\n environment.NX_DAEMON ??= 'false';\n const profileEnvironment = applyProfileEnvironment(environment, profile?.env ?? {});\n const personaPrompt = profile?.persona ? buildPersonaPrompt(profile.personaRoot, profile.persona) : undefined;\n let personaFile: string | undefined;\n\n if (personaPrompt) {\n personaFile = path.join(temporaryDirectory, PERSONA_FILENAME);\n await fs.promises.writeFile(personaFile, `${personaPrompt}\\n`, { mode: PRIVATE_FILE_MODE });\n }\n\n // Projection only, with no state file: Claude, Codex and Antigravity read\n // an environment and never the store.\n projectHarnessEnvironment(\n {\n root: options.repoRoot,\n majorMode: options.majorMode,\n temporaryDirectory,\n domains: options.domains,\n layers: selectedLayers,\n profile: profile?.name,\n profileEnvironment,\n hookGroups,\n mcpConfigPath: mcp.mcpConfigPath,\n personaFile,\n additionalDirectories: options.additionalDirectories,\n hooks: true,\n },\n environment,\n );\n environment[ADDITIONAL_DIRS_ENV] = options.additionalDirectories.join(path.delimiter);\n environment[CLAUDE_PROJECT_DIR_ENV] = options.repoRoot;\n environment[CODEX_REPO_ROOT_ENV] = options.repoRoot;\n environment[AGY_REPO_ROOT_ENV] = options.repoRoot;\n environment[ORIGINAL_REPO_PATH_ENV] ||= options.repoRoot;\n\n return {\n options,\n environment,\n plugins,\n profile,\n personaFile,\n mcpAllowlist,\n mcpConfigPath: mcp.mcpConfigPath,\n proxyConfigPath: mcp.proxyConfigPath,\n selectedLayers,\n hookGroups,\n sharedSkills: resolveSharedSkills(options.repoRoot, options.domains),\n cleanup: () => fs.promises.rm(temporaryDirectory, { recursive: true, force: true }),\n };\n } catch (error) {\n await fs.promises.rm(temporaryDirectory, { recursive: true, force: true });\n throw error;\n }\n}\n"],"mappings":"0eAuBA,MAAM,EAAsB,YA6B5B,SAAS,EAAe,EAAkB,EAAkC,CAC1E,IAAM,EAAQ,CAACA,EAAAA,QAAK,KAAK,EAAU,EAAoB,CAAC,CACxD,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAI,EAAO,MAAQ,GAAO,SAC1B,IAAM,EAAaA,EAAAA,QAAK,KAAK,EAAO,UAAW,EAAoB,CAC/DC,EAAAA,QAAG,WAAW,EAAW,EAAE,EAAM,KAAK,EAAW,CAEvD,OAAO,EAGT,SAAS,EAAuB,EAAoB,EAA0B,CAE5E,IAAM,GADW,EAAO,YAAc,EAAE,EAClBC,EAAAA,mBAChB,EAAO,MAAM,QAAQ,GAAO,KAAK,CAAG,EAAM,KAAK,IAAI,OAAO,CAAG,EAAE,CAC/D,EAAc,EAAK,QAAQ,WAAc,CACzC,EAAW,IAAgB,GAAK,IAAA,GAAY,EAAK,EAAc,GACrE,OAAO,EAAWF,EAAAA,QAAK,QAAQ,EAAU,EAAS,CAAGA,EAAAA,QAAK,KAAK,EAAU,kBAAsB,CAGjG,eAAe,EACb,EACA,EACA,EACA,EAC6D,CAC7D,IAAM,EAAS,MAAMG,EAAAA,kBACnBC,EAAAA,gBAAgB,EAAe,EAAU,EAAQ,CAAC,CAClD,EACA,EACA,EACD,CACK,EAAgBJ,EAAAA,QAAK,KAAK,EAAoB,WAA8B,CAElF,OADA,MAAMC,EAAAA,QAAG,SAAS,UAAU,EAAe,GAAG,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAC,IAAK,CAAE,KAAM,IAAmB,CAAC,CACxG,CAAE,gBAAe,gBAAiB,EAAuB,EAAQ,EAAS,CAAE,CAIrF,eAAsB,EAA0B,EAA8D,CAC5G,IAAM,GAAA,EAAA,EAAA,sBAAwC,EAAQ,SAAS,CACzD,GAAA,EAAA,EAAA,eAA+B,EAAkB,EAAQ,UAAU,CACnE,GAAA,EAAA,EAAA,iBAA6B,EAAkB,EAAe,CAC9D,EAAqB,MAAMA,EAAAA,QAAG,SAAS,QAAQD,EAAAA,QAAK,KAAKK,EAAAA,QAAG,QAAQ,CAAE,kBAA2B,CAAC,CACxG,MAAMJ,EAAAA,QAAG,SAAS,MAAM,EAAoB,IAAuB,CAEnE,GAAI,CACF,IAAM,EAAU,EAAQ,SAAA,EAAA,EAAA,gBAAyB,EAAQ,SAAU,EAAQ,QAAQ,CAAG,IAAA,GAChF,GAAA,EAAA,EAAA,sBAA+B,EAAQ,SAAU,EAAQ,QAAS,EAAE,CAAC,CACrE,EAAeK,EAAAA,oBAAoB,EAAQ,SAAU,EAAQ,QAAQ,CACrE,EAAM,MAAM,EAA4B,EAAQ,SAAU,EAAS,EAAc,EAAmB,CACpG,EAAc,CAAE,GAAG,QAAQ,IAAK,CACtC,EAAY,YAAc,QAC1B,IAAM,GAAA,EAAA,EAAA,yBAA6C,EAAa,GAAS,KAAO,EAAE,CAAC,CAC7E,EAAgB,GAAS,SAAA,EAAA,EAAA,oBAA6B,EAAQ,YAAa,EAAQ,QAAQ,CAAG,IAAA,GAChG,EAgCJ,OA9BI,IACF,EAAcN,EAAAA,QAAK,KAAK,EAAoB,aAAiB,CAC7D,MAAMC,EAAAA,QAAG,SAAS,UAAU,EAAa,GAAG,EAAc,IAAK,CAAE,KAAM,IAAmB,CAAC,GAK7F,EAAA,EAAA,2BACE,CACE,KAAM,EAAQ,SACd,UAAW,EAAQ,UACnB,qBACA,QAAS,EAAQ,QACjB,OAAQ,EACR,QAAS,GAAS,KAClB,qBACA,aACA,cAAe,EAAI,cACnB,cACA,sBAAuB,EAAQ,sBAC/B,MAAO,GACR,CACD,EACD,CACD,EAAY,uBAAuB,EAAQ,sBAAsB,KAAKD,EAAAA,QAAK,UAAU,CACrF,EAAY,mBAA0B,EAAQ,SAC9C,EAAY,gBAAuB,EAAQ,SAC3C,EAAY,cAAqB,EAAQ,SACzC,EAAY,qBAA4B,EAAQ,SAEzC,CACL,UACA,cACA,UACA,UACA,cACA,eACA,cAAe,EAAI,cACnB,gBAAiB,EAAI,gBACrB,iBACA,aACA,cAAA,EAAA,EAAA,qBAAkC,EAAQ,SAAU,EAAQ,QAAQ,CACpE,YAAeC,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CACpF,OACM,EAAO,CAEd,MADA,MAAMA,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CACpE"}
1
+ {"version":3,"file":"compatibilityContext.cjs","names":["path","fs","PROXY_SERVER_NAME","applyMcpAllowlist","mergeMcpConfigs","os","materializePluginEntries","resolveMcpAllowlist"],"sources":["../../src/adapters/compatibilityContext.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {\n type AgentProfile,\n applyProfileEnvironment,\n buildPersonaPrompt,\n type DomainMcpAllowlist,\n layerHookGroups,\n loadMajorModesConfig,\n type PluginEntry,\n projectHarnessEnvironment,\n resolveLayers,\n resolvePluginEntries,\n resolveProfile,\n resolveSharedSkills,\n} from '../services/config/index.ts';\nimport type { CompatibilityOptions } from '../types/interfaces/index.ts';\nimport { applyMcpAllowlist, PROXY_SERVER_NAME, resolveMcpAllowlist } from './mcpFilter.ts';\nimport { materializePluginEntries } from './pluginMaterializer.ts';\nimport { mergeMcpConfigs } from './resourceCollector.ts';\n\ntype JsonObject = Record<string, unknown>;\n\nconst MCP_CONFIG_FILENAME = '.mcp.json';\nconst GENERATED_MCP_CONFIG_FILENAME = 'mcp.json';\nconst PROXY_CONFIG_FILENAME = 'mcp-config.yaml';\nconst PERSONA_FILENAME = 'persona.md';\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst CONFIG_OPTION = '--config';\nconst TEMPORARY_DIRECTORY_PREFIX = 'doom-pi-compat-';\nconst ADDITIONAL_DIRS_ENV = 'DOOMPI_ADDITIONAL_DIRS';\nconst CLAUDE_PROJECT_DIR_ENV = 'CLAUDE_PROJECT_DIR';\nconst CODEX_REPO_ROOT_ENV = 'CODEX_REPO_ROOT';\nconst AGY_REPO_ROOT_ENV = 'AGY_REPO_ROOT';\nconst ORIGINAL_REPO_PATH_ENV = 'ORIGINAL_REPO_PATH';\n\nexport interface CompatibilityContext {\n options: CompatibilityOptions;\n environment: NodeJS.ProcessEnv;\n plugins: PluginEntry[];\n profile?: AgentProfile;\n personaFile?: string;\n mcpAllowlist?: DomainMcpAllowlist;\n mcpConfigPath: string;\n proxyConfigPath: string;\n selectedLayers: string[];\n hookGroups: string[];\n sharedSkills: boolean;\n cleanup(): Promise<void>;\n}\n\nfunction pluginMcpPaths(repoRoot: string, plugins: PluginEntry[]): string[] {\n const paths = [path.join(repoRoot, MCP_CONFIG_FILENAME)];\n for (const plugin of plugins) {\n if (plugin.mcp === false) continue;\n const configPath = path.join(plugin.directory, MCP_CONFIG_FILENAME);\n if (fs.existsSync(configPath)) paths.push(configPath);\n }\n return paths;\n}\n\nfunction resolveProxyConfigPath(config: JsonObject, repoRoot: string): string {\n const servers = (config.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n const args = Array.isArray(proxy?.args) ? proxy.args.map(String) : [];\n const configIndex = args.indexOf(CONFIG_OPTION);\n const selected = configIndex === -1 ? undefined : args[configIndex + 1];\n return selected ? path.resolve(repoRoot, selected) : path.join(repoRoot, PROXY_CONFIG_FILENAME);\n}\n\nasync function writeCompatibilityMcpConfig(\n repoRoot: string,\n plugins: PluginEntry[],\n allowlist: DomainMcpAllowlist | undefined,\n temporaryDirectory: string,\n): Promise<{ mcpConfigPath: string; proxyConfigPath: string }> {\n const config = await applyMcpAllowlist(\n mergeMcpConfigs(pluginMcpPaths(repoRoot, plugins)),\n allowlist,\n repoRoot,\n temporaryDirectory,\n );\n const mcpConfigPath = path.join(temporaryDirectory, GENERATED_MCP_CONFIG_FILENAME);\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n return { mcpConfigPath, proxyConfigPath: resolveProxyConfigPath(config, repoRoot) };\n}\n\n/** Resolves only the resources shared by Pi and compatibility frontends. */\nexport async function buildCompatibilityContext(options: CompatibilityOptions): Promise<CompatibilityContext> {\n const majorModesConfig = loadMajorModesConfig(options.repoRoot);\n const selectedLayers = resolveLayers(majorModesConfig, options.majorMode);\n const hookGroups = layerHookGroups(majorModesConfig, selectedLayers);\n const temporaryDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), TEMPORARY_DIRECTORY_PREFIX));\n await fs.promises.chmod(temporaryDirectory, PRIVATE_DIRECTORY_MODE);\n\n try {\n const profile = options.profile ? resolveProfile(options.repoRoot, options.profile) : undefined;\n const plugins = await materializePluginEntries(resolvePluginEntries(options.repoRoot, options.domains, []));\n const mcpAllowlist = resolveMcpAllowlist(options.repoRoot, options.domains);\n const mcp = await writeCompatibilityMcpConfig(options.repoRoot, plugins, mcpAllowlist, temporaryDirectory);\n const environment = { ...process.env };\n environment.NX_DAEMON ??= 'false';\n const profileEnvironment = applyProfileEnvironment(environment, profile?.env ?? {});\n const personaPrompt = profile?.persona ? buildPersonaPrompt(profile.personaRoot, profile.persona) : undefined;\n let personaFile: string | undefined;\n\n if (personaPrompt) {\n personaFile = path.join(temporaryDirectory, PERSONA_FILENAME);\n await fs.promises.writeFile(personaFile, `${personaPrompt}\\n`, { mode: PRIVATE_FILE_MODE });\n }\n\n // Projection only, with no state file: Claude, Codex and Antigravity read\n // an environment and never the store.\n projectHarnessEnvironment(\n {\n root: options.repoRoot,\n majorMode: options.majorMode,\n temporaryDirectory,\n domains: options.domains,\n layers: selectedLayers,\n profile: profile?.name,\n profileEnvironment,\n hookGroups,\n mcpConfigPath: mcp.mcpConfigPath,\n personaFile,\n additionalDirectories: options.additionalDirectories,\n hooks: true,\n },\n environment,\n );\n environment[ADDITIONAL_DIRS_ENV] = options.additionalDirectories.join(path.delimiter);\n environment[CLAUDE_PROJECT_DIR_ENV] = options.repoRoot;\n environment[CODEX_REPO_ROOT_ENV] = options.repoRoot;\n environment[AGY_REPO_ROOT_ENV] = options.repoRoot;\n environment[ORIGINAL_REPO_PATH_ENV] ||= options.repoRoot;\n\n return {\n options,\n environment,\n plugins,\n profile,\n personaFile,\n mcpAllowlist,\n mcpConfigPath: mcp.mcpConfigPath,\n proxyConfigPath: mcp.proxyConfigPath,\n selectedLayers,\n hookGroups,\n sharedSkills: resolveSharedSkills(options.repoRoot, options.domains),\n cleanup: () => fs.promises.rm(temporaryDirectory, { recursive: true, force: true }),\n };\n } catch (error) {\n await fs.promises.rm(temporaryDirectory, { recursive: true, force: true });\n throw error;\n }\n}\n"],"mappings":"ghBAwBA,MAAM,EAAsB,YA6B5B,SAAS,EAAe,EAAkB,EAAkC,CAC1E,IAAM,EAAQ,CAACA,EAAAA,QAAK,KAAK,EAAU,EAAoB,CAAC,CACxD,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAI,EAAO,MAAQ,GAAO,SAC1B,IAAM,EAAaA,EAAAA,QAAK,KAAK,EAAO,UAAW,EAAoB,CAC/DC,EAAAA,QAAG,WAAW,EAAW,EAAE,EAAM,KAAK,EAAW,CAEvD,OAAO,EAGT,SAAS,EAAuB,EAAoB,EAA0B,CAE5E,IAAM,GADW,EAAO,YAAc,EAAE,EAClBC,EAAAA,mBAChB,EAAO,MAAM,QAAQ,GAAO,KAAK,CAAG,EAAM,KAAK,IAAI,OAAO,CAAG,EAAE,CAC/D,EAAc,EAAK,QAAQ,WAAc,CACzC,EAAW,IAAgB,GAAK,IAAA,GAAY,EAAK,EAAc,GACrE,OAAO,EAAWF,EAAAA,QAAK,QAAQ,EAAU,EAAS,CAAGA,EAAAA,QAAK,KAAK,EAAU,kBAAsB,CAGjG,eAAe,EACb,EACA,EACA,EACA,EAC6D,CAC7D,IAAM,EAAS,MAAMG,EAAAA,kBACnBC,EAAAA,gBAAgB,EAAe,EAAU,EAAQ,CAAC,CAClD,EACA,EACA,EACD,CACK,EAAgBJ,EAAAA,QAAK,KAAK,EAAoB,WAA8B,CAElF,OADA,MAAMC,EAAAA,QAAG,SAAS,UAAU,EAAe,GAAG,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAC,IAAK,CAAE,KAAM,IAAmB,CAAC,CACxG,CAAE,gBAAe,gBAAiB,EAAuB,EAAQ,EAAS,CAAE,CAIrF,eAAsB,EAA0B,EAA8D,CAC5G,IAAM,GAAA,EAAA,EAAA,sBAAwC,EAAQ,SAAS,CACzD,GAAA,EAAA,EAAA,eAA+B,EAAkB,EAAQ,UAAU,CACnE,GAAA,EAAA,EAAA,iBAA6B,EAAkB,EAAe,CAC9D,EAAqB,MAAMA,EAAAA,QAAG,SAAS,QAAQD,EAAAA,QAAK,KAAKK,EAAAA,QAAG,QAAQ,CAAE,kBAA2B,CAAC,CACxG,MAAMJ,EAAAA,QAAG,SAAS,MAAM,EAAoB,IAAuB,CAEnE,GAAI,CACF,IAAM,EAAU,EAAQ,SAAA,EAAA,EAAA,gBAAyB,EAAQ,SAAU,EAAQ,QAAQ,CAAG,IAAA,GAChF,EAAU,MAAMK,EAAAA,0BAAAA,EAAAA,EAAAA,sBAA8C,EAAQ,SAAU,EAAQ,QAAS,EAAE,CAAC,CAAC,CACrG,EAAeC,EAAAA,oBAAoB,EAAQ,SAAU,EAAQ,QAAQ,CACrE,EAAM,MAAM,EAA4B,EAAQ,SAAU,EAAS,EAAc,EAAmB,CACpG,EAAc,CAAE,GAAG,QAAQ,IAAK,CACtC,EAAY,YAAc,QAC1B,IAAM,GAAA,EAAA,EAAA,yBAA6C,EAAa,GAAS,KAAO,EAAE,CAAC,CAC7E,EAAgB,GAAS,SAAA,EAAA,EAAA,oBAA6B,EAAQ,YAAa,EAAQ,QAAQ,CAAG,IAAA,GAChG,EAgCJ,OA9BI,IACF,EAAcP,EAAAA,QAAK,KAAK,EAAoB,aAAiB,CAC7D,MAAMC,EAAAA,QAAG,SAAS,UAAU,EAAa,GAAG,EAAc,IAAK,CAAE,KAAM,IAAmB,CAAC,GAK7F,EAAA,EAAA,2BACE,CACE,KAAM,EAAQ,SACd,UAAW,EAAQ,UACnB,qBACA,QAAS,EAAQ,QACjB,OAAQ,EACR,QAAS,GAAS,KAClB,qBACA,aACA,cAAe,EAAI,cACnB,cACA,sBAAuB,EAAQ,sBAC/B,MAAO,GACR,CACD,EACD,CACD,EAAY,uBAAuB,EAAQ,sBAAsB,KAAKD,EAAAA,QAAK,UAAU,CACrF,EAAY,mBAA0B,EAAQ,SAC9C,EAAY,gBAAuB,EAAQ,SAC3C,EAAY,cAAqB,EAAQ,SACzC,EAAY,qBAA4B,EAAQ,SAEzC,CACL,UACA,cACA,UACA,UACA,cACA,eACA,cAAe,EAAI,cACnB,gBAAiB,EAAI,gBACrB,iBACA,aACA,cAAA,EAAA,EAAA,qBAAkC,EAAQ,SAAU,EAAQ,QAAQ,CACpE,YAAeC,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CACpF,OACM,EAAO,CAEd,MADA,MAAMA,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CACpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"compatibilityContext.d.cts","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"mappings":";;;;UAqCiB,oBAAA;EACf,OAAA,EAAS,oBAAA;EACT,WAAA,EAAa,MAAA,CAAO,UAAA;EACpB,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,YAAA;EACV,WAAA;EACA,YAAA,GAAe,kBAAA;EACf,aAAA;EACA,eAAA;EACA,cAAA;EACA,UAAA;EACA,YAAA;EACA,OAAA,IAAW,OAAA;AAAA;;iBAwCS,yBAAA,CAA0B,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,oBAAA"}
1
+ {"version":3,"file":"compatibilityContext.d.cts","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"mappings":";;;;UAsCiB,oBAAA;EACf,OAAA,EAAS,oBAAA;EACT,WAAA,EAAa,MAAA,CAAO,UAAA;EACpB,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,YAAA;EACV,WAAA;EACA,YAAA,GAAe,kBAAA;EACf,aAAA;EACA,eAAA;EACA,cAAA;EACA,UAAA;EACA,YAAA;EACA,OAAA,IAAW,OAAA;AAAA;;iBAwCS,yBAAA,CAA0B,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"compatibilityContext.d.mts","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"mappings":";;;;UAqCiB,oBAAA;EACf,OAAA,EAAS,oBAAA;EACT,WAAA,EAAa,MAAA,CAAO,UAAA;EACpB,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,YAAA;EACV,WAAA;EACA,YAAA,GAAe,kBAAA;EACf,aAAA;EACA,eAAA;EACA,cAAA;EACA,UAAA;EACA,YAAA;EACA,OAAA,IAAW,OAAA;AAAA;;iBAwCS,yBAAA,CAA0B,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,oBAAA"}
1
+ {"version":3,"file":"compatibilityContext.d.mts","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"mappings":";;;;UAsCiB,oBAAA;EACf,OAAA,EAAS,oBAAA;EACT,WAAA,EAAa,MAAA,CAAO,UAAA;EACpB,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,YAAA;EACV,WAAA;EACA,YAAA,GAAe,kBAAA;EACf,aAAA;EACA,eAAA;EACA,cAAA;EACA,UAAA;EACA,YAAA;EACA,OAAA,IAAW,OAAA;AAAA;;iBAwCS,yBAAA,CAA0B,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,oBAAA"}
@@ -1,2 +1,2 @@
1
- import{projectHarnessEnvironment as e}from"./config/harnessState.mjs";import{applyProfileEnvironment as t,buildPersonaPrompt as n,layerHookGroups as r,loadMajorModesConfig as i,resolveLayers as a,resolvePluginEntries as o,resolveProfile as s,resolveSharedSkills as c}from"../services/config/index.mjs";import{PROXY_SERVER_NAME as l,applyMcpAllowlist as u,resolveMcpAllowlist as d}from"./mcpFilter.mjs";import{mergeMcpConfigs as f}from"./resourceCollector.mjs";import p from"node:path";import m from"node:fs";import h from"node:os";const g=`.mcp.json`;function _(e,t){let n=[p.join(e,g)];for(let e of t){if(e.mcp===!1)continue;let t=p.join(e.directory,g);m.existsSync(t)&&n.push(t)}return n}function v(e,t){let n=(e.mcpServers??{})[l],r=Array.isArray(n?.args)?n.args.map(String):[],i=r.indexOf(`--config`),a=i===-1?void 0:r[i+1];return a?p.resolve(t,a):p.join(t,`mcp-config.yaml`)}async function y(e,t,n,r){let i=await u(f(_(e,t)),n,e,r),a=p.join(r,`mcp.json`);return await m.promises.writeFile(a,`${JSON.stringify(i,null,2)}\n`,{mode:384}),{mcpConfigPath:a,proxyConfigPath:v(i,e)}}async function b(l){let u=i(l.repoRoot),f=a(u,l.majorMode),g=r(u,f),_=await m.promises.mkdtemp(p.join(h.tmpdir(),`doom-pi-compat-`));await m.promises.chmod(_,448);try{let r=l.profile?s(l.repoRoot,l.profile):void 0,i=o(l.repoRoot,l.domains,[]),a=d(l.repoRoot,l.domains),u=await y(l.repoRoot,i,a,_),h={...process.env};h.NX_DAEMON??=`false`;let v=t(h,r?.env??{}),b=r?.persona?n(r.personaRoot,r.persona):void 0,x;return b&&(x=p.join(_,`persona.md`),await m.promises.writeFile(x,`${b}\n`,{mode:384})),e({root:l.repoRoot,majorMode:l.majorMode,temporaryDirectory:_,domains:l.domains,layers:f,profile:r?.name,profileEnvironment:v,hookGroups:g,mcpConfigPath:u.mcpConfigPath,personaFile:x,additionalDirectories:l.additionalDirectories,hooks:!0},h),h.DOOMPI_ADDITIONAL_DIRS=l.additionalDirectories.join(p.delimiter),h.CLAUDE_PROJECT_DIR=l.repoRoot,h.CODEX_REPO_ROOT=l.repoRoot,h.AGY_REPO_ROOT=l.repoRoot,h.ORIGINAL_REPO_PATH||=l.repoRoot,{options:l,environment:h,plugins:i,profile:r,personaFile:x,mcpAllowlist:a,mcpConfigPath:u.mcpConfigPath,proxyConfigPath:u.proxyConfigPath,selectedLayers:f,hookGroups:g,sharedSkills:c(l.repoRoot,l.domains),cleanup:()=>m.promises.rm(_,{recursive:!0,force:!0})}}catch(e){throw await m.promises.rm(_,{recursive:!0,force:!0}),e}}export{b as buildCompatibilityContext};
1
+ import{projectHarnessEnvironment as e}from"./config/harnessState.mjs";import{applyProfileEnvironment as t,buildPersonaPrompt as n,layerHookGroups as r,loadMajorModesConfig as i,resolveLayers as a,resolvePluginEntries as o,resolveProfile as s,resolveSharedSkills as c}from"../services/config/index.mjs";import{PROXY_SERVER_NAME as l,applyMcpAllowlist as u,resolveMcpAllowlist as d}from"./mcpFilter.mjs";import{materializePluginEntries as f}from"./pluginMaterializer.mjs";import{mergeMcpConfigs as p}from"./resourceCollector.mjs";import m from"node:path";import h from"node:fs";import g from"node:os";const _=`.mcp.json`;function v(e,t){let n=[m.join(e,_)];for(let e of t){if(e.mcp===!1)continue;let t=m.join(e.directory,_);h.existsSync(t)&&n.push(t)}return n}function y(e,t){let n=(e.mcpServers??{})[l],r=Array.isArray(n?.args)?n.args.map(String):[],i=r.indexOf(`--config`),a=i===-1?void 0:r[i+1];return a?m.resolve(t,a):m.join(t,`mcp-config.yaml`)}async function b(e,t,n,r){let i=await u(p(v(e,t)),n,e,r),a=m.join(r,`mcp.json`);return await h.promises.writeFile(a,`${JSON.stringify(i,null,2)}\n`,{mode:384}),{mcpConfigPath:a,proxyConfigPath:y(i,e)}}async function x(l){let u=i(l.repoRoot),p=a(u,l.majorMode),_=r(u,p),v=await h.promises.mkdtemp(m.join(g.tmpdir(),`doom-pi-compat-`));await h.promises.chmod(v,448);try{let r=l.profile?s(l.repoRoot,l.profile):void 0,i=await f(o(l.repoRoot,l.domains,[])),a=d(l.repoRoot,l.domains),u=await b(l.repoRoot,i,a,v),g={...process.env};g.NX_DAEMON??=`false`;let y=t(g,r?.env??{}),x=r?.persona?n(r.personaRoot,r.persona):void 0,S;return x&&(S=m.join(v,`persona.md`),await h.promises.writeFile(S,`${x}\n`,{mode:384})),e({root:l.repoRoot,majorMode:l.majorMode,temporaryDirectory:v,domains:l.domains,layers:p,profile:r?.name,profileEnvironment:y,hookGroups:_,mcpConfigPath:u.mcpConfigPath,personaFile:S,additionalDirectories:l.additionalDirectories,hooks:!0},g),g.DOOMPI_ADDITIONAL_DIRS=l.additionalDirectories.join(m.delimiter),g.CLAUDE_PROJECT_DIR=l.repoRoot,g.CODEX_REPO_ROOT=l.repoRoot,g.AGY_REPO_ROOT=l.repoRoot,g.ORIGINAL_REPO_PATH||=l.repoRoot,{options:l,environment:g,plugins:i,profile:r,personaFile:S,mcpAllowlist:a,mcpConfigPath:u.mcpConfigPath,proxyConfigPath:u.proxyConfigPath,selectedLayers:p,hookGroups:_,sharedSkills:c(l.repoRoot,l.domains),cleanup:()=>h.promises.rm(v,{recursive:!0,force:!0})}}catch(e){throw await h.promises.rm(v,{recursive:!0,force:!0}),e}}export{x as buildCompatibilityContext};
2
2
  //# sourceMappingURL=compatibilityContext.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"compatibilityContext.mjs","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { CompatibilityOptions } from '../types/interfaces/index.ts';\nimport {\n type AgentProfile,\n applyProfileEnvironment,\n buildPersonaPrompt,\n type DomainMcpAllowlist,\n layerHookGroups,\n loadMajorModesConfig,\n type PluginEntry,\n projectHarnessEnvironment,\n resolveLayers,\n resolvePluginEntries,\n resolveProfile,\n resolveSharedSkills,\n} from '../services/config/index.ts';\nimport { applyMcpAllowlist, PROXY_SERVER_NAME, resolveMcpAllowlist } from './mcpFilter.ts';\nimport { mergeMcpConfigs } from './resourceCollector.ts';\n\ntype JsonObject = Record<string, unknown>;\n\nconst MCP_CONFIG_FILENAME = '.mcp.json';\nconst GENERATED_MCP_CONFIG_FILENAME = 'mcp.json';\nconst PROXY_CONFIG_FILENAME = 'mcp-config.yaml';\nconst PERSONA_FILENAME = 'persona.md';\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst CONFIG_OPTION = '--config';\nconst TEMPORARY_DIRECTORY_PREFIX = 'doom-pi-compat-';\nconst ADDITIONAL_DIRS_ENV = 'DOOMPI_ADDITIONAL_DIRS';\nconst CLAUDE_PROJECT_DIR_ENV = 'CLAUDE_PROJECT_DIR';\nconst CODEX_REPO_ROOT_ENV = 'CODEX_REPO_ROOT';\nconst AGY_REPO_ROOT_ENV = 'AGY_REPO_ROOT';\nconst ORIGINAL_REPO_PATH_ENV = 'ORIGINAL_REPO_PATH';\n\nexport interface CompatibilityContext {\n options: CompatibilityOptions;\n environment: NodeJS.ProcessEnv;\n plugins: PluginEntry[];\n profile?: AgentProfile;\n personaFile?: string;\n mcpAllowlist?: DomainMcpAllowlist;\n mcpConfigPath: string;\n proxyConfigPath: string;\n selectedLayers: string[];\n hookGroups: string[];\n sharedSkills: boolean;\n cleanup(): Promise<void>;\n}\n\nfunction pluginMcpPaths(repoRoot: string, plugins: PluginEntry[]): string[] {\n const paths = [path.join(repoRoot, MCP_CONFIG_FILENAME)];\n for (const plugin of plugins) {\n if (plugin.mcp === false) continue;\n const configPath = path.join(plugin.directory, MCP_CONFIG_FILENAME);\n if (fs.existsSync(configPath)) paths.push(configPath);\n }\n return paths;\n}\n\nfunction resolveProxyConfigPath(config: JsonObject, repoRoot: string): string {\n const servers = (config.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n const args = Array.isArray(proxy?.args) ? proxy.args.map(String) : [];\n const configIndex = args.indexOf(CONFIG_OPTION);\n const selected = configIndex === -1 ? undefined : args[configIndex + 1];\n return selected ? path.resolve(repoRoot, selected) : path.join(repoRoot, PROXY_CONFIG_FILENAME);\n}\n\nasync function writeCompatibilityMcpConfig(\n repoRoot: string,\n plugins: PluginEntry[],\n allowlist: DomainMcpAllowlist | undefined,\n temporaryDirectory: string,\n): Promise<{ mcpConfigPath: string; proxyConfigPath: string }> {\n const config = await applyMcpAllowlist(\n mergeMcpConfigs(pluginMcpPaths(repoRoot, plugins)),\n allowlist,\n repoRoot,\n temporaryDirectory,\n );\n const mcpConfigPath = path.join(temporaryDirectory, GENERATED_MCP_CONFIG_FILENAME);\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n return { mcpConfigPath, proxyConfigPath: resolveProxyConfigPath(config, repoRoot) };\n}\n\n/** Resolves only the resources shared by Pi and compatibility frontends. */\nexport async function buildCompatibilityContext(options: CompatibilityOptions): Promise<CompatibilityContext> {\n const majorModesConfig = loadMajorModesConfig(options.repoRoot);\n const selectedLayers = resolveLayers(majorModesConfig, options.majorMode);\n const hookGroups = layerHookGroups(majorModesConfig, selectedLayers);\n const temporaryDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), TEMPORARY_DIRECTORY_PREFIX));\n await fs.promises.chmod(temporaryDirectory, PRIVATE_DIRECTORY_MODE);\n\n try {\n const profile = options.profile ? resolveProfile(options.repoRoot, options.profile) : undefined;\n const plugins = resolvePluginEntries(options.repoRoot, options.domains, []);\n const mcpAllowlist = resolveMcpAllowlist(options.repoRoot, options.domains);\n const mcp = await writeCompatibilityMcpConfig(options.repoRoot, plugins, mcpAllowlist, temporaryDirectory);\n const environment = { ...process.env };\n environment.NX_DAEMON ??= 'false';\n const profileEnvironment = applyProfileEnvironment(environment, profile?.env ?? {});\n const personaPrompt = profile?.persona ? buildPersonaPrompt(profile.personaRoot, profile.persona) : undefined;\n let personaFile: string | undefined;\n\n if (personaPrompt) {\n personaFile = path.join(temporaryDirectory, PERSONA_FILENAME);\n await fs.promises.writeFile(personaFile, `${personaPrompt}\\n`, { mode: PRIVATE_FILE_MODE });\n }\n\n // Projection only, with no state file: Claude, Codex and Antigravity read\n // an environment and never the store.\n projectHarnessEnvironment(\n {\n root: options.repoRoot,\n majorMode: options.majorMode,\n temporaryDirectory,\n domains: options.domains,\n layers: selectedLayers,\n profile: profile?.name,\n profileEnvironment,\n hookGroups,\n mcpConfigPath: mcp.mcpConfigPath,\n personaFile,\n additionalDirectories: options.additionalDirectories,\n hooks: true,\n },\n environment,\n );\n environment[ADDITIONAL_DIRS_ENV] = options.additionalDirectories.join(path.delimiter);\n environment[CLAUDE_PROJECT_DIR_ENV] = options.repoRoot;\n environment[CODEX_REPO_ROOT_ENV] = options.repoRoot;\n environment[AGY_REPO_ROOT_ENV] = options.repoRoot;\n environment[ORIGINAL_REPO_PATH_ENV] ||= options.repoRoot;\n\n return {\n options,\n environment,\n plugins,\n profile,\n personaFile,\n mcpAllowlist,\n mcpConfigPath: mcp.mcpConfigPath,\n proxyConfigPath: mcp.proxyConfigPath,\n selectedLayers,\n hookGroups,\n sharedSkills: resolveSharedSkills(options.repoRoot, options.domains),\n cleanup: () => fs.promises.rm(temporaryDirectory, { recursive: true, force: true }),\n };\n } catch (error) {\n await fs.promises.rm(temporaryDirectory, { recursive: true, force: true });\n throw error;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"compatibilityContext.mjs","names":[],"sources":["../../src/adapters/compatibilityContext.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {\n type AgentProfile,\n applyProfileEnvironment,\n buildPersonaPrompt,\n type DomainMcpAllowlist,\n layerHookGroups,\n loadMajorModesConfig,\n type PluginEntry,\n projectHarnessEnvironment,\n resolveLayers,\n resolvePluginEntries,\n resolveProfile,\n resolveSharedSkills,\n} from '../services/config/index.ts';\nimport type { CompatibilityOptions } from '../types/interfaces/index.ts';\nimport { applyMcpAllowlist, PROXY_SERVER_NAME, resolveMcpAllowlist } from './mcpFilter.ts';\nimport { materializePluginEntries } from './pluginMaterializer.ts';\nimport { mergeMcpConfigs } from './resourceCollector.ts';\n\ntype JsonObject = Record<string, unknown>;\n\nconst MCP_CONFIG_FILENAME = '.mcp.json';\nconst GENERATED_MCP_CONFIG_FILENAME = 'mcp.json';\nconst PROXY_CONFIG_FILENAME = 'mcp-config.yaml';\nconst PERSONA_FILENAME = 'persona.md';\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst CONFIG_OPTION = '--config';\nconst TEMPORARY_DIRECTORY_PREFIX = 'doom-pi-compat-';\nconst ADDITIONAL_DIRS_ENV = 'DOOMPI_ADDITIONAL_DIRS';\nconst CLAUDE_PROJECT_DIR_ENV = 'CLAUDE_PROJECT_DIR';\nconst CODEX_REPO_ROOT_ENV = 'CODEX_REPO_ROOT';\nconst AGY_REPO_ROOT_ENV = 'AGY_REPO_ROOT';\nconst ORIGINAL_REPO_PATH_ENV = 'ORIGINAL_REPO_PATH';\n\nexport interface CompatibilityContext {\n options: CompatibilityOptions;\n environment: NodeJS.ProcessEnv;\n plugins: PluginEntry[];\n profile?: AgentProfile;\n personaFile?: string;\n mcpAllowlist?: DomainMcpAllowlist;\n mcpConfigPath: string;\n proxyConfigPath: string;\n selectedLayers: string[];\n hookGroups: string[];\n sharedSkills: boolean;\n cleanup(): Promise<void>;\n}\n\nfunction pluginMcpPaths(repoRoot: string, plugins: PluginEntry[]): string[] {\n const paths = [path.join(repoRoot, MCP_CONFIG_FILENAME)];\n for (const plugin of plugins) {\n if (plugin.mcp === false) continue;\n const configPath = path.join(plugin.directory, MCP_CONFIG_FILENAME);\n if (fs.existsSync(configPath)) paths.push(configPath);\n }\n return paths;\n}\n\nfunction resolveProxyConfigPath(config: JsonObject, repoRoot: string): string {\n const servers = (config.mcpServers ?? {}) as Record<string, JsonObject>;\n const proxy = servers[PROXY_SERVER_NAME];\n const args = Array.isArray(proxy?.args) ? proxy.args.map(String) : [];\n const configIndex = args.indexOf(CONFIG_OPTION);\n const selected = configIndex === -1 ? undefined : args[configIndex + 1];\n return selected ? path.resolve(repoRoot, selected) : path.join(repoRoot, PROXY_CONFIG_FILENAME);\n}\n\nasync function writeCompatibilityMcpConfig(\n repoRoot: string,\n plugins: PluginEntry[],\n allowlist: DomainMcpAllowlist | undefined,\n temporaryDirectory: string,\n): Promise<{ mcpConfigPath: string; proxyConfigPath: string }> {\n const config = await applyMcpAllowlist(\n mergeMcpConfigs(pluginMcpPaths(repoRoot, plugins)),\n allowlist,\n repoRoot,\n temporaryDirectory,\n );\n const mcpConfigPath = path.join(temporaryDirectory, GENERATED_MCP_CONFIG_FILENAME);\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n return { mcpConfigPath, proxyConfigPath: resolveProxyConfigPath(config, repoRoot) };\n}\n\n/** Resolves only the resources shared by Pi and compatibility frontends. */\nexport async function buildCompatibilityContext(options: CompatibilityOptions): Promise<CompatibilityContext> {\n const majorModesConfig = loadMajorModesConfig(options.repoRoot);\n const selectedLayers = resolveLayers(majorModesConfig, options.majorMode);\n const hookGroups = layerHookGroups(majorModesConfig, selectedLayers);\n const temporaryDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), TEMPORARY_DIRECTORY_PREFIX));\n await fs.promises.chmod(temporaryDirectory, PRIVATE_DIRECTORY_MODE);\n\n try {\n const profile = options.profile ? resolveProfile(options.repoRoot, options.profile) : undefined;\n const plugins = await materializePluginEntries(resolvePluginEntries(options.repoRoot, options.domains, []));\n const mcpAllowlist = resolveMcpAllowlist(options.repoRoot, options.domains);\n const mcp = await writeCompatibilityMcpConfig(options.repoRoot, plugins, mcpAllowlist, temporaryDirectory);\n const environment = { ...process.env };\n environment.NX_DAEMON ??= 'false';\n const profileEnvironment = applyProfileEnvironment(environment, profile?.env ?? {});\n const personaPrompt = profile?.persona ? buildPersonaPrompt(profile.personaRoot, profile.persona) : undefined;\n let personaFile: string | undefined;\n\n if (personaPrompt) {\n personaFile = path.join(temporaryDirectory, PERSONA_FILENAME);\n await fs.promises.writeFile(personaFile, `${personaPrompt}\\n`, { mode: PRIVATE_FILE_MODE });\n }\n\n // Projection only, with no state file: Claude, Codex and Antigravity read\n // an environment and never the store.\n projectHarnessEnvironment(\n {\n root: options.repoRoot,\n majorMode: options.majorMode,\n temporaryDirectory,\n domains: options.domains,\n layers: selectedLayers,\n profile: profile?.name,\n profileEnvironment,\n hookGroups,\n mcpConfigPath: mcp.mcpConfigPath,\n personaFile,\n additionalDirectories: options.additionalDirectories,\n hooks: true,\n },\n environment,\n );\n environment[ADDITIONAL_DIRS_ENV] = options.additionalDirectories.join(path.delimiter);\n environment[CLAUDE_PROJECT_DIR_ENV] = options.repoRoot;\n environment[CODEX_REPO_ROOT_ENV] = options.repoRoot;\n environment[AGY_REPO_ROOT_ENV] = options.repoRoot;\n environment[ORIGINAL_REPO_PATH_ENV] ||= options.repoRoot;\n\n return {\n options,\n environment,\n plugins,\n profile,\n personaFile,\n mcpAllowlist,\n mcpConfigPath: mcp.mcpConfigPath,\n proxyConfigPath: mcp.proxyConfigPath,\n selectedLayers,\n hookGroups,\n sharedSkills: resolveSharedSkills(options.repoRoot, options.domains),\n cleanup: () => fs.promises.rm(temporaryDirectory, { recursive: true, force: true }),\n };\n } catch (error) {\n await fs.promises.rm(temporaryDirectory, { recursive: true, force: true });\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./bootstrapLocator.cjs`),n=require(`./config/harnessState.cjs`),r=require(`../services/extensionAssembler.cjs`),i=require(`./resourceCollector.cjs`),a=require(`./harnessContext.cjs`),o=require(`./extensionCompiler.cjs`),s=require(`./syncState.cjs`),c=require(`./compositionState.cjs`);let l=require(`node:url`),u=require(`node:path`);u=e.__toESM(u,1);let d=require(`node:fs`);d=e.__toESM(d,1);let f=require(`@agimon-ai/doompi-config/majorModes`),p=require(`@agimon-ai/doompi-ui/extensionName`),m=require(`@earendil-works/pi-coding-agent`),h=require(`@agimon-ai/doompi-config/harnessStore`);const g=`doompi is configured for Pi but this repository was never synced. Run doompi sync.`,_=process.env.DOOMPI_TIMING===`1`||process.env.PI_TIMING===`1`,v={majorMode:`major-mode`,domains:`domains`,profile:`profile`,mute:`mute`},y=`layer`;function b(e){return e instanceof Error?e.message:String(e)}function x(e){try{return d.default.realpathSync(e)}catch{return u.default.resolve(e)}}function S(e,t){let{extensions:n}=(0,m.parseArgs)(e);if(!n||n.length===0)return!1;let r=new Set(Object.values(t).map(x));return n.some(e=>r.has(x(e)))}async function C(e,t,r=process.env){let i=await D(t),a={...n.readHarnessState({...e.env,...r}),...e.fileState,temporaryDirectory:i};(0,h.createHarnessSession)(a,{directory:i,environment:r});for(let[e,t]of Object.entries(a.profileEnvironment))r[e]===void 0&&(r[e]=t);return a}function w(e){let{unknownFlags:t}=(0,m.parseArgs)(e),n=e=>{let n=t.get(e);return typeof n==`string`&&n.trim()?n.trim():void 0},r=n(v.domains);return{majorMode:n(v.majorMode),domains:r?.split(`,`).map(e=>e.trim()).filter(Boolean),profile:n(v.profile),mute:t.get(v.mute)!==void 0,removedLayer:t.get(y)!==void 0}}function T(e){e.registerFlag(v.majorMode,{type:`string`,description:`Named major mode from .doom/modes.yaml`}),e.registerFlag(v.domains,{type:`string`,description:`Comma-separated content domains`}),e.registerFlag(v.profile,{type:`string`,description:`Persona and env from .doom/profiles.yaml`}),e.registerFlag(v.mute,{type:`boolean`,description:`Disable the notification extension`})}async function E(e,t,r,i){if(e.removedLayer&&i.push(`--${y} was replaced by --${v.majorMode}`),e.majorMode)try{let{applyMajorMode:r}=await Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`));r(t,e.majorMode,n.getHarnessState())}catch(t){i.push(`--${v.majorMode} ${e.majorMode}: ${b(t)}`)}if(e.domains&&e.domains.length>0)try{let{applyDomains:t}=await Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`));await t(e.domains,n.getHarnessState())}catch(t){i.push(`--domains ${e.domains.join(`,`)}: ${b(t)}`)}if(e.profile)try{let[{applyProfile:t},{resolveProfile:i}]=await Promise.all([Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`)),import(`@agimon-ai/doompi-config/profiles`)]);await t(i(r,e.profile),n.getHarnessState())}catch(t){i.push(`--profile ${e.profile}: ${b(t)}`)}}async function D(e,t=process.env){let r=s.runDirectory(e);return await d.default.promises.mkdir(r,{mode:448,recursive:!0}),n.updateHarnessState({temporaryDirectory:r},t),r}async function O(e){await d.default.promises.rm(s.runDirectory(e),{recursive:!0,force:!0})}async function k(e,t=n.getHarnessState(),a=process.env){let l=t.root??e.root,d=s.createMapResolvers(e.resolved,e.compiled),p=t.mcp?d.optionalPackageEntry(r.CONTEXT_PACKAGES.mcp):void 0,m={agents:t.agents,autoStop:!1,preset:e.selection.preset,mcpEntry:p,personaEntry:d.ownEntry(r.PERSONA_ENTRY),workflowExtension:i.selectWorkflowExtensionForProcess(d.optionalPackageEntry(r.CONTEXT_PACKAGES.workflow),d.optionalPackageEntry(r.CONTEXT_PACKAGES.dispatcherWorkflow),a),layers:[...t.layers],majorModesConfig:(0,f.loadMajorModesConfig)(l),resolvers:d};n.updateHarnessState({childExtensions:r.assembleChildExtensions({...m,agents:!1,mute:!0})},a),t.agents&&(a.PI_SUBAGENT_EXTRA_AGENT_DIRS=t.agentDirectories.join(u.default.delimiter),a.PI_SUBAGENT_EXTRA_SKILL_DIRS=t.skillDirectories.join(u.default.delimiter));let h=[...r.assembleExtensions({...m,mute:a[c.MUTE_ENV]===`1`})].reverse(),g=e.bundles?.[o.extensionSetKey(h)];return g?[g]:h}async function A(e,t,n){let r=[];for(let i of t){let t=performance.now(),a;try{a=await import((0,l.pathToFileURL)(i).href),_&&process.stderr.write(`[doompi:timing] import ${(performance.now()-t).toFixed(1)}ms ${i}\n`)}catch(e){n.push(`${i}: ${b(e)}`);continue}if(typeof a.default!=`function`){n.push(`${i}: does not export an extension factory`);continue}let o=performance.now();try{await a.default((0,p.withExtensionSource)(e,i)),_&&process.stderr.write(`[doompi:timing] factory ${(performance.now()-o).toFixed(1)}ms ${i}\n`),r.push(i)}catch(e){n.push(`${i}: ${b(e)}`)}}return r}async function j(e,n={}){let r=n.environment??process.env,i=[],o=t.findSyncedRoot(n.cwd??process.cwd());if(!o)return{problems:[g],stale:!1,loaded:[]};let l;try{l=s.readSyncState(o)}catch(e){return{problems:[b(e)],stale:!1,loaded:[]}}if(!l)return{problems:[g],stale:!1,loaded:[]};let u=n.argv??process.argv.slice(2);if(r[c.EXTERNAL_EXTENSIONS_ENV]===`1`||S(u,{...l.resolved,...l.bundles}))return{problems:[],stale:!1,loaded:[]};if(a.configurePreset({preset:l.selection.preset,piArgs:[]},r),!c.alreadyComposed(r)){r[c.COMPOSED_ENV]=`1`,await C(l,o,r);let e=w(u);e.mute&&(r[c.MUTE_ENV]=`1`),await E(e,(0,f.loadMajorModesConfig)(o),o,i)}let d;try{d=await k(l,(0,h.loadHarnessState)(r).state,r)}catch(e){return{problems:[...i,b(e)],stale:!1,loaded:[]}}let p=await A(e,d,i);return{problems:i,stale:s.computeInputsHash(o,l.selection)!==l.inputsHash,loaded:p}}exports.DOOM_FLAGS=v,exports.REMOVED_LAYER_FLAG=y,exports.applyStartupFlags=E,exports.cleanupRunDirectory=O,exports.composeDoomSession=j,exports.composeLoadOrder=k,exports.extensionsProvidedExternally=S,exports.loadComposedExtensions=A,exports.prepareRunDirectory=D,exports.readStartupFlags=w,exports.registerDoomFlags=T,exports.startSyncedSession=C;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./bootstrapLocator.cjs`),n=require(`./config/harnessState.cjs`),r=require(`./resourceCollector.cjs`),i=require(`../services/extensionAssembler.cjs`),a=require(`./extensionCompiler.cjs`),o=require(`./compositionState.cjs`),s=require(`./harnessContext.cjs`),c=require(`./syncState.cjs`);let l=require(`node:url`),u=require(`node:path`);u=e.__toESM(u,1);let d=require(`node:fs`);d=e.__toESM(d,1);let f=require(`@agimon-ai/doompi-config/majorModes`),p=require(`@agimon-ai/doompi-ui/extensionName`),m=require(`@earendil-works/pi-coding-agent`),h=require(`@agimon-ai/doompi-config/harnessStore`);const g=`doompi is configured for Pi but this repository was never synced. Run doompi sync.`,_=process.env.DOOMPI_TIMING===`1`||process.env.PI_TIMING===`1`,v={majorMode:`major-mode`,domains:`domains`,profile:`profile`,mute:`mute`},y=`layer`;function b(e){return e instanceof Error?e.message:String(e)}function x(e){try{return d.default.realpathSync(e)}catch{return u.default.resolve(e)}}function S(e,t){let{extensions:n}=(0,m.parseArgs)(e);if(!n||n.length===0)return!1;let r=new Set(Object.values(t).map(x));return n.some(e=>r.has(x(e)))}async function C(e,t,r=process.env){let i=await D(t),a={...n.readHarnessState({...e.env,...r}),...e.fileState,temporaryDirectory:i};(0,h.createHarnessSession)(a,{directory:i,environment:r});for(let[e,t]of Object.entries(a.profileEnvironment))r[e]===void 0&&(r[e]=t);return a}function w(e){let{unknownFlags:t}=(0,m.parseArgs)(e),n=e=>{let n=t.get(e);return typeof n==`string`&&n.trim()?n.trim():void 0},r=n(v.domains);return{majorMode:n(v.majorMode),domains:r?.split(`,`).map(e=>e.trim()).filter(Boolean),profile:n(v.profile),mute:t.get(v.mute)!==void 0,removedLayer:t.get(y)!==void 0}}function T(e){e.registerFlag(v.majorMode,{type:`string`,description:`Named major mode from .doom/modes.yaml`}),e.registerFlag(v.domains,{type:`string`,description:`Comma-separated content domains`}),e.registerFlag(v.profile,{type:`string`,description:`Persona and env from .doom/profiles.yaml`}),e.registerFlag(v.mute,{type:`boolean`,description:`Disable the notification extension`})}async function E(e,t,r,i){if(e.removedLayer&&i.push(`--${y} was replaced by --${v.majorMode}`),e.majorMode)try{let{applyMajorMode:r}=await Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`));r(t,e.majorMode,n.getHarnessState())}catch(t){i.push(`--${v.majorMode} ${e.majorMode}: ${b(t)}`)}if(e.domains&&e.domains.length>0)try{let{applyDomains:t}=await Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`));await t(e.domains,n.getHarnessState())}catch(t){i.push(`--domains ${e.domains.join(`,`)}: ${b(t)}`)}if(e.profile)try{let[{applyProfile:t},{resolveProfile:i}]=await Promise.all([Promise.resolve().then(()=>require(`./matrixSwitcher.cjs`)),import(`@agimon-ai/doompi-config/profiles`)]);await t(i(r,e.profile),n.getHarnessState())}catch(t){i.push(`--profile ${e.profile}: ${b(t)}`)}}async function D(e,t=process.env){let r=c.runDirectory(e);return await d.default.promises.mkdir(r,{mode:448,recursive:!0}),n.updateHarnessState({temporaryDirectory:r},t),r}async function O(e){await d.default.promises.rm(c.runDirectory(e),{recursive:!0,force:!0})}async function k(e,t=n.getHarnessState(),s=process.env){let l=t.root??e.root,d=c.createMapResolvers(e.resolved,e.compiled),p=t.mcp?d.optionalPackageEntry(i.CONTEXT_PACKAGES.mcp):void 0,m={agents:t.agents,autoStop:!1,preset:e.selection.preset,mcpEntry:p,personaEntry:d.ownEntry(i.PERSONA_ENTRY),workflowExtension:r.selectWorkflowExtensionForProcess(d.optionalPackageEntry(i.CONTEXT_PACKAGES.workflow),d.optionalPackageEntry(i.CONTEXT_PACKAGES.dispatcherWorkflow),s),layers:[...t.layers],majorModesConfig:(0,f.loadMajorModesConfig)(l),resolvers:d};n.updateHarnessState({childExtensions:i.assembleChildExtensions({...m,agents:!1,mute:!0})},s),t.agents&&(s.PI_SUBAGENT_EXTRA_AGENT_DIRS=t.agentDirectories.join(u.default.delimiter),s.PI_SUBAGENT_EXTRA_SKILL_DIRS=t.skillDirectories.join(u.default.delimiter));let h=[...i.assembleExtensions({...m,mute:s[o.MUTE_ENV]===`1`})].reverse(),g=e.bundles?.[a.extensionSetKey(h)];return g?[g]:h}async function A(e,t,n){let r=[];for(let i of t){let t=performance.now(),a;try{a=await import((0,l.pathToFileURL)(i).href),_&&process.stderr.write(`[doompi:timing] import ${(performance.now()-t).toFixed(1)}ms ${i}\n`)}catch(e){n.push(`${i}: ${b(e)}`);continue}if(typeof a.default!=`function`){n.push(`${i}: does not export an extension factory`);continue}let o=performance.now();try{await a.default((0,p.withExtensionSource)(e,i)),_&&process.stderr.write(`[doompi:timing] factory ${(performance.now()-o).toFixed(1)}ms ${i}\n`),r.push(i)}catch(e){n.push(`${i}: ${b(e)}`)}}return r}async function j(e,n={}){let r=n.environment??process.env,i=[],a=t.findSyncedRoot(n.cwd??process.cwd());if(!a)return{problems:[g],stale:!1,loaded:[]};let l;try{l=c.readSyncState(a)}catch(e){return{problems:[b(e)],stale:!1,loaded:[]}}if(!l)return{problems:[g],stale:!1,loaded:[]};let u=n.argv??process.argv.slice(2);if(r[o.EXTERNAL_EXTENSIONS_ENV]===`1`||S(u,{...l.resolved,...l.bundles}))return{problems:[],stale:!1,loaded:[]};if(s.configurePreset({preset:l.selection.preset,piArgs:[]},r),!o.alreadyComposed(r)){r[o.COMPOSED_ENV]=`1`,await C(l,a,r);let e=w(u);e.mute&&(r[o.MUTE_ENV]=`1`),await E(e,(0,f.loadMajorModesConfig)(a),a,i)}let d;try{d=await k(l,(0,h.loadHarnessState)(r).state,r)}catch(e){return{problems:[...i,b(e)],stale:!1,loaded:[]}}let p=await A(e,d,i);return{problems:i,stale:c.computeInputsHash(a,l.selection)!==l.inputsHash,loaded:p}}exports.DOOM_FLAGS=v,exports.REMOVED_LAYER_FLAG=y,exports.applyStartupFlags=E,exports.cleanupRunDirectory=O,exports.composeDoomSession=j,exports.composeLoadOrder=k,exports.extensionsProvidedExternally=S,exports.loadComposedExtensions=A,exports.prepareRunDirectory=D,exports.readStartupFlags=w,exports.registerDoomFlags=T,exports.startSyncedSession=C;
2
2
  //# sourceMappingURL=composer.cjs.map
@@ -1,2 +1,2 @@
1
- import{findSyncedRoot as e}from"./bootstrapLocator.mjs";import{createHarnessSession as t,getHarnessState as n,loadHarnessState as r,readHarnessState as i,updateHarnessState as a}from"./config/harnessState.mjs";import{CONTEXT_PACKAGES as o,PERSONA_ENTRY as s,assembleChildExtensions as c,assembleExtensions as l}from"../services/extensionAssembler.mjs";import{selectWorkflowExtensionForProcess as u}from"./resourceCollector.mjs";import{configurePreset as d}from"./harnessContext.mjs";import{extensionSetKey as f}from"./extensionCompiler.mjs";import{computeInputsHash as p,createMapResolvers as m,readSyncState as h,runDirectory as g}from"./syncState.mjs";import{COMPOSED_ENV as _,EXTERNAL_EXTENSIONS_ENV as v,MUTE_ENV as y,alreadyComposed as b}from"./compositionState.mjs";import{pathToFileURL as x}from"node:url";import S from"node:path";import C from"node:fs";import{loadMajorModesConfig as w}from"@agimon-ai/doompi-config/majorModes";import{withExtensionSource as T}from"@agimon-ai/doompi-ui/extensionName";import{parseArgs as E}from"@earendil-works/pi-coding-agent";const D=`doompi is configured for Pi but this repository was never synced. Run doompi sync.`,O=process.env.DOOMPI_TIMING===`1`||process.env.PI_TIMING===`1`,k={majorMode:`major-mode`,domains:`domains`,profile:`profile`,mute:`mute`},A=`layer`;function j(e){return e instanceof Error?e.message:String(e)}function M(e){try{return C.realpathSync(e)}catch{return S.resolve(e)}}function N(e,t){let{extensions:n}=E(e);if(!n||n.length===0)return!1;let r=new Set(Object.values(t).map(M));return n.some(e=>r.has(M(e)))}async function P(e,n,r=process.env){let a=await R(n),o={...i({...e.env,...r}),...e.fileState,temporaryDirectory:a};t(o,{directory:a,environment:r});for(let[e,t]of Object.entries(o.profileEnvironment))r[e]===void 0&&(r[e]=t);return o}function F(e){let{unknownFlags:t}=E(e),n=e=>{let n=t.get(e);return typeof n==`string`&&n.trim()?n.trim():void 0},r=n(k.domains);return{majorMode:n(k.majorMode),domains:r?.split(`,`).map(e=>e.trim()).filter(Boolean),profile:n(k.profile),mute:t.get(k.mute)!==void 0,removedLayer:t.get(A)!==void 0}}function I(e){e.registerFlag(k.majorMode,{type:`string`,description:`Named major mode from .doom/modes.yaml`}),e.registerFlag(k.domains,{type:`string`,description:`Comma-separated content domains`}),e.registerFlag(k.profile,{type:`string`,description:`Persona and env from .doom/profiles.yaml`}),e.registerFlag(k.mute,{type:`boolean`,description:`Disable the notification extension`})}async function L(e,t,r,i){if(e.removedLayer&&i.push(`--${A} was replaced by --${k.majorMode}`),e.majorMode)try{let{applyMajorMode:r}=await import(`./matrixSwitcher.mjs`);r(t,e.majorMode,n())}catch(t){i.push(`--${k.majorMode} ${e.majorMode}: ${j(t)}`)}if(e.domains&&e.domains.length>0)try{let{applyDomains:t}=await import(`./matrixSwitcher.mjs`);await t(e.domains,n())}catch(t){i.push(`--domains ${e.domains.join(`,`)}: ${j(t)}`)}if(e.profile)try{let[{applyProfile:t},{resolveProfile:i}]=await Promise.all([import(`./matrixSwitcher.mjs`),import(`@agimon-ai/doompi-config/profiles`)]);await t(i(r,e.profile),n())}catch(t){i.push(`--profile ${e.profile}: ${j(t)}`)}}async function R(e,t=process.env){let n=g(e);return await C.promises.mkdir(n,{mode:448,recursive:!0}),a({temporaryDirectory:n},t),n}async function z(e){await C.promises.rm(g(e),{recursive:!0,force:!0})}async function B(e,t=n(),r=process.env){let i=t.root??e.root,d=m(e.resolved,e.compiled),p=t.mcp?d.optionalPackageEntry(o.mcp):void 0,h={agents:t.agents,autoStop:!1,preset:e.selection.preset,mcpEntry:p,personaEntry:d.ownEntry(s),workflowExtension:u(d.optionalPackageEntry(o.workflow),d.optionalPackageEntry(o.dispatcherWorkflow),r),layers:[...t.layers],majorModesConfig:w(i),resolvers:d};a({childExtensions:c({...h,agents:!1,mute:!0})},r),t.agents&&(r.PI_SUBAGENT_EXTRA_AGENT_DIRS=t.agentDirectories.join(S.delimiter),r.PI_SUBAGENT_EXTRA_SKILL_DIRS=t.skillDirectories.join(S.delimiter));let g=[...l({...h,mute:r[y]===`1`})].reverse(),_=e.bundles?.[f(g)];return _?[_]:g}async function V(e,t,n){let r=[];for(let i of t){let t=performance.now(),a;try{a=await import(x(i).href),O&&process.stderr.write(`[doompi:timing] import ${(performance.now()-t).toFixed(1)}ms ${i}\n`)}catch(e){n.push(`${i}: ${j(e)}`);continue}if(typeof a.default!=`function`){n.push(`${i}: does not export an extension factory`);continue}let o=performance.now();try{await a.default(T(e,i)),O&&process.stderr.write(`[doompi:timing] factory ${(performance.now()-o).toFixed(1)}ms ${i}\n`),r.push(i)}catch(e){n.push(`${i}: ${j(e)}`)}}return r}async function H(t,n={}){let i=n.environment??process.env,a=[],o=e(n.cwd??process.cwd());if(!o)return{problems:[D],stale:!1,loaded:[]};let s;try{s=h(o)}catch(e){return{problems:[j(e)],stale:!1,loaded:[]}}if(!s)return{problems:[D],stale:!1,loaded:[]};let c=n.argv??process.argv.slice(2);if(i[v]===`1`||N(c,{...s.resolved,...s.bundles}))return{problems:[],stale:!1,loaded:[]};if(d({preset:s.selection.preset,piArgs:[]},i),!b(i)){i[_]=`1`,await P(s,o,i);let e=F(c);e.mute&&(i[y]=`1`),await L(e,w(o),o,a)}let l;try{l=await B(s,r(i).state,i)}catch(e){return{problems:[...a,j(e)],stale:!1,loaded:[]}}let u=await V(t,l,a);return{problems:a,stale:p(o,s.selection)!==s.inputsHash,loaded:u}}export{k as DOOM_FLAGS,A as REMOVED_LAYER_FLAG,L as applyStartupFlags,z as cleanupRunDirectory,H as composeDoomSession,B as composeLoadOrder,N as extensionsProvidedExternally,V as loadComposedExtensions,R as prepareRunDirectory,F as readStartupFlags,I as registerDoomFlags,P as startSyncedSession};
1
+ import{findSyncedRoot as e}from"./bootstrapLocator.mjs";import{createHarnessSession as t,getHarnessState as n,loadHarnessState as r,readHarnessState as i,updateHarnessState as a}from"./config/harnessState.mjs";import{selectWorkflowExtensionForProcess as o}from"./resourceCollector.mjs";import{CONTEXT_PACKAGES as s,PERSONA_ENTRY as c,assembleChildExtensions as l,assembleExtensions as u}from"../services/extensionAssembler.mjs";import{extensionSetKey as d}from"./extensionCompiler.mjs";import{COMPOSED_ENV as f,EXTERNAL_EXTENSIONS_ENV as p,MUTE_ENV as m,alreadyComposed as h}from"./compositionState.mjs";import{configurePreset as g}from"./harnessContext.mjs";import{computeInputsHash as _,createMapResolvers as v,readSyncState as y,runDirectory as b}from"./syncState.mjs";import{pathToFileURL as x}from"node:url";import S from"node:path";import C from"node:fs";import{loadMajorModesConfig as w}from"@agimon-ai/doompi-config/majorModes";import{withExtensionSource as T}from"@agimon-ai/doompi-ui/extensionName";import{parseArgs as E}from"@earendil-works/pi-coding-agent";const D=`doompi is configured for Pi but this repository was never synced. Run doompi sync.`,O=process.env.DOOMPI_TIMING===`1`||process.env.PI_TIMING===`1`,k={majorMode:`major-mode`,domains:`domains`,profile:`profile`,mute:`mute`},A=`layer`;function j(e){return e instanceof Error?e.message:String(e)}function M(e){try{return C.realpathSync(e)}catch{return S.resolve(e)}}function N(e,t){let{extensions:n}=E(e);if(!n||n.length===0)return!1;let r=new Set(Object.values(t).map(M));return n.some(e=>r.has(M(e)))}async function P(e,n,r=process.env){let a=await R(n),o={...i({...e.env,...r}),...e.fileState,temporaryDirectory:a};t(o,{directory:a,environment:r});for(let[e,t]of Object.entries(o.profileEnvironment))r[e]===void 0&&(r[e]=t);return o}function F(e){let{unknownFlags:t}=E(e),n=e=>{let n=t.get(e);return typeof n==`string`&&n.trim()?n.trim():void 0},r=n(k.domains);return{majorMode:n(k.majorMode),domains:r?.split(`,`).map(e=>e.trim()).filter(Boolean),profile:n(k.profile),mute:t.get(k.mute)!==void 0,removedLayer:t.get(A)!==void 0}}function I(e){e.registerFlag(k.majorMode,{type:`string`,description:`Named major mode from .doom/modes.yaml`}),e.registerFlag(k.domains,{type:`string`,description:`Comma-separated content domains`}),e.registerFlag(k.profile,{type:`string`,description:`Persona and env from .doom/profiles.yaml`}),e.registerFlag(k.mute,{type:`boolean`,description:`Disable the notification extension`})}async function L(e,t,r,i){if(e.removedLayer&&i.push(`--${A} was replaced by --${k.majorMode}`),e.majorMode)try{let{applyMajorMode:r}=await import(`./matrixSwitcher.mjs`);r(t,e.majorMode,n())}catch(t){i.push(`--${k.majorMode} ${e.majorMode}: ${j(t)}`)}if(e.domains&&e.domains.length>0)try{let{applyDomains:t}=await import(`./matrixSwitcher.mjs`);await t(e.domains,n())}catch(t){i.push(`--domains ${e.domains.join(`,`)}: ${j(t)}`)}if(e.profile)try{let[{applyProfile:t},{resolveProfile:i}]=await Promise.all([import(`./matrixSwitcher.mjs`),import(`@agimon-ai/doompi-config/profiles`)]);await t(i(r,e.profile),n())}catch(t){i.push(`--profile ${e.profile}: ${j(t)}`)}}async function R(e,t=process.env){let n=b(e);return await C.promises.mkdir(n,{mode:448,recursive:!0}),a({temporaryDirectory:n},t),n}async function z(e){await C.promises.rm(b(e),{recursive:!0,force:!0})}async function B(e,t=n(),r=process.env){let i=t.root??e.root,f=v(e.resolved,e.compiled),p=t.mcp?f.optionalPackageEntry(s.mcp):void 0,h={agents:t.agents,autoStop:!1,preset:e.selection.preset,mcpEntry:p,personaEntry:f.ownEntry(c),workflowExtension:o(f.optionalPackageEntry(s.workflow),f.optionalPackageEntry(s.dispatcherWorkflow),r),layers:[...t.layers],majorModesConfig:w(i),resolvers:f};a({childExtensions:l({...h,agents:!1,mute:!0})},r),t.agents&&(r.PI_SUBAGENT_EXTRA_AGENT_DIRS=t.agentDirectories.join(S.delimiter),r.PI_SUBAGENT_EXTRA_SKILL_DIRS=t.skillDirectories.join(S.delimiter));let g=[...u({...h,mute:r[m]===`1`})].reverse(),_=e.bundles?.[d(g)];return _?[_]:g}async function V(e,t,n){let r=[];for(let i of t){let t=performance.now(),a;try{a=await import(x(i).href),O&&process.stderr.write(`[doompi:timing] import ${(performance.now()-t).toFixed(1)}ms ${i}\n`)}catch(e){n.push(`${i}: ${j(e)}`);continue}if(typeof a.default!=`function`){n.push(`${i}: does not export an extension factory`);continue}let o=performance.now();try{await a.default(T(e,i)),O&&process.stderr.write(`[doompi:timing] factory ${(performance.now()-o).toFixed(1)}ms ${i}\n`),r.push(i)}catch(e){n.push(`${i}: ${j(e)}`)}}return r}async function H(t,n={}){let i=n.environment??process.env,a=[],o=e(n.cwd??process.cwd());if(!o)return{problems:[D],stale:!1,loaded:[]};let s;try{s=y(o)}catch(e){return{problems:[j(e)],stale:!1,loaded:[]}}if(!s)return{problems:[D],stale:!1,loaded:[]};let c=n.argv??process.argv.slice(2);if(i[p]===`1`||N(c,{...s.resolved,...s.bundles}))return{problems:[],stale:!1,loaded:[]};if(g({preset:s.selection.preset,piArgs:[]},i),!h(i)){i[f]=`1`,await P(s,o,i);let e=F(c);e.mute&&(i[m]=`1`),await L(e,w(o),o,a)}let l;try{l=await B(s,r(i).state,i)}catch(e){return{problems:[...a,j(e)],stale:!1,loaded:[]}}let u=await V(t,l,a);return{problems:a,stale:_(o,s.selection)!==s.inputsHash,loaded:u}}export{k as DOOM_FLAGS,A as REMOVED_LAYER_FLAG,L as applyStartupFlags,z as cleanupRunDirectory,H as composeDoomSession,B as composeLoadOrder,N as extensionsProvidedExternally,V as loadComposedExtensions,R as prepareRunDirectory,F as readStartupFlags,I as registerDoomFlags,P as startSyncedSession};
2
2
  //# sourceMappingURL=composer.mjs.map
@@ -0,0 +1,3 @@
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./dpiSettings.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`@agimon-ai/doompi-config`);const i=`--force`,a=`PI_SUBAGENT_PI_BINARY`,o=/^dpi(?:\.[cm]?js|\.ts)?$/u;async function s(e){let t=await import(`@earendil-works/pi-coding-agent`);if(t.SettingsManager!==e.SettingsManager)throw Error(`DPI resolved more than one Pi settings runtime`);return t}function c(e=process.env,t=process.argv[1]){e.PI_CODING_AGENT=`true`,e.AI_AGENT=`pi`,!e[a]?.trim()&&t&&o.test(n.default.basename(t))&&(e[a]=n.default.resolve(t))}async function l(e){let n=await t.loadPiSettingsRuntime(),r=await s(n),i=t.installDpiSettingsOverlay(n);process.title=`dpi`,c(),process.emitWarning=(()=>void 0);try{await r.main(e);let t=process.exitCode;return typeof t==`number`?t:Number.parseInt(t??`0`,10)}finally{i()}}function u(e){return[`DoomPi repository configuration: ${e.directory}`,...e.created.length>0?[`created: ${e.created.join(`, `)}`]:[],...e.preserved.length>0?[`kept: ${e.preserved.join(`, `)}`]:[],...e.replaced.length>0?[`replaced: ${e.replaced.join(`, `)}`]:[],``,"Run `dpi sync` next.",``].join(`
2
+ `)}function d(e,t=process.cwd(),n=process.stdout){let a=e.slice(1),o=a.find(e=>e!==i);if(o!==void 0)throw Error(`dpi init does not accept ${o}`);let s=(0,r.initializeRepositoryDoomConfig)(t,{force:a.includes(i)});return n.write(u(s)),0}async function f(e){let{SyncPipeline:t}=await Promise.resolve().then(()=>require(`../commands/syncPipeline.cjs`));return new t({settingsMode:`embedded`}).execute(e)}const p={init:d,launchPi:l,sync:f};async function m(e,t=p){return e[0]===`init`?t.init(e):e[0]===`sync`?t.sync(e):t.launchPi(e)}exports.runDpi=m;
3
+ //# sourceMappingURL=dpiRunner.cjs.map