@agimon-ai/doompi-config 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.cjs +1 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.mjs +1 -0
  5. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  6. package/dist/atomicJson.cjs +2 -0
  7. package/dist/atomicJson.cjs.map +1 -0
  8. package/dist/atomicJson.d.cts +6 -0
  9. package/dist/atomicJson.d.cts.map +1 -0
  10. package/dist/atomicJson.d.mts +6 -0
  11. package/dist/atomicJson.d.mts.map +1 -0
  12. package/dist/atomicJson.mjs +2 -0
  13. package/dist/atomicJson.mjs.map +1 -0
  14. package/dist/config/piConfig.cjs +2 -0
  15. package/dist/config/piConfig.cjs.map +1 -0
  16. package/dist/config/piConfig.d.cts +7 -0
  17. package/dist/config/piConfig.d.cts.map +1 -0
  18. package/dist/config/piConfig.d.mts +7 -0
  19. package/dist/config/piConfig.d.mts.map +1 -0
  20. package/dist/config/piConfig.mjs +2 -0
  21. package/dist/config/piConfig.mjs.map +1 -0
  22. package/dist/config/schema.cjs +0 -0
  23. package/dist/config/schema.d.cts +33 -0
  24. package/dist/config/schema.d.cts.map +1 -0
  25. package/dist/config/schema.d.mts +33 -0
  26. package/dist/config/schema.d.mts.map +1 -0
  27. package/dist/config/schema.mjs +1 -0
  28. package/dist/config.cjs +2 -0
  29. package/dist/config.cjs.map +1 -0
  30. package/dist/config.d.cts +24 -0
  31. package/dist/config.d.cts.map +1 -0
  32. package/dist/config.d.mts +24 -0
  33. package/dist/config.d.mts.map +1 -0
  34. package/dist/config.mjs +2 -0
  35. package/dist/config.mjs.map +1 -0
  36. package/dist/configWriter.cjs +2 -0
  37. package/dist/configWriter.cjs.map +1 -0
  38. package/dist/configWriter.d.cts +52 -0
  39. package/dist/configWriter.d.cts.map +1 -0
  40. package/dist/configWriter.d.mts +52 -0
  41. package/dist/configWriter.d.mts.map +1 -0
  42. package/dist/configWriter.mjs +2 -0
  43. package/dist/configWriter.mjs.map +1 -0
  44. package/dist/container.cjs +2 -0
  45. package/dist/container.cjs.map +1 -0
  46. package/dist/container.d.cts +12 -0
  47. package/dist/container.d.cts.map +1 -0
  48. package/dist/container.d.mts +12 -0
  49. package/dist/container.d.mts.map +1 -0
  50. package/dist/container.mjs +2 -0
  51. package/dist/container.mjs.map +1 -0
  52. package/dist/domains.cjs +2 -0
  53. package/dist/domains.cjs.map +1 -0
  54. package/dist/domains.d.cts +75 -0
  55. package/dist/domains.d.cts.map +1 -0
  56. package/dist/domains.d.mts +75 -0
  57. package/dist/domains.d.mts.map +1 -0
  58. package/dist/domains.mjs +2 -0
  59. package/dist/domains.mjs.map +1 -0
  60. package/dist/extensions/doom.cjs +2 -0
  61. package/dist/extensions/doom.cjs.map +1 -0
  62. package/dist/extensions/doom.d.cts +8 -0
  63. package/dist/extensions/doom.d.cts.map +1 -0
  64. package/dist/extensions/doom.d.mts +8 -0
  65. package/dist/extensions/doom.d.mts.map +1 -0
  66. package/dist/extensions/doom.mjs +2 -0
  67. package/dist/extensions/doom.mjs.map +1 -0
  68. package/dist/extensions/pi.cjs +2 -0
  69. package/dist/extensions/pi.cjs.map +1 -0
  70. package/dist/extensions/pi.d.cts +8 -0
  71. package/dist/extensions/pi.d.cts.map +1 -0
  72. package/dist/extensions/pi.d.mts +8 -0
  73. package/dist/extensions/pi.d.mts.map +1 -0
  74. package/dist/extensions/pi.mjs +2 -0
  75. package/dist/extensions/pi.mjs.map +1 -0
  76. package/dist/harnessState.cjs +2 -0
  77. package/dist/harnessState.cjs.map +1 -0
  78. package/dist/harnessState.d.cts +50 -0
  79. package/dist/harnessState.d.cts.map +1 -0
  80. package/dist/harnessState.d.mts +50 -0
  81. package/dist/harnessState.d.mts.map +1 -0
  82. package/dist/harnessState.mjs +2 -0
  83. package/dist/harnessState.mjs.map +1 -0
  84. package/dist/harnessStore.cjs +2 -0
  85. package/dist/harnessStore.cjs.map +1 -0
  86. package/dist/harnessStore.d.cts +102 -0
  87. package/dist/harnessStore.d.cts.map +1 -0
  88. package/dist/harnessStore.d.mts +102 -0
  89. package/dist/harnessStore.d.mts.map +1 -0
  90. package/dist/harnessStore.mjs +2 -0
  91. package/dist/harnessStore.mjs.map +1 -0
  92. package/dist/index.cjs +1 -0
  93. package/dist/index.d.cts +16 -0
  94. package/dist/index.d.mts +16 -0
  95. package/dist/index.mjs +1 -0
  96. package/dist/init.cjs +73 -0
  97. package/dist/init.cjs.map +1 -0
  98. package/dist/init.d.cts +33 -0
  99. package/dist/init.d.cts.map +1 -0
  100. package/dist/init.d.mts +33 -0
  101. package/dist/init.d.mts.map +1 -0
  102. package/dist/init.mjs +73 -0
  103. package/dist/init.mjs.map +1 -0
  104. package/dist/layeredConfig.cjs +2 -0
  105. package/dist/layeredConfig.cjs.map +1 -0
  106. package/dist/layeredConfig.d.cts +49 -0
  107. package/dist/layeredConfig.d.cts.map +1 -0
  108. package/dist/layeredConfig.d.mts +49 -0
  109. package/dist/layeredConfig.d.mts.map +1 -0
  110. package/dist/layeredConfig.mjs +2 -0
  111. package/dist/layeredConfig.mjs.map +1 -0
  112. package/dist/majorModes.cjs +2 -0
  113. package/dist/majorModes.cjs.map +1 -0
  114. package/dist/majorModes.d.cts +73 -0
  115. package/dist/majorModes.d.cts.map +1 -0
  116. package/dist/majorModes.d.mts +73 -0
  117. package/dist/majorModes.d.mts.map +1 -0
  118. package/dist/majorModes.mjs +2 -0
  119. package/dist/majorModes.mjs.map +1 -0
  120. package/dist/pi.cjs +1 -0
  121. package/dist/pi.d.cts +2 -0
  122. package/dist/pi.d.mts +2 -0
  123. package/dist/pi.mjs +1 -0
  124. package/dist/piContext.cjs +2 -0
  125. package/dist/piContext.cjs.map +1 -0
  126. package/dist/piContext.d.cts +19 -0
  127. package/dist/piContext.d.cts.map +1 -0
  128. package/dist/piContext.d.mts +19 -0
  129. package/dist/piContext.d.mts.map +1 -0
  130. package/dist/piContext.mjs +2 -0
  131. package/dist/piContext.mjs.map +1 -0
  132. package/dist/profiles.cjs +4 -0
  133. package/dist/profiles.cjs.map +1 -0
  134. package/dist/profiles.d.cts +35 -0
  135. package/dist/profiles.d.cts.map +1 -0
  136. package/dist/profiles.d.mts +35 -0
  137. package/dist/profiles.d.mts.map +1 -0
  138. package/dist/profiles.mjs +4 -0
  139. package/dist/profiles.mjs.map +1 -0
  140. package/dist/types.cjs +2 -0
  141. package/dist/types.cjs.map +1 -0
  142. package/dist/types.d.cts +132 -0
  143. package/dist/types.d.cts.map +1 -0
  144. package/dist/types.d.mts +132 -0
  145. package/dist/types.d.mts.map +1 -0
  146. package/dist/types.mjs +2 -0
  147. package/dist/types.mjs.map +1 -0
  148. package/package.json +150 -0
  149. package/skills/doom-pi-config/SKILL.md +26 -0
  150. package/skills/doom-pi-config/agents/openai.yaml +4 -0
  151. package/skills/doom-pi-config/references/config-contract.md +43 -0
@@ -0,0 +1,52 @@
1
+ //#region src/configWriter.d.ts
2
+ /**
3
+ * Writes into the global Doom config file, one key path at a time.
4
+ *
5
+ * Extracted from doom-file-edit, which owned the only writer in the repo and had
6
+ * it hard-coded to `editor.command`. Several extensions now edit their own
7
+ * settings from the config panel, and every one of them needs the same four
8
+ * properties: keep the user's comments, never publish a file the parser would
9
+ * reject, never leave a half-written file behind, and apply a set of related
10
+ * edits together.
11
+ *
12
+ * That last one is not a convenience. `voice.adapters.<engine>.model` accepts a
13
+ * path or an id but not both, so switching between them is a set and an unset
14
+ * that must land in the same write, or the file is briefly invalid.
15
+ *
16
+ * Atomicity is the same rename trick as `atomicJson.ts` next door, and carries
17
+ * the same caveat: it prevents torn reads, not lost updates. Two sessions with
18
+ * the panel open still clobber each other, because the rename only publishes
19
+ * what the caller already computed.
20
+ *
21
+ * AVOID:
22
+ * - Treating this as a lock
23
+ * - Writing an empty string; the parser rejects blank values, so clearing a key
24
+ * means removing it
25
+ */
26
+ interface DoomConfigEdit {
27
+ /** Key path into the document, e.g. `['voice', 'adapters', 'mlx-whisper', 'model', 'id']`. */
28
+ readonly keyPath: readonly string[];
29
+ /** The value to write. `undefined` removes the key. */
30
+ readonly value?: string;
31
+ }
32
+ interface WriteDoomConfigOptions {
33
+ /**
34
+ * Remove ancestors left holding nothing. Defaults to true, and is not
35
+ * cosmetic: an adapter left as `{}` fails validation, because the parser
36
+ * requires a model once the adapter exists at all.
37
+ */
38
+ readonly prune?: boolean;
39
+ }
40
+ /**
41
+ * Applies every edit as one document mutation, or throws having written nothing.
42
+ *
43
+ * Validation runs against the serialized result rather than each edit, so a pair
44
+ * of edits only valid together is accepted, and a single edit that breaks an
45
+ * invariant elsewhere is still caught.
46
+ */
47
+ declare function writeDoomConfigValues(filePath: string, edits: readonly DoomConfigEdit[], options?: WriteDoomConfigOptions): Promise<void>;
48
+ declare function setDoomConfigValue(filePath: string, keyPath: readonly string[], value: string): Promise<void>;
49
+ declare function unsetDoomConfigValue(filePath: string, keyPath: readonly string[]): Promise<void>;
50
+ //#endregion
51
+ export { DoomConfigEdit, WriteDoomConfigOptions, setDoomConfigValue, unsetDoomConfigValue, writeDoomConfigValues };
52
+ //# sourceMappingURL=configWriter.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configWriter.d.cts","names":[],"sources":["../src/configWriter.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;UAkCiB;;WAEN;;WAEA;;UAGM;;;;;;WAMN;;;;;;;;;iBAmCW,sBACpB,kBACA,gBAAgB,kBAChB,UAAS,yBACR;iBAoCmB,mBAAmB,kBAAkB,4BAA4B,gBAAgB;iBAIjF,qBAAqB,kBAAkB,6BAA6B"}
@@ -0,0 +1,52 @@
1
+ //#region src/configWriter.d.ts
2
+ /**
3
+ * Writes into the global Doom config file, one key path at a time.
4
+ *
5
+ * Extracted from doom-file-edit, which owned the only writer in the repo and had
6
+ * it hard-coded to `editor.command`. Several extensions now edit their own
7
+ * settings from the config panel, and every one of them needs the same four
8
+ * properties: keep the user's comments, never publish a file the parser would
9
+ * reject, never leave a half-written file behind, and apply a set of related
10
+ * edits together.
11
+ *
12
+ * That last one is not a convenience. `voice.adapters.<engine>.model` accepts a
13
+ * path or an id but not both, so switching between them is a set and an unset
14
+ * that must land in the same write, or the file is briefly invalid.
15
+ *
16
+ * Atomicity is the same rename trick as `atomicJson.ts` next door, and carries
17
+ * the same caveat: it prevents torn reads, not lost updates. Two sessions with
18
+ * the panel open still clobber each other, because the rename only publishes
19
+ * what the caller already computed.
20
+ *
21
+ * AVOID:
22
+ * - Treating this as a lock
23
+ * - Writing an empty string; the parser rejects blank values, so clearing a key
24
+ * means removing it
25
+ */
26
+ interface DoomConfigEdit {
27
+ /** Key path into the document, e.g. `['voice', 'adapters', 'mlx-whisper', 'model', 'id']`. */
28
+ readonly keyPath: readonly string[];
29
+ /** The value to write. `undefined` removes the key. */
30
+ readonly value?: string;
31
+ }
32
+ interface WriteDoomConfigOptions {
33
+ /**
34
+ * Remove ancestors left holding nothing. Defaults to true, and is not
35
+ * cosmetic: an adapter left as `{}` fails validation, because the parser
36
+ * requires a model once the adapter exists at all.
37
+ */
38
+ readonly prune?: boolean;
39
+ }
40
+ /**
41
+ * Applies every edit as one document mutation, or throws having written nothing.
42
+ *
43
+ * Validation runs against the serialized result rather than each edit, so a pair
44
+ * of edits only valid together is accepted, and a single edit that breaks an
45
+ * invariant elsewhere is still caught.
46
+ */
47
+ declare function writeDoomConfigValues(filePath: string, edits: readonly DoomConfigEdit[], options?: WriteDoomConfigOptions): Promise<void>;
48
+ declare function setDoomConfigValue(filePath: string, keyPath: readonly string[], value: string): Promise<void>;
49
+ declare function unsetDoomConfigValue(filePath: string, keyPath: readonly string[]): Promise<void>;
50
+ //#endregion
51
+ export { DoomConfigEdit, WriteDoomConfigOptions, setDoomConfigValue, unsetDoomConfigValue, writeDoomConfigValues };
52
+ //# sourceMappingURL=configWriter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configWriter.d.mts","names":[],"sources":["../src/configWriter.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;UAkCiB;;WAEN;;WAEA;;UAGM;;;;;;WAMN;;;;;;;;;iBAmCW,sBACpB,kBACA,gBAAgB,kBAChB,UAAS,yBACR;iBAoCmB,mBAAmB,kBAAkB,4BAA4B,gBAAgB;iBAIjF,qBAAqB,kBAAkB,6BAA6B"}
@@ -0,0 +1,2 @@
1
+ import{parseDoomConfig as e}from"./config.mjs";import t from"node:path";import{parseDocument as n}from"yaml";import{randomUUID as r}from"node:crypto";import i from"node:fs/promises";async function a(e){try{return await i.readFile(e,`utf8`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return``;throw e}}function o(e){if(typeof e!=`object`||!e)return!1;let t=e.items;return Array.isArray(t)&&t.length===0}function s(e,t){for(let n=t.length-1;n>0;--n){let r=t.slice(0,n);if(e.hasIn(r)){if(!o(e.getIn(r,!0)))return;e.deleteIn(r)}}}async function c(o,c,l={}){if(c.length===0)return;let u=await a(o),d=n(u,{keepSourceTokens:!0});if(d.errors.length>0)throw Error(`Could not parse Doom config at ${o}`);for(let e of c){let t=[...e.keyPath];if(e.value!==void 0){d.setIn(t,e.value);continue}d.hasIn(t)&&(d.deleteIn(t),l.prune!==!1&&s(d,t))}let f=d.toString();e(f,o),await i.mkdir(t.dirname(o),{mode:448,recursive:!0});let p=`${o}.${process.pid}.${r()}.tmp`;try{await i.writeFile(p,f,{encoding:`utf8`,mode:384}),await i.rename(p,o)}catch(e){throw await i.rm(p,{force:!0}),e}}async function l(e,t,n){await c(e,[{keyPath:t,value:n}])}async function u(e,t){await c(e,[{keyPath:t}])}export{l as setDoomConfigValue,u as unsetDoomConfigValue,c as writeDoomConfigValues};
2
+ //# sourceMappingURL=configWriter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configWriter.mjs","names":[],"sources":["../src/configWriter.ts"],"sourcesContent":["/**\n * Writes into the global Doom config file, one key path at a time.\n *\n * Extracted from doom-file-edit, which owned the only writer in the repo and had\n * it hard-coded to `editor.command`. Several extensions now edit their own\n * settings from the config panel, and every one of them needs the same four\n * properties: keep the user's comments, never publish a file the parser would\n * reject, never leave a half-written file behind, and apply a set of related\n * edits together.\n *\n * That last one is not a convenience. `voice.adapters.<engine>.model` accepts a\n * path or an id but not both, so switching between them is a set and an unset\n * that must land in the same write, or the file is briefly invalid.\n *\n * Atomicity is the same rename trick as `atomicJson.ts` next door, and carries\n * the same caveat: it prevents torn reads, not lost updates. Two sessions with\n * the panel open still clobber each other, because the rename only publishes\n * what the caller already computed.\n *\n * AVOID:\n * - Treating this as a lock\n * - Writing an empty string; the parser rejects blank values, so clearing a key\n * means removing it\n */\n\nimport { randomUUID } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { parseDocument } from 'yaml';\nimport { parseDoomConfig } from './config.ts';\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\n\nexport interface DoomConfigEdit {\n /** Key path into the document, e.g. `['voice', 'adapters', 'mlx-whisper', 'model', 'id']`. */\n readonly keyPath: readonly string[];\n /** The value to write. `undefined` removes the key. */\n readonly value?: string;\n}\n\nexport interface WriteDoomConfigOptions {\n /**\n * Remove ancestors left holding nothing. Defaults to true, and is not\n * cosmetic: an adapter left as `{}` fails validation, because the parser\n * requires a model once the adapter exists at all.\n */\n readonly prune?: boolean;\n}\n\nasync function readIfPresent(filePath: string): Promise<string> {\n try {\n return await fs.readFile(filePath, 'utf8');\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return '';\n throw error;\n }\n}\n\nfunction isEmptyCollection(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false;\n const items = (value as { items?: unknown }).items;\n return Array.isArray(items) && items.length === 0;\n}\n\n/** Drops ancestors of a removed key that are now empty, deepest first. */\nfunction pruneEmptyAncestors(document: ReturnType<typeof parseDocument>, keyPath: readonly string[]): void {\n for (let depth = keyPath.length - 1; depth > 0; depth -= 1) {\n const ancestor = keyPath.slice(0, depth);\n if (!document.hasIn(ancestor)) continue;\n if (!isEmptyCollection(document.getIn(ancestor, true))) return;\n document.deleteIn(ancestor);\n }\n}\n\n/**\n * Applies every edit as one document mutation, or throws having written nothing.\n *\n * Validation runs against the serialized result rather than each edit, so a pair\n * of edits only valid together is accepted, and a single edit that breaks an\n * invariant elsewhere is still caught.\n */\nexport async function writeDoomConfigValues(\n filePath: string,\n edits: readonly DoomConfigEdit[],\n options: WriteDoomConfigOptions = {},\n): Promise<void> {\n if (edits.length === 0) return;\n const content = await readIfPresent(filePath);\n // Not `content || '{}\\n'`: seeding an absent file with a flow map makes yaml\n // keep that style, so the first write produces `{ editor: { command: ... } }`\n // and every later one grows that one line. An empty source starts a block map.\n const document = parseDocument(content, { keepSourceTokens: true });\n if (document.errors.length > 0) throw new Error(`Could not parse Doom config at ${filePath}`);\n\n for (const edit of edits) {\n const keyPath = [...edit.keyPath];\n if (edit.value !== undefined) {\n document.setIn(keyPath, edit.value);\n continue;\n }\n // deleteIn throws when an ancestor is missing rather than treating the key as\n // already absent, and clearing an unset key is worth supporting.\n if (!document.hasIn(keyPath)) continue;\n document.deleteIn(keyPath);\n if (options.prune !== false) pruneEmptyAncestors(document, keyPath);\n }\n\n const output = document.toString();\n parseDoomConfig(output, filePath);\n\n await fs.mkdir(path.dirname(filePath), { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await fs.writeFile(temporaryPath, output, { encoding: 'utf8', mode: PRIVATE_FILE_MODE });\n await fs.rename(temporaryPath, filePath);\n } catch (error) {\n await fs.rm(temporaryPath, { force: true });\n throw error;\n }\n}\n\nexport async function setDoomConfigValue(filePath: string, keyPath: readonly string[], value: string): Promise<void> {\n await writeDoomConfigValues(filePath, [{ keyPath, value }]);\n}\n\nexport async function unsetDoomConfigValue(filePath: string, keyPath: readonly string[]): Promise<void> {\n await writeDoomConfigValues(filePath, [{ keyPath }]);\n}\n"],"mappings":"sLAkDA,eAAe,EAAc,EAAmC,CAC9D,GAAI,CACF,OAAO,MAAM,EAAG,SAAS,EAAU,MAAM,CAC3C,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,SAAU,MAAO,GACjF,MAAM,CACR,CACF,CAEA,SAAS,EAAkB,EAAyB,CAClD,GAAsB,OAAO,GAAU,WAAnC,EAA6C,MAAO,GACxD,IAAM,EAAS,EAA8B,MAC7C,OAAO,MAAM,QAAQ,CAAK,GAAK,EAAM,SAAW,CAClD,CAGA,SAAS,EAAoB,EAA4C,EAAkC,CACzG,IAAK,IAAI,EAAQ,EAAQ,OAAS,EAAG,EAAQ,EAAG,IAAY,CAC1D,IAAM,EAAW,EAAQ,MAAM,EAAG,CAAK,EAClC,KAAS,MAAM,CAAQ,EAC5B,IAAI,CAAC,EAAkB,EAAS,MAAM,EAAU,EAAI,CAAC,EAAG,OACxD,EAAS,SAAS,CAAQ,CAD8B,CAE1D,CACF,CASA,eAAsB,EACpB,EACA,EACA,EAAkC,CAAC,EACpB,CACf,GAAI,EAAM,SAAW,EAAG,OACxB,IAAM,EAAU,MAAM,EAAc,CAAQ,EAItC,EAAW,EAAc,EAAS,CAAE,iBAAkB,EAAK,CAAC,EAClE,GAAI,EAAS,OAAO,OAAS,EAAG,MAAU,MAAM,kCAAkC,GAAU,EAE5F,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAU,CAAC,GAAG,EAAK,OAAO,EAChC,GAAI,EAAK,QAAU,IAAA,GAAW,CAC5B,EAAS,MAAM,EAAS,EAAK,KAAK,EAClC,QACF,CAGK,EAAS,MAAM,CAAO,IAC3B,EAAS,SAAS,CAAO,EACrB,EAAQ,QAAU,IAAO,EAAoB,EAAU,CAAO,EACpE,CAEA,IAAM,EAAS,EAAS,SAAS,EACjC,EAAgB,EAAQ,CAAQ,EAEhC,MAAM,EAAG,MAAM,EAAK,QAAQ,CAAQ,EAAG,CAAE,KAAM,IAAwB,UAAW,EAAK,CAAC,EACxF,IAAM,EAAgB,GAAG,EAAS,GAAG,QAAQ,IAAI,GAAG,EAAW,EAAE,MACjE,GAAI,CACF,MAAM,EAAG,UAAU,EAAe,EAAQ,CAAE,SAAU,OAAQ,KAAM,GAAkB,CAAC,EACvF,MAAM,EAAG,OAAO,EAAe,CAAQ,CACzC,OAAS,EAAO,CAEd,MADA,MAAM,EAAG,GAAG,EAAe,CAAE,MAAO,EAAK,CAAC,EACpC,CACR,CACF,CAEA,eAAsB,EAAmB,EAAkB,EAA4B,EAA8B,CACnH,MAAM,EAAsB,EAAU,CAAC,CAAE,UAAS,OAAM,CAAC,CAAC,CAC5D,CAEA,eAAsB,EAAqB,EAAkB,EAA2C,CACtG,MAAM,EAAsB,EAAU,CAAC,CAAE,SAAQ,CAAC,CAAC,CACrD"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./config.cjs"),t=require("./types.cjs"),n=require("./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.cjs");require("reflect-metadata");let r=require("inversify"),i=class{load(t,n){return e.loadDoomConfig(t,n)}};i=n.default([(0,r.injectable)()],i);function a(){return new r.ContainerModule(({bind:e})=>{e(t.DOOM_CONFIG_TYPES.ConfigService).to(i).inSingletonScope()})}function o(){let e=new r.Container;return e.bind(t.DOOM_CONFIG_TYPES.ConfigService).to(i).inSingletonScope(),e}Object.defineProperty(exports,"DoomConfigService",{enumerable:!0,get:function(){return i}}),exports.createDoomConfigContainer=o,exports.createDoomConfigModule=a;
2
+ //# sourceMappingURL=container.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.cjs","names":["loadDoomConfig","injectable","ContainerModule","DOOM_CONFIG_TYPES","Container"],"sources":["../src/container.ts"],"sourcesContent":["import 'reflect-metadata';\nimport { Container, ContainerModule, injectable } from 'inversify';\nimport { loadDoomConfig } from './config.ts';\nimport { DOOM_CONFIG_TYPES, type DoomConfig, type IDoomConfigService } from './types.ts';\n\n@injectable()\nexport class DoomConfigService implements IDoomConfigService {\n load(repoRoot: string, homeDirectory?: string): DoomConfig {\n return loadDoomConfig(repoRoot, homeDirectory);\n }\n}\nexport function createDoomConfigModule(): ContainerModule {\n return new ContainerModule(({ bind }) => {\n bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(DoomConfigService).inSingletonScope();\n });\n}\nexport function createDoomConfigContainer(): Container {\n const container = new Container();\n container.bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(DoomConfigService).inSingletonScope();\n return container;\n}\n"],"mappings":"kQAMa,EAAN,KAAsD,CAC3D,KAAK,EAAkB,EAAoC,CACzD,OAAOA,EAAAA,eAAe,EAAU,CAAa,CAC/C,CACF,EALCC,EAAAA,EAAAA,QAAAA,EAAAA,EAAAA,EAAAA,WAAAA,CAAW,CAAA,EAAA,CAAA,EAMZ,SAAgB,GAA0C,CACxD,OAAO,IAAIC,EAAAA,iBAAiB,CAAE,UAAW,CACvC,EAAyBC,EAAAA,kBAAkB,aAAa,CAAC,CAAC,GAAG,CAAiB,CAAC,CAAC,iBAAiB,CACnG,CAAC,CACH,CACA,SAAgB,GAAuC,CACrD,IAAM,EAAY,IAAIC,EAAAA,UAEtB,OADA,EAAU,KAAyBD,EAAAA,kBAAkB,aAAa,CAAC,CAAC,GAAG,CAAiB,CAAC,CAAC,iBAAiB,EACpG,CACT"}
@@ -0,0 +1,12 @@
1
+ import { DoomConfig, IDoomConfigService } from "./types.cjs";
2
+ import "reflect-metadata";
3
+ import { Container, ContainerModule } from "inversify";
4
+ //#region src/container.d.ts
5
+ declare class DoomConfigService implements IDoomConfigService {
6
+ load(repoRoot: string, homeDirectory?: string): DoomConfig;
7
+ }
8
+ declare function createDoomConfigModule(): ContainerModule;
9
+ declare function createDoomConfigContainer(): Container;
10
+ //#endregion
11
+ export { DoomConfigService, createDoomConfigContainer, createDoomConfigModule };
12
+ //# sourceMappingURL=container.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.d.cts","names":[],"sources":["../src/container.ts"],"mappings":";;;;cAMa,6BAA6B;EACxC,KAAK,kBAAkB,yBAAyB;;iBAIlC,0BAA0B;iBAK1B,6BAA6B"}
@@ -0,0 +1,12 @@
1
+ import { DoomConfig, IDoomConfigService } from "./types.mjs";
2
+ import "reflect-metadata";
3
+ import { Container, ContainerModule } from "inversify";
4
+ //#region src/container.d.ts
5
+ declare class DoomConfigService implements IDoomConfigService {
6
+ load(repoRoot: string, homeDirectory?: string): DoomConfig;
7
+ }
8
+ declare function createDoomConfigModule(): ContainerModule;
9
+ declare function createDoomConfigContainer(): Container;
10
+ //#endregion
11
+ export { DoomConfigService, createDoomConfigContainer, createDoomConfigModule };
12
+ //# sourceMappingURL=container.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.d.mts","names":[],"sources":["../src/container.ts"],"mappings":";;;;cAMa,6BAA6B;EACxC,KAAK,kBAAkB,yBAAyB;;iBAIlC,0BAA0B;iBAK1B,6BAA6B"}
@@ -0,0 +1,2 @@
1
+ import{loadDoomConfig as e}from"./config.mjs";import{DOOM_CONFIG_TYPES as t}from"./types.mjs";import n from"./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.mjs";import"reflect-metadata";import{Container as r,ContainerModule as i,injectable as a}from"inversify";let o=class{load(t,n){return e(t,n)}};o=n([a()],o);function s(){return new i(({bind:e})=>{e(t.ConfigService).to(o).inSingletonScope()})}function c(){let e=new r;return e.bind(t.ConfigService).to(o).inSingletonScope(),e}export{o as DoomConfigService,c as createDoomConfigContainer,s as createDoomConfigModule};
2
+ //# sourceMappingURL=container.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.mjs","names":[],"sources":["../src/container.ts"],"sourcesContent":["import 'reflect-metadata';\nimport { Container, ContainerModule, injectable } from 'inversify';\nimport { loadDoomConfig } from './config.ts';\nimport { DOOM_CONFIG_TYPES, type DoomConfig, type IDoomConfigService } from './types.ts';\n\n@injectable()\nexport class DoomConfigService implements IDoomConfigService {\n load(repoRoot: string, homeDirectory?: string): DoomConfig {\n return loadDoomConfig(repoRoot, homeDirectory);\n }\n}\nexport function createDoomConfigModule(): ContainerModule {\n return new ContainerModule(({ bind }) => {\n bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(DoomConfigService).inSingletonScope();\n });\n}\nexport function createDoomConfigContainer(): Container {\n const container = new Container();\n container.bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(DoomConfigService).inSingletonScope();\n return container;\n}\n"],"mappings":"mRAMO,IAAM,EAAN,KAAsD,CAC3D,KAAK,EAAkB,EAAoC,CACzD,OAAO,EAAe,EAAU,CAAa,CAC/C,CACF,EALC,EAAA,EAAA,CAAA,EAAW,CAAA,EAAA,CAAA,EAMZ,SAAgB,GAA0C,CACxD,OAAO,IAAI,GAAiB,CAAE,UAAW,CACvC,EAAyB,EAAkB,aAAa,CAAC,CAAC,GAAG,CAAiB,CAAC,CAAC,iBAAiB,CACnG,CAAC,CACH,CACA,SAAgB,GAAuC,CACrD,IAAM,EAAY,IAAI,EAEtB,OADA,EAAU,KAAyB,EAAkB,aAAa,CAAC,CAAC,GAAG,CAAiB,CAAC,CAAC,iBAAiB,EACpG,CACT"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_virtual/_rolldown/runtime.cjs"),t=require("./layeredConfig.cjs");let n=require("node:fs");n=e.__toESM(n,1);let r=require("node:os");r=e.__toESM(r,1);let i=require("node:path");i=e.__toESM(i,1);function a(e,n=r.default.homedir()){let i=t.readDoomConfigSources(`domains.yaml`,e,n),a={};for(let e of i)Object.assign(a,e.document.aliases??{});return{domains:t.mergeNamedSources(i,e=>e.domains),aliases:a}}function o(e,t){let n=a(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function s(e,t){return t.flatMap(e=>e.split(`,`).map(e=>e.trim()).filter(Boolean)).flatMap(t=>e.aliases[t]??[t])}function c(e){return e.match(/^\/domains\s+(?:[^\s,]+,)*([^\s,]*)$/)?.[1]}function l(e,t){let n=t.toLowerCase();return e.filter(e=>e.toLowerCase().startsWith(n)).map(e=>({value:e,label:e}))}function u(e,t,n){let r=a(e,n),i=s(r,t);return i.length===0||i.some(e=>r.domains[e]?.sharedSkills!==!1)}function d(e,t,r,o){let c=a(e,o),l=[],u=new Set;for(let e of s(c,t)){let t=c.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let e of t.plugins??[]){let r=typeof e!=`string`,a=i.default.resolve(t.baseDirectory,r?e.dir:e);if(!n.default.existsSync(a))throw Error(`Domain plugin does not exist: ${a}`);u.has(a)||(u.add(a),l.push(r?{directory:a,skills:e.skills,agents:e.agents,hooks:e.hooks,mcp:e.mcp}:{directory:a}))}}for(let e of r){if(!n.default.existsSync(e))throw Error(`Plugin directory does not exist: ${e}`);let t=i.default.resolve(e);u.has(t)||(u.add(t),l.push({directory:t}))}return l}function f(e,t,n,r){return d(e,t,n,r).map(e=>e.directory)}exports.DOOM_DIR=t.DOOM_DIR,exports.domainCompletionItems=l,exports.domainCompletionPrefix=c,exports.expandDomainNames=s,exports.listDomainNames=o,exports.loadDomains=a,exports.resolvePluginDirectories=f,exports.resolvePluginEntries=d,exports.resolveSharedSkills=u;
2
+ //# sourceMappingURL=domains.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.cjs","names":["os","readDoomConfigSources","mergeNamedSources","path","fs"],"sources":["../src/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { mergeNamedSources, readDoomConfigSources } from './layeredConfig.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\n/** A plugin entry is a whole plugin dir, or a subset of one. */\nexport type DomainPlugin =\n | string\n | { dir: string; skills?: string[]; agents?: string[]; hooks?: boolean; mcp?: boolean };\n\nexport interface DomainMcpAllowlist {\n /** Server names kept from the repo-level .mcp.json. */\n servers?: string[];\n /** Upstream server names kept in the agiflow-proxy config. */\n proxy?: string[];\n}\n\nexport interface DomainDefinition {\n /**\n * Plugin directories, each one relative to the config that declares it: the\n * repository root for `.doom/domains.yaml`, the global `.doom` directory for\n * `~/.pi/.doom/domains.yaml`. The path is written out in full, so a plugin\n * does not have to live under `plugins/`.\n */\n plugins?: DomainPlugin[];\n mcp?: DomainMcpAllowlist;\n /** Prepend .claude/skills. Defaults to true. */\n sharedSkills?: boolean;\n}\n\n/** A domain plus the root its plugin paths resolve against. */\nexport interface ResolvedDomain extends DomainDefinition {\n baseDirectory: string;\n}\n\nexport interface DomainManifest {\n domains: Record<string, ResolvedDomain>;\n aliases: Record<string, string[]>;\n}\n\ninterface DomainDocument {\n domains?: Record<string, DomainDefinition>;\n aliases?: Record<string, string[]>;\n}\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst MISSING_DOMAIN_PLUGIN_ERROR = 'Domain plugin does not exist';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst NAME_DELIMITER = ',';\n\n/**\n * Reads domains from the global and repository configs, repository last.\n *\n * Either file alone is a complete manifest. A repository domain replaces the\n * global domain of the same name outright, so a machine-wide default can be\n * inherited everywhere and overridden where a repository disagrees.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<DomainDocument>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n for (const source of sources) Object.assign(aliases, source.document.aliases ?? {});\n return { domains: mergeNamedSources(sources, (document) => document.domains), aliases };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/** Splits comma-joined selections and expands aliases into concrete domain names. */\nexport function expandDomainNames(manifest: DomainManifest, domainNames: readonly string[]): string[] {\n return domainNames\n .flatMap((raw) =>\n raw\n .split(NAME_DELIMITER)\n .map((name) => name.trim())\n .filter(Boolean),\n )\n .flatMap((name) => manifest.aliases[name] ?? [name]);\n}\n\nexport function domainCompletionPrefix(textBeforeCursor: string): string | undefined {\n const match = textBeforeCursor.match(/^\\/domains\\s+(?:[^\\s,]+,)*([^\\s,]*)$/);\n return match?.[1];\n}\n\nexport function domainCompletionItems(domainNames: string[], query: string): Array<{ value: string; label: string }> {\n const normalizedQuery = query.toLowerCase();\n return domainNames\n .filter((name) => name.toLowerCase().startsWith(normalizedQuery))\n .map((name) => ({ value: name, label: name }));\n}\n\n/** A resolved plugin directory plus any subset filter the domain applied. */\nexport interface PluginEntry {\n directory: string;\n /** Skill names to keep. Omit to keep every skill in the plugin. */\n skills?: string[];\n /** Agent names to keep. Omit to keep every agent in the plugin. */\n agents?: string[];\n hooks?: boolean;\n mcp?: boolean;\n}\n\n/**\n * Whether to prepend .claude/skills.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves domains to plugin entries, preserving each plugin's subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n\n for (const name of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[name];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${name}`);\n for (const plugin of domain.plugins ?? []) {\n const isSubset = typeof plugin !== 'string';\n const directory = path.resolve(domain.baseDirectory, isSubset ? plugin.dir : plugin);\n if (!fs.existsSync(directory)) throw new Error(`${MISSING_DOMAIN_PLUGIN_ERROR}: ${directory}`);\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push(\n isSubset\n ? { directory, skills: plugin.skills, agents: plugin.agents, hooks: plugin.hooks, mcp: plugin.mcp }\n : { directory },\n );\n }\n }\n\n for (const directory of explicitDirectories) {\n if (!fs.existsSync(directory)) throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n const resolved = path.resolve(directory);\n if (seen.has(resolved)) continue;\n seen.add(resolved);\n entries.push({ directory: resolved });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n"],"mappings":"wRA4DA,SAAgB,EAAY,EAAkB,EAAwBA,EAAAA,QAAG,QAAQ,EAAmB,CAClG,IAAM,EAAUC,EAAAA,sBAAsC,eAAc,EAAU,CAAa,EACrF,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAU,EAAS,OAAO,OAAO,EAAS,EAAO,SAAS,SAAW,CAAC,CAAC,EAClF,MAAO,CAAE,QAASC,EAAAA,kBAAkB,EAAU,GAAa,EAAS,OAAO,EAAG,SAAQ,CACxF,CAEA,SAAgB,EAAgB,EAAkB,EAAkC,CAClF,IAAM,EAAW,EAAY,EAAU,CAAa,EACpD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAS,OAAO,EAAG,GAAG,OAAO,KAAK,EAAS,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CACjG,CAGA,SAAgB,EAAkB,EAA0B,EAA0C,CACpG,OAAO,EACJ,QAAS,GACR,EACG,MAAM,GAAc,CAAC,CACrB,IAAK,GAAS,EAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,CACnB,CAAC,CACA,QAAS,GAAS,EAAS,QAAQ,IAAS,CAAC,CAAI,CAAC,CACvD,CAEA,SAAgB,EAAuB,EAA8C,CAEnF,OADc,EAAiB,MAAM,sCAC1B,CAAC,GAAG,EACjB,CAEA,SAAgB,EAAsB,EAAuB,EAAwD,CACnH,IAAM,EAAkB,EAAM,YAAY,EAC1C,OAAO,EACJ,OAAQ,GAAS,EAAK,YAAY,CAAC,CAAC,WAAW,CAAe,CAAC,CAAC,CAChE,IAAK,IAAU,CAAE,MAAO,EAAM,MAAO,CAAK,EAAE,CACjD,CAmBA,SAAgB,EAAoB,EAAkB,EAAuB,EAAiC,CAC5G,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAW,EAAkB,EAAU,CAAW,EAExD,OADI,EAAS,SAAW,GACjB,EAAS,KAAM,GAAS,EAAS,QAAQ,EAAK,EAAE,eAAiB,EAAK,CAC/E,CAGA,SAAgB,EACd,EACA,EACA,EACA,EACe,CACf,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAyB,CAAC,EAC1B,EAAO,IAAI,IAEjB,IAAK,IAAM,KAAQ,EAAkB,EAAU,CAAW,EAAG,CAC3D,IAAM,EAAS,EAAS,QAAQ,GAChC,GAAI,CAAC,EAAQ,MAAU,MAAM,mBAA4B,GAAM,EAC/D,IAAK,IAAM,KAAU,EAAO,SAAW,CAAC,EAAG,CACzC,IAAM,EAAW,OAAO,GAAW,SAC7B,EAAYC,EAAAA,QAAK,QAAQ,EAAO,cAAe,EAAW,EAAO,IAAM,CAAM,EACnF,GAAI,CAACC,EAAAA,QAAG,WAAW,CAAS,EAAG,MAAU,MAAM,iCAAmC,GAAW,EACzF,EAAK,IAAI,CAAS,IACtB,EAAK,IAAI,CAAS,EAClB,EAAQ,KACN,EACI,CAAE,YAAW,OAAQ,EAAO,OAAQ,OAAQ,EAAO,OAAQ,MAAO,EAAO,MAAO,IAAK,EAAO,GAAI,EAChG,CAAE,WAAU,CAClB,EACF,CACF,CAEA,IAAK,IAAM,KAAa,EAAqB,CAC3C,GAAI,CAACA,EAAAA,QAAG,WAAW,CAAS,EAAG,MAAU,MAAM,oCAAsC,GAAW,EAChG,IAAM,EAAWD,EAAAA,QAAK,QAAQ,CAAS,EACnC,EAAK,IAAI,CAAQ,IACrB,EAAK,IAAI,CAAQ,EACjB,EAAQ,KAAK,CAAE,UAAW,CAAS,CAAC,EACtC,CACA,OAAO,CACT,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACU,CACV,OAAO,EAAqB,EAAU,EAAa,EAAqB,CAAa,CAAC,CAAC,IACpF,GAAU,EAAM,SACnB,CACF"}
@@ -0,0 +1,75 @@
1
+ import { DOOM_DIR } from "./layeredConfig.cjs";
2
+ //#region src/domains.d.ts
3
+ /** A plugin entry is a whole plugin dir, or a subset of one. */
4
+ type DomainPlugin = string | {
5
+ dir: string;
6
+ skills?: string[];
7
+ agents?: string[];
8
+ hooks?: boolean;
9
+ mcp?: boolean;
10
+ };
11
+ interface DomainMcpAllowlist {
12
+ /** Server names kept from the repo-level .mcp.json. */
13
+ servers?: string[];
14
+ /** Upstream server names kept in the agiflow-proxy config. */
15
+ proxy?: string[];
16
+ }
17
+ interface DomainDefinition {
18
+ /**
19
+ * Plugin directories, each one relative to the config that declares it: the
20
+ * repository root for `.doom/domains.yaml`, the global `.doom` directory for
21
+ * `~/.pi/.doom/domains.yaml`. The path is written out in full, so a plugin
22
+ * does not have to live under `plugins/`.
23
+ */
24
+ plugins?: DomainPlugin[];
25
+ mcp?: DomainMcpAllowlist;
26
+ /** Prepend .claude/skills. Defaults to true. */
27
+ sharedSkills?: boolean;
28
+ }
29
+ /** A domain plus the root its plugin paths resolve against. */
30
+ interface ResolvedDomain extends DomainDefinition {
31
+ baseDirectory: string;
32
+ }
33
+ interface DomainManifest {
34
+ domains: Record<string, ResolvedDomain>;
35
+ aliases: Record<string, string[]>;
36
+ }
37
+ /**
38
+ * Reads domains from the global and repository configs, repository last.
39
+ *
40
+ * Either file alone is a complete manifest. A repository domain replaces the
41
+ * global domain of the same name outright, so a machine-wide default can be
42
+ * inherited everywhere and overridden where a repository disagrees.
43
+ */
44
+ declare function loadDomains(repoRoot: string, homeDirectory?: string): DomainManifest;
45
+ declare function listDomainNames(repoRoot: string, homeDirectory?: string): string[];
46
+ /** Splits comma-joined selections and expands aliases into concrete domain names. */
47
+ declare function expandDomainNames(manifest: DomainManifest, domainNames: readonly string[]): string[];
48
+ declare function domainCompletionPrefix(textBeforeCursor: string): string | undefined;
49
+ declare function domainCompletionItems(domainNames: string[], query: string): Array<{
50
+ value: string;
51
+ label: string;
52
+ }>;
53
+ /** A resolved plugin directory plus any subset filter the domain applied. */
54
+ interface PluginEntry {
55
+ directory: string;
56
+ /** Skill names to keep. Omit to keep every skill in the plugin. */
57
+ skills?: string[];
58
+ /** Agent names to keep. Omit to keep every agent in the plugin. */
59
+ agents?: string[];
60
+ hooks?: boolean;
61
+ mcp?: boolean;
62
+ }
63
+ /**
64
+ * Whether to prepend .claude/skills.
65
+ *
66
+ * Shared skills are included unless every selected domain opts out, so mixing a
67
+ * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.
68
+ */
69
+ declare function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean;
70
+ /** Resolves domains to plugin entries, preserving each plugin's subset filter. */
71
+ declare function resolvePluginEntries(repoRoot: string, domainNames: string[], explicitDirectories: string[], homeDirectory?: string): PluginEntry[];
72
+ declare function resolvePluginDirectories(repoRoot: string, domainNames: string[], explicitDirectories: string[], homeDirectory?: string): string[];
73
+ //#endregion
74
+ export { DOOM_DIR, DomainDefinition, DomainManifest, DomainMcpAllowlist, DomainPlugin, PluginEntry, ResolvedDomain, domainCompletionItems, domainCompletionPrefix, expandDomainNames, listDomainNames, loadDomains, resolvePluginDirectories, resolvePluginEntries, resolveSharedSkills };
75
+ //# sourceMappingURL=domains.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.d.cts","names":[],"sources":["../src/domains.ts"],"mappings":";;;KAQY;EAEN;EAAa;EAAmB;EAAmB;EAAiB;;UAEzD;;EAEf;;EAEA;;UAGe;;;;;;;EAOf,UAAU;EACV,MAAM;;EAEN;;;UAIe,uBAAuB;EACtC;;UAGe;EACf,SAAS,eAAe;EACxB,SAAS;;;;;;;;;iBAqBK,YAAY,kBAAkB,yBAAuC;iBAOrE,gBAAgB,kBAAkB;;iBAMlC,kBAAkB,UAAU,gBAAgB;iBAW5C,uBAAuB;iBAKvB,sBAAsB,uBAAuB,gBAAgB;EAAQ;EAAe;;;UAQnF;EACf;;EAEA;;EAEA;EACA;EACA;;;;;;;;iBASc,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAgCa,yBACd,kBACA,uBACA,+BACA"}
@@ -0,0 +1,75 @@
1
+ import { DOOM_DIR } from "./layeredConfig.mjs";
2
+ //#region src/domains.d.ts
3
+ /** A plugin entry is a whole plugin dir, or a subset of one. */
4
+ type DomainPlugin = string | {
5
+ dir: string;
6
+ skills?: string[];
7
+ agents?: string[];
8
+ hooks?: boolean;
9
+ mcp?: boolean;
10
+ };
11
+ interface DomainMcpAllowlist {
12
+ /** Server names kept from the repo-level .mcp.json. */
13
+ servers?: string[];
14
+ /** Upstream server names kept in the agiflow-proxy config. */
15
+ proxy?: string[];
16
+ }
17
+ interface DomainDefinition {
18
+ /**
19
+ * Plugin directories, each one relative to the config that declares it: the
20
+ * repository root for `.doom/domains.yaml`, the global `.doom` directory for
21
+ * `~/.pi/.doom/domains.yaml`. The path is written out in full, so a plugin
22
+ * does not have to live under `plugins/`.
23
+ */
24
+ plugins?: DomainPlugin[];
25
+ mcp?: DomainMcpAllowlist;
26
+ /** Prepend .claude/skills. Defaults to true. */
27
+ sharedSkills?: boolean;
28
+ }
29
+ /** A domain plus the root its plugin paths resolve against. */
30
+ interface ResolvedDomain extends DomainDefinition {
31
+ baseDirectory: string;
32
+ }
33
+ interface DomainManifest {
34
+ domains: Record<string, ResolvedDomain>;
35
+ aliases: Record<string, string[]>;
36
+ }
37
+ /**
38
+ * Reads domains from the global and repository configs, repository last.
39
+ *
40
+ * Either file alone is a complete manifest. A repository domain replaces the
41
+ * global domain of the same name outright, so a machine-wide default can be
42
+ * inherited everywhere and overridden where a repository disagrees.
43
+ */
44
+ declare function loadDomains(repoRoot: string, homeDirectory?: string): DomainManifest;
45
+ declare function listDomainNames(repoRoot: string, homeDirectory?: string): string[];
46
+ /** Splits comma-joined selections and expands aliases into concrete domain names. */
47
+ declare function expandDomainNames(manifest: DomainManifest, domainNames: readonly string[]): string[];
48
+ declare function domainCompletionPrefix(textBeforeCursor: string): string | undefined;
49
+ declare function domainCompletionItems(domainNames: string[], query: string): Array<{
50
+ value: string;
51
+ label: string;
52
+ }>;
53
+ /** A resolved plugin directory plus any subset filter the domain applied. */
54
+ interface PluginEntry {
55
+ directory: string;
56
+ /** Skill names to keep. Omit to keep every skill in the plugin. */
57
+ skills?: string[];
58
+ /** Agent names to keep. Omit to keep every agent in the plugin. */
59
+ agents?: string[];
60
+ hooks?: boolean;
61
+ mcp?: boolean;
62
+ }
63
+ /**
64
+ * Whether to prepend .claude/skills.
65
+ *
66
+ * Shared skills are included unless every selected domain opts out, so mixing a
67
+ * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.
68
+ */
69
+ declare function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean;
70
+ /** Resolves domains to plugin entries, preserving each plugin's subset filter. */
71
+ declare function resolvePluginEntries(repoRoot: string, domainNames: string[], explicitDirectories: string[], homeDirectory?: string): PluginEntry[];
72
+ declare function resolvePluginDirectories(repoRoot: string, domainNames: string[], explicitDirectories: string[], homeDirectory?: string): string[];
73
+ //#endregion
74
+ export { DOOM_DIR, DomainDefinition, DomainManifest, DomainMcpAllowlist, DomainPlugin, PluginEntry, ResolvedDomain, domainCompletionItems, domainCompletionPrefix, expandDomainNames, listDomainNames, loadDomains, resolvePluginDirectories, resolvePluginEntries, resolveSharedSkills };
75
+ //# sourceMappingURL=domains.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.d.mts","names":[],"sources":["../src/domains.ts"],"mappings":";;;KAQY;EAEN;EAAa;EAAmB;EAAmB;EAAiB;;UAEzD;;EAEf;;EAEA;;UAGe;;;;;;;EAOf,UAAU;EACV,MAAM;;EAEN;;;UAIe,uBAAuB;EACtC;;UAGe;EACf,SAAS,eAAe;EACxB,SAAS;;;;;;;;;iBAqBK,YAAY,kBAAkB,yBAAuC;iBAOrE,gBAAgB,kBAAkB;;iBAMlC,kBAAkB,UAAU,gBAAgB;iBAW5C,uBAAuB;iBAKvB,sBAAsB,uBAAuB,gBAAgB;EAAQ;EAAe;;;UAQnF;EACf;;EAEA;;EAEA;EACA;EACA;;;;;;;;iBASc,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAgCa,yBACd,kBACA,uBACA,+BACA"}
@@ -0,0 +1,2 @@
1
+ import{DOOM_DIR as e,mergeNamedSources as t,readDoomConfigSources as n}from"./layeredConfig.mjs";import r from"node:fs";import i from"node:os";import a from"node:path";function o(e,r=i.homedir()){let a=n(`domains.yaml`,e,r),o={};for(let e of a)Object.assign(o,e.document.aliases??{});return{domains:t(a,e=>e.domains),aliases:o}}function s(e,t){let n=o(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function c(e,t){return t.flatMap(e=>e.split(`,`).map(e=>e.trim()).filter(Boolean)).flatMap(t=>e.aliases[t]??[t])}function l(e){return e.match(/^\/domains\s+(?:[^\s,]+,)*([^\s,]*)$/)?.[1]}function u(e,t){let n=t.toLowerCase();return e.filter(e=>e.toLowerCase().startsWith(n)).map(e=>({value:e,label:e}))}function d(e,t,n){let r=o(e,n),i=c(r,t);return i.length===0||i.some(e=>r.domains[e]?.sharedSkills!==!1)}function f(e,t,n,i){let s=o(e,i),l=[],u=new Set;for(let e of c(s,t)){let t=s.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let e of t.plugins??[]){let n=typeof e!=`string`,i=a.resolve(t.baseDirectory,n?e.dir:e);if(!r.existsSync(i))throw Error(`Domain plugin does not exist: ${i}`);u.has(i)||(u.add(i),l.push(n?{directory:i,skills:e.skills,agents:e.agents,hooks:e.hooks,mcp:e.mcp}:{directory:i}))}}for(let e of n){if(!r.existsSync(e))throw Error(`Plugin directory does not exist: ${e}`);let t=a.resolve(e);u.has(t)||(u.add(t),l.push({directory:t}))}return l}function p(e,t,n,r){return f(e,t,n,r).map(e=>e.directory)}export{e as DOOM_DIR,u as domainCompletionItems,l as domainCompletionPrefix,c as expandDomainNames,s as listDomainNames,o as loadDomains,p as resolvePluginDirectories,f as resolvePluginEntries,d as resolveSharedSkills};
2
+ //# sourceMappingURL=domains.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.mjs","names":[],"sources":["../src/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { mergeNamedSources, readDoomConfigSources } from './layeredConfig.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\n/** A plugin entry is a whole plugin dir, or a subset of one. */\nexport type DomainPlugin =\n | string\n | { dir: string; skills?: string[]; agents?: string[]; hooks?: boolean; mcp?: boolean };\n\nexport interface DomainMcpAllowlist {\n /** Server names kept from the repo-level .mcp.json. */\n servers?: string[];\n /** Upstream server names kept in the agiflow-proxy config. */\n proxy?: string[];\n}\n\nexport interface DomainDefinition {\n /**\n * Plugin directories, each one relative to the config that declares it: the\n * repository root for `.doom/domains.yaml`, the global `.doom` directory for\n * `~/.pi/.doom/domains.yaml`. The path is written out in full, so a plugin\n * does not have to live under `plugins/`.\n */\n plugins?: DomainPlugin[];\n mcp?: DomainMcpAllowlist;\n /** Prepend .claude/skills. Defaults to true. */\n sharedSkills?: boolean;\n}\n\n/** A domain plus the root its plugin paths resolve against. */\nexport interface ResolvedDomain extends DomainDefinition {\n baseDirectory: string;\n}\n\nexport interface DomainManifest {\n domains: Record<string, ResolvedDomain>;\n aliases: Record<string, string[]>;\n}\n\ninterface DomainDocument {\n domains?: Record<string, DomainDefinition>;\n aliases?: Record<string, string[]>;\n}\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst MISSING_DOMAIN_PLUGIN_ERROR = 'Domain plugin does not exist';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst NAME_DELIMITER = ',';\n\n/**\n * Reads domains from the global and repository configs, repository last.\n *\n * Either file alone is a complete manifest. A repository domain replaces the\n * global domain of the same name outright, so a machine-wide default can be\n * inherited everywhere and overridden where a repository disagrees.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<DomainDocument>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n for (const source of sources) Object.assign(aliases, source.document.aliases ?? {});\n return { domains: mergeNamedSources(sources, (document) => document.domains), aliases };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/** Splits comma-joined selections and expands aliases into concrete domain names. */\nexport function expandDomainNames(manifest: DomainManifest, domainNames: readonly string[]): string[] {\n return domainNames\n .flatMap((raw) =>\n raw\n .split(NAME_DELIMITER)\n .map((name) => name.trim())\n .filter(Boolean),\n )\n .flatMap((name) => manifest.aliases[name] ?? [name]);\n}\n\nexport function domainCompletionPrefix(textBeforeCursor: string): string | undefined {\n const match = textBeforeCursor.match(/^\\/domains\\s+(?:[^\\s,]+,)*([^\\s,]*)$/);\n return match?.[1];\n}\n\nexport function domainCompletionItems(domainNames: string[], query: string): Array<{ value: string; label: string }> {\n const normalizedQuery = query.toLowerCase();\n return domainNames\n .filter((name) => name.toLowerCase().startsWith(normalizedQuery))\n .map((name) => ({ value: name, label: name }));\n}\n\n/** A resolved plugin directory plus any subset filter the domain applied. */\nexport interface PluginEntry {\n directory: string;\n /** Skill names to keep. Omit to keep every skill in the plugin. */\n skills?: string[];\n /** Agent names to keep. Omit to keep every agent in the plugin. */\n agents?: string[];\n hooks?: boolean;\n mcp?: boolean;\n}\n\n/**\n * Whether to prepend .claude/skills.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves domains to plugin entries, preserving each plugin's subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n\n for (const name of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[name];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${name}`);\n for (const plugin of domain.plugins ?? []) {\n const isSubset = typeof plugin !== 'string';\n const directory = path.resolve(domain.baseDirectory, isSubset ? plugin.dir : plugin);\n if (!fs.existsSync(directory)) throw new Error(`${MISSING_DOMAIN_PLUGIN_ERROR}: ${directory}`);\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push(\n isSubset\n ? { directory, skills: plugin.skills, agents: plugin.agents, hooks: plugin.hooks, mcp: plugin.mcp }\n : { directory },\n );\n }\n }\n\n for (const directory of explicitDirectories) {\n if (!fs.existsSync(directory)) throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n const resolved = path.resolve(directory);\n if (seen.has(resolved)) continue;\n seen.add(resolved);\n entries.push({ directory: resolved });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n"],"mappings":"wKA4DA,SAAgB,EAAY,EAAkB,EAAwB,EAAG,QAAQ,EAAmB,CAClG,IAAM,EAAU,EAAsC,eAAc,EAAU,CAAa,EACrF,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAU,EAAS,OAAO,OAAO,EAAS,EAAO,SAAS,SAAW,CAAC,CAAC,EAClF,MAAO,CAAE,QAAS,EAAkB,EAAU,GAAa,EAAS,OAAO,EAAG,SAAQ,CACxF,CAEA,SAAgB,EAAgB,EAAkB,EAAkC,CAClF,IAAM,EAAW,EAAY,EAAU,CAAa,EACpD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAS,OAAO,EAAG,GAAG,OAAO,KAAK,EAAS,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CACjG,CAGA,SAAgB,EAAkB,EAA0B,EAA0C,CACpG,OAAO,EACJ,QAAS,GACR,EACG,MAAM,GAAc,CAAC,CACrB,IAAK,GAAS,EAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,CACnB,CAAC,CACA,QAAS,GAAS,EAAS,QAAQ,IAAS,CAAC,CAAI,CAAC,CACvD,CAEA,SAAgB,EAAuB,EAA8C,CAEnF,OADc,EAAiB,MAAM,sCAC1B,CAAC,GAAG,EACjB,CAEA,SAAgB,EAAsB,EAAuB,EAAwD,CACnH,IAAM,EAAkB,EAAM,YAAY,EAC1C,OAAO,EACJ,OAAQ,GAAS,EAAK,YAAY,CAAC,CAAC,WAAW,CAAe,CAAC,CAAC,CAChE,IAAK,IAAU,CAAE,MAAO,EAAM,MAAO,CAAK,EAAE,CACjD,CAmBA,SAAgB,EAAoB,EAAkB,EAAuB,EAAiC,CAC5G,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAW,EAAkB,EAAU,CAAW,EAExD,OADI,EAAS,SAAW,GACjB,EAAS,KAAM,GAAS,EAAS,QAAQ,EAAK,EAAE,eAAiB,EAAK,CAC/E,CAGA,SAAgB,EACd,EACA,EACA,EACA,EACe,CACf,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAyB,CAAC,EAC1B,EAAO,IAAI,IAEjB,IAAK,IAAM,KAAQ,EAAkB,EAAU,CAAW,EAAG,CAC3D,IAAM,EAAS,EAAS,QAAQ,GAChC,GAAI,CAAC,EAAQ,MAAU,MAAM,mBAA4B,GAAM,EAC/D,IAAK,IAAM,KAAU,EAAO,SAAW,CAAC,EAAG,CACzC,IAAM,EAAW,OAAO,GAAW,SAC7B,EAAY,EAAK,QAAQ,EAAO,cAAe,EAAW,EAAO,IAAM,CAAM,EACnF,GAAI,CAAC,EAAG,WAAW,CAAS,EAAG,MAAU,MAAM,iCAAmC,GAAW,EACzF,EAAK,IAAI,CAAS,IACtB,EAAK,IAAI,CAAS,EAClB,EAAQ,KACN,EACI,CAAE,YAAW,OAAQ,EAAO,OAAQ,OAAQ,EAAO,OAAQ,MAAO,EAAO,MAAO,IAAK,EAAO,GAAI,EAChG,CAAE,WAAU,CAClB,EACF,CACF,CAEA,IAAK,IAAM,KAAa,EAAqB,CAC3C,GAAI,CAAC,EAAG,WAAW,CAAS,EAAG,MAAU,MAAM,oCAAsC,GAAW,EAChG,IAAM,EAAW,EAAK,QAAQ,CAAS,EACnC,EAAK,IAAI,CAAQ,IACrB,EAAK,IAAI,CAAQ,EACjB,EAAQ,KAAK,CAAE,UAAW,CAAS,CAAC,EACtC,CACA,OAAO,CACT,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACU,CACV,OAAO,EAAqB,EAAU,EAAa,EAAqB,CAAa,CAAC,CAAC,IACpF,GAAU,EAAM,SACnB,CACF"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../config.cjs"),t=require("../config/piConfig.cjs"),n=new WeakSet,r=new WeakMap;function i(e){return r.get(e)}function a(i,a={}){if(n.has(i))throw Error(`Doom config adapter is already registered for this host.`);n.add(i),i.on(`session_start`,(n,i)=>{r.set(i,t.loadPiConfig({repoRoot:i.cwd,homeDirectory:a.homeDirectory,defaults:a.defaults,overlay:{...e.loadDoomConfig(i.cwd,a.homeDirectory)},programmatic:a.programmatic,environment:a.environment,cli:a.cli,isProjectTrusted:()=>i.isProjectTrusted()}))}),i.on(`session_shutdown`,(e,t)=>{r.delete(t)})}exports.default=a,exports.readDoomConfigContext=i;
2
+ //# sourceMappingURL=doom.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doom.cjs","names":["loadPiConfig","loadDoomConfig"],"sources":["../../src/extensions/doom.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { loadDoomConfig } from '../config.ts';\nimport { loadPiConfig } from '../config/piConfig.ts';\nimport type { ConfigAdapterRegistrationOptions, PiConfig } from '../config/schema.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\nconst registeredHosts = new WeakSet<ExtensionAPI>();\nconst resolvedConfigs = new WeakMap<ExtensionContext, PiConfig>();\n\nexport function readDoomConfigContext(context: ExtensionContext): PiConfig | undefined {\n return resolvedConfigs.get(context);\n}\n\nexport default function registerDoomConfigAdapter(\n pi: ExtensionAPI,\n options: ConfigAdapterRegistrationOptions = {},\n): void {\n if (registeredHosts.has(pi)) throw new Error('Doom config adapter is already registered for this host.');\n registeredHosts.add(pi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n resolvedConfigs.set(\n context,\n loadPiConfig({\n repoRoot: context.cwd,\n homeDirectory: options.homeDirectory,\n defaults: options.defaults,\n overlay: { ...loadDoomConfig(context.cwd, options.homeDirectory) },\n programmatic: options.programmatic,\n environment: options.environment,\n cli: options.cli,\n isProjectTrusted: () => context.isProjectTrusted(),\n }),\n );\n });\n pi.on(SESSION_SHUTDOWN_EVENT, (_event, context) => {\n resolvedConfigs.delete(context);\n });\n}\n"],"mappings":"oKAQM,EAAkB,IAAI,QACtB,EAAkB,IAAI,QAE5B,SAAgB,EAAsB,EAAiD,CACrF,OAAO,EAAgB,IAAI,CAAO,CACpC,CAEA,SAAwB,EACtB,EACA,EAA4C,CAAC,EACvC,CACN,GAAI,EAAgB,IAAI,CAAE,EAAG,MAAU,MAAM,0DAA0D,EACvG,EAAgB,IAAI,CAAE,EACtB,EAAG,GAAG,iBAAsB,EAAQ,IAAY,CAC9C,EAAgB,IACd,EACAA,EAAAA,aAAa,CACX,SAAU,EAAQ,IAClB,cAAe,EAAQ,cACvB,SAAU,EAAQ,SAClB,QAAS,CAAE,GAAGC,EAAAA,eAAe,EAAQ,IAAK,EAAQ,aAAa,CAAE,EACjE,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,IAAK,EAAQ,IACb,qBAAwB,EAAQ,iBAAiB,CACnD,CAAC,CACH,CACF,CAAC,EACD,EAAG,GAAG,oBAAyB,EAAQ,IAAY,CACjD,EAAgB,OAAO,CAAO,CAChC,CAAC,CACH"}
@@ -0,0 +1,8 @@
1
+ import { ConfigAdapterRegistrationOptions, PiConfig } from "../config/schema.cjs";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ //#region src/extensions/doom.d.ts
4
+ declare function readDoomConfigContext(context: ExtensionContext): PiConfig | undefined;
5
+ declare function registerDoomConfigAdapter(pi: ExtensionAPI, options?: ConfigAdapterRegistrationOptions): void;
6
+ //#endregion
7
+ export { registerDoomConfigAdapter as default, readDoomConfigContext };
8
+ //# sourceMappingURL=doom.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doom.d.cts","names":[],"sources":["../../src/extensions/doom.ts"],"mappings":";;;iBAWgB,sBAAsB,SAAS,mBAAmB;iBAI1C,0BACtB,IAAI,cACJ,UAAS"}
@@ -0,0 +1,8 @@
1
+ import { ConfigAdapterRegistrationOptions, PiConfig } from "../config/schema.mjs";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ //#region src/extensions/doom.d.ts
4
+ declare function readDoomConfigContext(context: ExtensionContext): PiConfig | undefined;
5
+ declare function registerDoomConfigAdapter(pi: ExtensionAPI, options?: ConfigAdapterRegistrationOptions): void;
6
+ //#endregion
7
+ export { registerDoomConfigAdapter as default, readDoomConfigContext };
8
+ //# sourceMappingURL=doom.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doom.d.mts","names":[],"sources":["../../src/extensions/doom.ts"],"mappings":";;;iBAWgB,sBAAsB,SAAS,mBAAmB;iBAI1C,0BACtB,IAAI,cACJ,UAAS"}
@@ -0,0 +1,2 @@
1
+ import{loadDoomConfig as e}from"../config.mjs";import{loadPiConfig as t}from"../config/piConfig.mjs";const n=new WeakSet,r=new WeakMap;function i(e){return r.get(e)}function a(i,a={}){if(n.has(i))throw Error(`Doom config adapter is already registered for this host.`);n.add(i),i.on(`session_start`,(n,i)=>{r.set(i,t({repoRoot:i.cwd,homeDirectory:a.homeDirectory,defaults:a.defaults,overlay:{...e(i.cwd,a.homeDirectory)},programmatic:a.programmatic,environment:a.environment,cli:a.cli,isProjectTrusted:()=>i.isProjectTrusted()}))}),i.on(`session_shutdown`,(e,t)=>{r.delete(t)})}export{a as default,i as readDoomConfigContext};
2
+ //# sourceMappingURL=doom.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doom.mjs","names":[],"sources":["../../src/extensions/doom.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { loadDoomConfig } from '../config.ts';\nimport { loadPiConfig } from '../config/piConfig.ts';\nimport type { ConfigAdapterRegistrationOptions, PiConfig } from '../config/schema.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\nconst registeredHosts = new WeakSet<ExtensionAPI>();\nconst resolvedConfigs = new WeakMap<ExtensionContext, PiConfig>();\n\nexport function readDoomConfigContext(context: ExtensionContext): PiConfig | undefined {\n return resolvedConfigs.get(context);\n}\n\nexport default function registerDoomConfigAdapter(\n pi: ExtensionAPI,\n options: ConfigAdapterRegistrationOptions = {},\n): void {\n if (registeredHosts.has(pi)) throw new Error('Doom config adapter is already registered for this host.');\n registeredHosts.add(pi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n resolvedConfigs.set(\n context,\n loadPiConfig({\n repoRoot: context.cwd,\n homeDirectory: options.homeDirectory,\n defaults: options.defaults,\n overlay: { ...loadDoomConfig(context.cwd, options.homeDirectory) },\n programmatic: options.programmatic,\n environment: options.environment,\n cli: options.cli,\n isProjectTrusted: () => context.isProjectTrusted(),\n }),\n );\n });\n pi.on(SESSION_SHUTDOWN_EVENT, (_event, context) => {\n resolvedConfigs.delete(context);\n });\n}\n"],"mappings":"qGAKA,MAGM,EAAkB,IAAI,QACtB,EAAkB,IAAI,QAE5B,SAAgB,EAAsB,EAAiD,CACrF,OAAO,EAAgB,IAAI,CAAO,CACpC,CAEA,SAAwB,EACtB,EACA,EAA4C,CAAC,EACvC,CACN,GAAI,EAAgB,IAAI,CAAE,EAAG,MAAU,MAAM,0DAA0D,EACvG,EAAgB,IAAI,CAAE,EACtB,EAAG,GAAG,iBAAsB,EAAQ,IAAY,CAC9C,EAAgB,IACd,EACA,EAAa,CACX,SAAU,EAAQ,IAClB,cAAe,EAAQ,cACvB,SAAU,EAAQ,SAClB,QAAS,CAAE,GAAG,EAAe,EAAQ,IAAK,EAAQ,aAAa,CAAE,EACjE,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,IAAK,EAAQ,IACb,qBAAwB,EAAQ,iBAAiB,CACnD,CAAC,CACH,CACF,CAAC,EACD,EAAG,GAAG,oBAAyB,EAAQ,IAAY,CACjD,EAAgB,OAAO,CAAO,CAChC,CAAC,CACH"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../config/piConfig.cjs"),t=new WeakSet,n=new WeakMap;function r(e){return n.get(e)}function i(r,i={}){if(t.has(r))throw Error(`Pi config adapter is already registered for this host.`);t.add(r),r.on(`session_start`,(t,r)=>{n.set(r,e.loadPiConfig({repoRoot:r.cwd,homeDirectory:i.homeDirectory,defaults:i.defaults,programmatic:i.programmatic,environment:i.environment,cli:i.cli,isProjectTrusted:()=>r.isProjectTrusted()}))}),r.on(`session_shutdown`,(e,t)=>{n.delete(t)})}exports.default=i,exports.readPiConfigContext=r;
2
+ //# sourceMappingURL=pi.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.cjs","names":["loadPiConfig"],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { loadPiConfig } from '../config/piConfig.ts';\nimport type { ConfigAdapterRegistrationOptions, PiConfig } from '../config/schema.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\nconst registeredHosts = new WeakSet<ExtensionAPI>();\nconst resolvedConfigs = new WeakMap<ExtensionContext, PiConfig>();\n\nexport function readPiConfigContext(context: ExtensionContext): PiConfig | undefined {\n return resolvedConfigs.get(context);\n}\n\nexport default function registerPiConfigAdapter(\n pi: ExtensionAPI,\n options: ConfigAdapterRegistrationOptions = {},\n): void {\n if (registeredHosts.has(pi)) throw new Error('Pi config adapter is already registered for this host.');\n registeredHosts.add(pi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n resolvedConfigs.set(\n context,\n loadPiConfig({\n repoRoot: context.cwd,\n homeDirectory: options.homeDirectory,\n defaults: options.defaults,\n programmatic: options.programmatic,\n environment: options.environment,\n cli: options.cli,\n isProjectTrusted: () => context.isProjectTrusted(),\n }),\n );\n });\n pi.on(SESSION_SHUTDOWN_EVENT, (_event, context) => {\n resolvedConfigs.delete(context);\n });\n}\n"],"mappings":"yIAOM,EAAkB,IAAI,QACtB,EAAkB,IAAI,QAE5B,SAAgB,EAAoB,EAAiD,CACnF,OAAO,EAAgB,IAAI,CAAO,CACpC,CAEA,SAAwB,EACtB,EACA,EAA4C,CAAC,EACvC,CACN,GAAI,EAAgB,IAAI,CAAE,EAAG,MAAU,MAAM,wDAAwD,EACrG,EAAgB,IAAI,CAAE,EACtB,EAAG,GAAG,iBAAsB,EAAQ,IAAY,CAC9C,EAAgB,IACd,EACAA,EAAAA,aAAa,CACX,SAAU,EAAQ,IAClB,cAAe,EAAQ,cACvB,SAAU,EAAQ,SAClB,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,IAAK,EAAQ,IACb,qBAAwB,EAAQ,iBAAiB,CACnD,CAAC,CACH,CACF,CAAC,EACD,EAAG,GAAG,oBAAyB,EAAQ,IAAY,CACjD,EAAgB,OAAO,CAAO,CAChC,CAAC,CACH"}
@@ -0,0 +1,8 @@
1
+ import { ConfigAdapterRegistrationOptions, PiConfig } from "../config/schema.cjs";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ //#region src/extensions/pi.d.ts
4
+ declare function readPiConfigContext(context: ExtensionContext): PiConfig | undefined;
5
+ declare function registerPiConfigAdapter(pi: ExtensionAPI, options?: ConfigAdapterRegistrationOptions): void;
6
+ //#endregion
7
+ export { registerPiConfigAdapter as default, readPiConfigContext };
8
+ //# sourceMappingURL=pi.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;;iBAUgB,oBAAoB,SAAS,mBAAmB;iBAIxC,wBACtB,IAAI,cACJ,UAAS"}
@@ -0,0 +1,8 @@
1
+ import { ConfigAdapterRegistrationOptions, PiConfig } from "../config/schema.mjs";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ //#region src/extensions/pi.d.ts
4
+ declare function readPiConfigContext(context: ExtensionContext): PiConfig | undefined;
5
+ declare function registerPiConfigAdapter(pi: ExtensionAPI, options?: ConfigAdapterRegistrationOptions): void;
6
+ //#endregion
7
+ export { registerPiConfigAdapter as default, readPiConfigContext };
8
+ //# sourceMappingURL=pi.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;;iBAUgB,oBAAoB,SAAS,mBAAmB;iBAIxC,wBACtB,IAAI,cACJ,UAAS"}
@@ -0,0 +1,2 @@
1
+ import{loadPiConfig as e}from"../config/piConfig.mjs";const t=new WeakSet,n=new WeakMap;function r(e){return n.get(e)}function i(r,i={}){if(t.has(r))throw Error(`Pi config adapter is already registered for this host.`);t.add(r),r.on(`session_start`,(t,r)=>{n.set(r,e({repoRoot:r.cwd,homeDirectory:i.homeDirectory,defaults:i.defaults,programmatic:i.programmatic,environment:i.environment,cli:i.cli,isProjectTrusted:()=>r.isProjectTrusted()}))}),r.on(`session_shutdown`,(e,t)=>{n.delete(t)})}export{i as default,r as readPiConfigContext};
2
+ //# sourceMappingURL=pi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.mjs","names":[],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { loadPiConfig } from '../config/piConfig.ts';\nimport type { ConfigAdapterRegistrationOptions, PiConfig } from '../config/schema.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\nconst registeredHosts = new WeakSet<ExtensionAPI>();\nconst resolvedConfigs = new WeakMap<ExtensionContext, PiConfig>();\n\nexport function readPiConfigContext(context: ExtensionContext): PiConfig | undefined {\n return resolvedConfigs.get(context);\n}\n\nexport default function registerPiConfigAdapter(\n pi: ExtensionAPI,\n options: ConfigAdapterRegistrationOptions = {},\n): void {\n if (registeredHosts.has(pi)) throw new Error('Pi config adapter is already registered for this host.');\n registeredHosts.add(pi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n resolvedConfigs.set(\n context,\n loadPiConfig({\n repoRoot: context.cwd,\n homeDirectory: options.homeDirectory,\n defaults: options.defaults,\n programmatic: options.programmatic,\n environment: options.environment,\n cli: options.cli,\n isProjectTrusted: () => context.isProjectTrusted(),\n }),\n );\n });\n pi.on(SESSION_SHUTDOWN_EVENT, (_event, context) => {\n resolvedConfigs.delete(context);\n });\n}\n"],"mappings":"sDAIA,MAGM,EAAkB,IAAI,QACtB,EAAkB,IAAI,QAE5B,SAAgB,EAAoB,EAAiD,CACnF,OAAO,EAAgB,IAAI,CAAO,CACpC,CAEA,SAAwB,EACtB,EACA,EAA4C,CAAC,EACvC,CACN,GAAI,EAAgB,IAAI,CAAE,EAAG,MAAU,MAAM,wDAAwD,EACrG,EAAgB,IAAI,CAAE,EACtB,EAAG,GAAG,iBAAsB,EAAQ,IAAY,CAC9C,EAAgB,IACd,EACA,EAAa,CACX,SAAU,EAAQ,IAClB,cAAe,EAAQ,cACvB,SAAU,EAAQ,SAClB,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,IAAK,EAAQ,IACb,qBAAwB,EAAQ,iBAAiB,CACnD,CAAC,CACH,CACF,CAAC,EACD,EAAG,GAAG,oBAAyB,EAAQ,IAAY,CACjD,EAAgB,OAAO,CAAO,CAChC,CAAC,CACH"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);const n=new Set([`profileEnvironment`,`pluginHooks`]),r={root:`DOOMPI_ROOT`,majorMode:`DOOMPI_MAJOR_MODE`,temporaryDirectory:`DOOMPI_TEMP_DIR`,domains:`DOOMPI_DOMAINS`,layers:`DOOMPI_LAYERS`,profile:`DOOMPI_PROFILE`,profileEnvironment:`DOOMPI_PROFILE_ENV`,hookGroups:`DOOMPI_HOOK_GROUPS`,skillDirectories:`DOOMPI_SKILL_DIRS`,agentDirectories:`DOOMPI_AGENT_DIRS`,additionalDirectories:`DOOMPI_ADDITIONAL_DIRS`,childExtensions:`DOOMPI_CHILD_EXTENSIONS`,pluginDirectories:`DOOMPI_PLUGIN_DIRS`,pluginHooks:`DOOMPI_PLUGIN_HOOKS`,mcpConfigPath:`DOOMPI_MCP_CONFIG`,personaFile:`DOOMPI_PERSONA_FILE`,workflowExtension:`DOOMPI_WORKFLOW_EXTENSION`,hooks:`DOOMPI_HOOKS_ENABLED`,agents:`DOOMPI_AGENTS_ENABLED`,mcp:`DOOMPI_MCP_ENABLED`,allowProtectedWrites:`DOOMPI_ALLOW_PROTECTED_WRITES`};function i(e){return e?.split(`,`).map(e=>e.trim()).filter(Boolean)??[]}function a(e){return e?.split(t.default.delimiter).map(e=>e.trim()).filter(Boolean)??[]}function o(e){return e!==`0`}function s(e,t,n){if(!e)return{};try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]==`string`))}catch(e){return n?.(t,e),{}}}function c(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}catch(e){return n?.(t,e),[]}}function l(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.pluginRoot==`string`&&typeof e.configPath==`string`):[]}catch(e){return n?.(t,e),[]}}function u(e=process.env,t){let n=r,u=e[n.hookGroups];return{root:e[n.root]||void 0,majorMode:e[n.majorMode]||`copilot`,temporaryDirectory:e[n.temporaryDirectory]||void 0,domains:i(e[n.domains]),layers:i(e[n.layers]),profile:e[n.profile]||void 0,profileEnvironment:s(e[n.profileEnvironment],n.profileEnvironment,t),hookGroups:u===void 0?void 0:i(u),skillDirectories:a(e[n.skillDirectories]),agentDirectories:a(e[n.agentDirectories]),additionalDirectories:a(e[n.additionalDirectories]),childExtensions:c(e[n.childExtensions],n.childExtensions,t),pluginDirectories:a(e[n.pluginDirectories]),pluginHooks:l(e[n.pluginHooks],n.pluginHooks,t),mcpConfigPath:e[n.mcpConfigPath]||void 0,personaFile:e[n.personaFile]||void 0,workflowExtension:e[n.workflowExtension]||void 0,hooks:o(e[n.hooks]),agents:o(e[n.agents]),mcp:o(e[n.mcp]),allowProtectedWrites:o(e[n.allowProtectedWrites])}}function d(e,n=process.env){let i=(e,t)=>{t===void 0?delete n[e]:n[e]=t},a=(e,t)=>i(e,t?`1`:`0`),o=r;return`root`in e&&i(o.root,e.root),`majorMode`in e&&i(o.majorMode,e.majorMode),`temporaryDirectory`in e&&i(o.temporaryDirectory,e.temporaryDirectory),`domains`in e&&i(o.domains,e.domains?.join(`,`)),`layers`in e&&i(o.layers,e.layers?.join(`,`)),`profile`in e&&i(o.profile,e.profile),`hookGroups`in e&&i(o.hookGroups,e.hookGroups?.join(`,`)),`skillDirectories`in e&&i(o.skillDirectories,e.skillDirectories?.join(t.default.delimiter)),`agentDirectories`in e&&i(o.agentDirectories,e.agentDirectories?.join(t.default.delimiter)),`additionalDirectories`in e&&i(o.additionalDirectories,e.additionalDirectories?.join(t.default.delimiter)),`childExtensions`in e&&i(o.childExtensions,JSON.stringify(e.childExtensions??[])),`pluginDirectories`in e&&i(o.pluginDirectories,e.pluginDirectories?.join(t.default.delimiter)),`mcpConfigPath`in e&&i(o.mcpConfigPath,e.mcpConfigPath),`personaFile`in e&&i(o.personaFile,e.personaFile),`workflowExtension`in e&&i(o.workflowExtension,e.workflowExtension),e.hooks!==void 0&&a(o.hooks,e.hooks),e.agents!==void 0&&a(o.agents,e.agents),e.mcp!==void 0&&a(o.mcp,e.mcp),e.allowProtectedWrites!==void 0&&a(o.allowProtectedWrites,e.allowProtectedWrites),n}exports.FILE_ONLY_STATE_FIELDS=n,exports.HARNESS_STATE_KEYS=r,exports.projectHarnessEnvironment=d,exports.readHarnessState=u;
2
+ //# sourceMappingURL=harnessState.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessState.cjs","names":["path"],"sources":["../src/harnessState.ts"],"sourcesContent":["import path from 'node:path';\nimport type { HarnessState, PluginHookSource } from './types.ts';\n\n/**\n * The codec between harness state and the environment.\n *\n * Decoding exists for processes that were started without a state file: a\n * nested run, a third-party spawn, or anything older than the store. Encoding\n * exists because bash hooks, the shell launchers, and packages that do not\n * depend on this one can only read an environment. Ownership, persistence and\n * mutation belong to harnessStore.ts; nothing here touches disk or holds state.\n */\n\nconst DEFAULT_MAJOR_MODE = 'copilot';\nconst DISABLED_FLAG = '0';\n\n/**\n * State that lives in the file only.\n *\n * Both are JSON documents that every spawned process and every hook would\n * otherwise copy in its environment, and neither has a reader outside this\n * package: the plugin hook list is consumed by the Pi hooks extension and the\n * profile environment by the profile switcher, both of which read the store.\n */\nexport const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState> = new Set(['profileEnvironment', 'pluginHooks']);\n\nexport type HarnessStateParseReporter = (key: string, error: unknown) => void;\n\nexport const HARNESS_STATE_KEYS = {\n root: 'DOOMPI_ROOT',\n majorMode: 'DOOMPI_MAJOR_MODE',\n temporaryDirectory: 'DOOMPI_TEMP_DIR',\n domains: 'DOOMPI_DOMAINS',\n layers: 'DOOMPI_LAYERS',\n profile: 'DOOMPI_PROFILE',\n profileEnvironment: 'DOOMPI_PROFILE_ENV',\n hookGroups: 'DOOMPI_HOOK_GROUPS',\n skillDirectories: 'DOOMPI_SKILL_DIRS',\n agentDirectories: 'DOOMPI_AGENT_DIRS',\n additionalDirectories: 'DOOMPI_ADDITIONAL_DIRS',\n childExtensions: 'DOOMPI_CHILD_EXTENSIONS',\n pluginDirectories: 'DOOMPI_PLUGIN_DIRS',\n pluginHooks: 'DOOMPI_PLUGIN_HOOKS',\n mcpConfigPath: 'DOOMPI_MCP_CONFIG',\n personaFile: 'DOOMPI_PERSONA_FILE',\n workflowExtension: 'DOOMPI_WORKFLOW_EXTENSION',\n hooks: 'DOOMPI_HOOKS_ENABLED',\n agents: 'DOOMPI_AGENTS_ENABLED',\n mcp: 'DOOMPI_MCP_ENABLED',\n allowProtectedWrites: 'DOOMPI_ALLOW_PROTECTED_WRITES',\n} as const;\n\nfunction splitCsv(value: string | undefined): string[] {\n return (\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction splitPaths(value: string | undefined): string[] {\n return (\n value\n ?.split(path.delimiter)\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction parseFlag(value: string | undefined): boolean {\n return value !== DISABLED_FLAG;\n}\n\nfunction parseStringRecord(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): Record<string, string> {\n if (!value) return {};\n try {\n const parsed = JSON.parse(value) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n return Object.fromEntries(\n Object.entries(parsed).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n } catch (error) {\n report?.(key, error);\n return {};\n }\n}\n\nfunction parseStringList(value: string | undefined, key: string, report?: HarnessStateParseReporter): string[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nfunction parsePluginHooks(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): PluginHookSource[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is PluginHookSource =>\n typeof item === 'object' &&\n item !== null &&\n typeof (item as PluginHookSource).pluginRoot === 'string' &&\n typeof (item as PluginHookSource).configPath === 'string',\n );\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nexport function readHarnessState(\n environment: NodeJS.ProcessEnv = process.env,\n report?: HarnessStateParseReporter,\n): HarnessState {\n const keys = HARNESS_STATE_KEYS;\n const hookGroups = environment[keys.hookGroups];\n return {\n root: environment[keys.root] || undefined,\n majorMode: environment[keys.majorMode] || DEFAULT_MAJOR_MODE,\n temporaryDirectory: environment[keys.temporaryDirectory] || undefined,\n domains: splitCsv(environment[keys.domains]),\n layers: splitCsv(environment[keys.layers]),\n profile: environment[keys.profile] || undefined,\n profileEnvironment: parseStringRecord(environment[keys.profileEnvironment], keys.profileEnvironment, report),\n hookGroups: hookGroups === undefined ? undefined : splitCsv(hookGroups),\n skillDirectories: splitPaths(environment[keys.skillDirectories]),\n agentDirectories: splitPaths(environment[keys.agentDirectories]),\n additionalDirectories: splitPaths(environment[keys.additionalDirectories]),\n childExtensions: parseStringList(environment[keys.childExtensions], keys.childExtensions, report),\n pluginDirectories: splitPaths(environment[keys.pluginDirectories]),\n pluginHooks: parsePluginHooks(environment[keys.pluginHooks], keys.pluginHooks, report),\n mcpConfigPath: environment[keys.mcpConfigPath] || undefined,\n personaFile: environment[keys.personaFile] || undefined,\n workflowExtension: environment[keys.workflowExtension] || undefined,\n hooks: parseFlag(environment[keys.hooks]),\n agents: parseFlag(environment[keys.agents]),\n mcp: parseFlag(environment[keys.mcp]),\n allowProtectedWrites: parseFlag(environment[keys.allowProtectedWrites]),\n };\n}\n\n/**\n * Publishes a state patch into an environment.\n *\n * Takes the environment rather than assuming `process.env`, because the\n * launcher builds a child environment and Doom Team builds a spawn snapshot;\n * neither should mutate its own process to describe another one.\n *\n * Fields in FILE_ONLY_FIELDS are skipped: the file carries them, and a reader\n * that needs them reads the store.\n */\nexport function projectHarnessEnvironment(\n patch: Partial<HarnessState>,\n environment: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const assign = (key: string, value: string | undefined): void => {\n if (value === undefined) delete environment[key];\n else environment[key] = value;\n };\n const assignFlag = (key: string, value: boolean): void => assign(key, value ? '1' : DISABLED_FLAG);\n const keys = HARNESS_STATE_KEYS;\n\n if ('root' in patch) assign(keys.root, patch.root);\n if ('majorMode' in patch) assign(keys.majorMode, patch.majorMode);\n if ('temporaryDirectory' in patch) assign(keys.temporaryDirectory, patch.temporaryDirectory);\n if ('domains' in patch) assign(keys.domains, patch.domains?.join(','));\n if ('layers' in patch) assign(keys.layers, patch.layers?.join(','));\n if ('profile' in patch) assign(keys.profile, patch.profile);\n if ('hookGroups' in patch) assign(keys.hookGroups, patch.hookGroups?.join(','));\n if ('skillDirectories' in patch) assign(keys.skillDirectories, patch.skillDirectories?.join(path.delimiter));\n if ('agentDirectories' in patch) assign(keys.agentDirectories, patch.agentDirectories?.join(path.delimiter));\n if ('additionalDirectories' in patch) {\n assign(keys.additionalDirectories, patch.additionalDirectories?.join(path.delimiter));\n }\n if ('childExtensions' in patch) assign(keys.childExtensions, JSON.stringify(patch.childExtensions ?? []));\n if ('pluginDirectories' in patch) assign(keys.pluginDirectories, patch.pluginDirectories?.join(path.delimiter));\n if ('mcpConfigPath' in patch) assign(keys.mcpConfigPath, patch.mcpConfigPath);\n if ('personaFile' in patch) assign(keys.personaFile, patch.personaFile);\n if ('workflowExtension' in patch) assign(keys.workflowExtension, patch.workflowExtension);\n if (patch.hooks !== undefined) assignFlag(keys.hooks, patch.hooks);\n if (patch.agents !== undefined) assignFlag(keys.agents, patch.agents);\n if (patch.mcp !== undefined) assignFlag(keys.mcp, patch.mcp);\n if (patch.allowProtectedWrites !== undefined) assignFlag(keys.allowProtectedWrites, patch.allowProtectedWrites);\n return environment;\n}\n"],"mappings":"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"}