@agimon-ai/doompi-config 0.0.1-alpha.2 → 0.0.1-alpha.21

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 (309) hide show
  1. package/README.md +139 -14
  2. package/dist/adapters/atomicJson.cjs +2 -0
  3. package/dist/adapters/atomicJson.cjs.map +1 -0
  4. package/dist/adapters/atomicJson.d.cts +6 -0
  5. package/dist/adapters/atomicJson.d.cts.map +1 -0
  6. package/dist/adapters/atomicJson.d.mts +6 -0
  7. package/dist/adapters/atomicJson.d.mts.map +1 -0
  8. package/dist/adapters/atomicJson.mjs +2 -0
  9. package/dist/adapters/atomicJson.mjs.map +1 -0
  10. package/dist/adapters/config.cjs +2 -0
  11. package/dist/adapters/config.cjs.map +1 -0
  12. package/dist/adapters/config.d.cts +11 -0
  13. package/dist/adapters/config.d.cts.map +1 -0
  14. package/dist/adapters/config.d.mts +11 -0
  15. package/dist/adapters/config.d.mts.map +1 -0
  16. package/dist/adapters/config.mjs +2 -0
  17. package/dist/adapters/config.mjs.map +1 -0
  18. package/dist/adapters/configWriter.cjs +2 -0
  19. package/dist/adapters/configWriter.cjs.map +1 -0
  20. package/dist/adapters/configWriter.d.cts +52 -0
  21. package/dist/adapters/configWriter.d.cts.map +1 -0
  22. package/dist/adapters/configWriter.d.mts +52 -0
  23. package/dist/adapters/configWriter.d.mts.map +1 -0
  24. package/dist/adapters/configWriter.mjs +2 -0
  25. package/dist/adapters/configWriter.mjs.map +1 -0
  26. package/dist/adapters/domains.cjs +2 -0
  27. package/dist/adapters/domains.cjs.map +1 -0
  28. package/dist/adapters/domains.d.cts +25 -0
  29. package/dist/adapters/domains.d.cts.map +1 -0
  30. package/dist/adapters/domains.d.mts +25 -0
  31. package/dist/adapters/domains.d.mts.map +1 -0
  32. package/dist/adapters/domains.mjs +2 -0
  33. package/dist/adapters/domains.mjs.map +1 -0
  34. package/dist/adapters/harnessState.cjs +2 -0
  35. package/dist/adapters/harnessState.cjs.map +1 -0
  36. package/dist/adapters/harnessState.d.cts +50 -0
  37. package/dist/adapters/harnessState.d.cts.map +1 -0
  38. package/dist/adapters/harnessState.d.mts +50 -0
  39. package/dist/adapters/harnessState.d.mts.map +1 -0
  40. package/dist/adapters/harnessState.mjs +2 -0
  41. package/dist/adapters/harnessState.mjs.map +1 -0
  42. package/dist/adapters/harnessStore.cjs +2 -0
  43. package/dist/adapters/harnessStore.cjs.map +1 -0
  44. package/dist/adapters/harnessStore.d.cts +102 -0
  45. package/dist/adapters/harnessStore.d.cts.map +1 -0
  46. package/dist/adapters/harnessStore.d.mts +102 -0
  47. package/dist/adapters/harnessStore.d.mts.map +1 -0
  48. package/dist/adapters/harnessStore.mjs +2 -0
  49. package/dist/adapters/harnessStore.mjs.map +1 -0
  50. package/dist/adapters/init.cjs +178 -0
  51. package/dist/adapters/init.cjs.map +1 -0
  52. package/dist/adapters/init.d.cts +39 -0
  53. package/dist/adapters/init.d.cts.map +1 -0
  54. package/dist/adapters/init.d.mts +39 -0
  55. package/dist/adapters/init.d.mts.map +1 -0
  56. package/dist/adapters/init.mjs +178 -0
  57. package/dist/adapters/init.mjs.map +1 -0
  58. package/dist/adapters/layeredConfig.cjs +2 -0
  59. package/dist/adapters/layeredConfig.cjs.map +1 -0
  60. package/dist/adapters/layeredConfig.d.cts +49 -0
  61. package/dist/adapters/layeredConfig.d.cts.map +1 -0
  62. package/dist/adapters/layeredConfig.d.mts +49 -0
  63. package/dist/adapters/layeredConfig.d.mts.map +1 -0
  64. package/dist/adapters/layeredConfig.mjs +2 -0
  65. package/dist/adapters/layeredConfig.mjs.map +1 -0
  66. package/dist/adapters/majorModes.cjs +2 -0
  67. package/dist/adapters/majorModes.cjs.map +1 -0
  68. package/dist/adapters/majorModes.d.cts +88 -0
  69. package/dist/adapters/majorModes.d.cts.map +1 -0
  70. package/dist/adapters/majorModes.d.mts +88 -0
  71. package/dist/adapters/majorModes.d.mts.map +1 -0
  72. package/dist/adapters/majorModes.mjs +2 -0
  73. package/dist/adapters/majorModes.mjs.map +1 -0
  74. package/dist/adapters/pi/configExtension.cjs +2 -0
  75. package/dist/adapters/pi/configExtension.cjs.map +1 -0
  76. package/dist/adapters/pi/configExtension.d.cts +8 -0
  77. package/dist/adapters/pi/configExtension.d.cts.map +1 -0
  78. package/dist/adapters/pi/configExtension.d.mts +8 -0
  79. package/dist/adapters/pi/configExtension.d.mts.map +1 -0
  80. package/dist/adapters/pi/configExtension.mjs +2 -0
  81. package/dist/adapters/pi/configExtension.mjs.map +1 -0
  82. package/dist/adapters/pi/doomConfigExtension.cjs +2 -0
  83. package/dist/adapters/pi/doomConfigExtension.cjs.map +1 -0
  84. package/dist/adapters/pi/doomConfigExtension.d.cts +8 -0
  85. package/dist/adapters/pi/doomConfigExtension.d.cts.map +1 -0
  86. package/dist/adapters/pi/doomConfigExtension.d.mts +8 -0
  87. package/dist/adapters/pi/doomConfigExtension.d.mts.map +1 -0
  88. package/dist/adapters/pi/doomConfigExtension.mjs +2 -0
  89. package/dist/adapters/pi/doomConfigExtension.mjs.map +1 -0
  90. package/dist/adapters/pi/helpContribution.cjs +2 -0
  91. package/dist/adapters/pi/helpContribution.cjs.map +1 -0
  92. package/dist/adapters/pi/helpContribution.mjs +2 -0
  93. package/dist/adapters/pi/helpContribution.mjs.map +1 -0
  94. package/dist/adapters/pi/piContext.cjs +2 -0
  95. package/dist/adapters/pi/piContext.cjs.map +1 -0
  96. package/dist/adapters/pi/piContext.d.cts +20 -0
  97. package/dist/adapters/pi/piContext.d.cts.map +1 -0
  98. package/dist/adapters/pi/piContext.d.mts +20 -0
  99. package/dist/adapters/pi/piContext.d.mts.map +1 -0
  100. package/dist/adapters/pi/piContext.mjs +2 -0
  101. package/dist/adapters/pi/piContext.mjs.map +1 -0
  102. package/dist/adapters/piConfig.cjs +2 -0
  103. package/dist/adapters/piConfig.cjs.map +1 -0
  104. package/dist/adapters/piConfig.d.cts +8 -0
  105. package/dist/adapters/piConfig.d.cts.map +1 -0
  106. package/dist/adapters/piConfig.d.mts +8 -0
  107. package/dist/adapters/piConfig.d.mts.map +1 -0
  108. package/dist/adapters/piConfig.mjs +2 -0
  109. package/dist/adapters/piConfig.mjs.map +1 -0
  110. package/dist/adapters/pluginCatalog.cjs +2 -0
  111. package/dist/adapters/pluginCatalog.cjs.map +1 -0
  112. package/dist/adapters/pluginCatalog.d.cts +12 -0
  113. package/dist/adapters/pluginCatalog.d.cts.map +1 -0
  114. package/dist/adapters/pluginCatalog.d.mts +12 -0
  115. package/dist/adapters/pluginCatalog.d.mts.map +1 -0
  116. package/dist/adapters/pluginCatalog.mjs +2 -0
  117. package/dist/adapters/pluginCatalog.mjs.map +1 -0
  118. package/dist/adapters/profiles.cjs +4 -0
  119. package/dist/adapters/profiles.cjs.map +1 -0
  120. package/dist/adapters/profiles.d.cts +36 -0
  121. package/dist/adapters/profiles.d.cts.map +1 -0
  122. package/dist/adapters/profiles.d.mts +36 -0
  123. package/dist/adapters/profiles.d.mts.map +1 -0
  124. package/dist/adapters/profiles.mjs +4 -0
  125. package/dist/adapters/profiles.mjs.map +1 -0
  126. package/dist/atomicJson.cjs +1 -2
  127. package/dist/atomicJson.d.cts +2 -6
  128. package/dist/atomicJson.d.mts +2 -6
  129. package/dist/atomicJson.mjs +1 -2
  130. package/dist/config/piConfig.cjs +1 -2
  131. package/dist/config/piConfig.d.cts +2 -7
  132. package/dist/config/piConfig.d.mts +2 -7
  133. package/dist/config/piConfig.mjs +1 -2
  134. package/dist/config/schema.d.cts +2 -33
  135. package/dist/config/schema.d.mts +2 -33
  136. package/dist/config.cjs +1 -2
  137. package/dist/config.d.cts +3 -24
  138. package/dist/config.d.mts +3 -24
  139. package/dist/config.mjs +1 -2
  140. package/dist/configWriter.cjs +1 -2
  141. package/dist/configWriter.d.cts +2 -52
  142. package/dist/configWriter.d.mts +2 -52
  143. package/dist/configWriter.mjs +1 -2
  144. package/dist/container/doomConfigContainer.cjs +2 -0
  145. package/dist/container/doomConfigContainer.cjs.map +1 -0
  146. package/dist/container/doomConfigContainer.d.cts +12 -0
  147. package/dist/container/doomConfigContainer.d.cts.map +1 -0
  148. package/dist/container/doomConfigContainer.d.mts +12 -0
  149. package/dist/container/doomConfigContainer.d.mts.map +1 -0
  150. package/dist/container/doomConfigContainer.mjs +2 -0
  151. package/dist/container/doomConfigContainer.mjs.map +1 -0
  152. package/dist/container.cjs +1 -2
  153. package/dist/container.d.cts +2 -12
  154. package/dist/container.d.mts +2 -12
  155. package/dist/container.mjs +1 -2
  156. package/dist/domains.cjs +1 -2
  157. package/dist/domains.d.cts +6 -77
  158. package/dist/domains.d.mts +6 -77
  159. package/dist/domains.mjs +1 -2
  160. package/dist/extensions/doom.cjs +1 -2
  161. package/dist/extensions/doom.d.cts +2 -8
  162. package/dist/extensions/doom.d.mts +2 -8
  163. package/dist/extensions/doom.mjs +1 -2
  164. package/dist/extensions/pi.cjs +1 -2
  165. package/dist/extensions/pi.d.cts +2 -8
  166. package/dist/extensions/pi.d.mts +2 -8
  167. package/dist/extensions/pi.mjs +1 -2
  168. package/dist/harnessState.cjs +1 -2
  169. package/dist/harnessState.d.cts +2 -50
  170. package/dist/harnessState.d.mts +2 -50
  171. package/dist/harnessState.mjs +1 -2
  172. package/dist/harnessStore.cjs +1 -2
  173. package/dist/harnessStore.d.cts +2 -102
  174. package/dist/harnessStore.d.mts +2 -102
  175. package/dist/harnessStore.mjs +1 -2
  176. package/dist/index.cjs +1 -1
  177. package/dist/index.d.cts +20 -16
  178. package/dist/index.d.mts +20 -16
  179. package/dist/index.mjs +1 -1
  180. package/dist/init.cjs +1 -76
  181. package/dist/init.d.cts +2 -33
  182. package/dist/init.d.mts +2 -33
  183. package/dist/init.mjs +1 -76
  184. package/dist/layeredConfig.cjs +1 -2
  185. package/dist/layeredConfig.d.cts +2 -49
  186. package/dist/layeredConfig.d.mts +2 -49
  187. package/dist/layeredConfig.mjs +1 -2
  188. package/dist/majorModes.cjs +1 -2
  189. package/dist/majorModes.d.cts +2 -75
  190. package/dist/majorModes.d.mts +2 -75
  191. package/dist/majorModes.mjs +1 -2
  192. package/dist/pi.cjs +1 -1
  193. package/dist/pi.d.cts +1 -1
  194. package/dist/pi.d.mts +1 -1
  195. package/dist/pi.mjs +1 -1
  196. package/dist/piContext.cjs +1 -2
  197. package/dist/piContext.d.cts +2 -19
  198. package/dist/piContext.d.mts +2 -19
  199. package/dist/piContext.mjs +1 -2
  200. package/dist/profiles.cjs +1 -4
  201. package/dist/profiles.d.cts +2 -35
  202. package/dist/profiles.d.mts +2 -35
  203. package/dist/profiles.mjs +1 -4
  204. package/dist/schemas/config/schema.d.cts +33 -0
  205. package/dist/schemas/config/schema.d.cts.map +1 -0
  206. package/dist/schemas/config/schema.d.mts +33 -0
  207. package/dist/schemas/config/schema.d.mts.map +1 -0
  208. package/dist/services/configPolicy.cjs +2 -0
  209. package/dist/services/configPolicy.cjs.map +1 -0
  210. package/dist/services/configPolicy.d.cts +19 -0
  211. package/dist/services/configPolicy.d.cts.map +1 -0
  212. package/dist/services/configPolicy.d.mts +19 -0
  213. package/dist/services/configPolicy.d.mts.map +1 -0
  214. package/dist/services/configPolicy.mjs +2 -0
  215. package/dist/services/configPolicy.mjs.map +1 -0
  216. package/dist/services/domains.cjs +2 -0
  217. package/dist/services/domains.cjs.map +1 -0
  218. package/dist/services/domains.d.cts +12 -0
  219. package/dist/services/domains.d.cts.map +1 -0
  220. package/dist/services/domains.d.mts +12 -0
  221. package/dist/services/domains.d.mts.map +1 -0
  222. package/dist/services/domains.mjs +2 -0
  223. package/dist/services/domains.mjs.map +1 -0
  224. package/dist/types/config.cjs +2 -0
  225. package/dist/types/config.cjs.map +1 -0
  226. package/dist/types/config.d.cts +136 -0
  227. package/dist/types/config.d.cts.map +1 -0
  228. package/dist/types/config.d.mts +136 -0
  229. package/dist/types/config.d.mts.map +1 -0
  230. package/dist/types/config.mjs +2 -0
  231. package/dist/types/config.mjs.map +1 -0
  232. package/dist/types/domains.d.cts +89 -0
  233. package/dist/types/domains.d.cts.map +1 -0
  234. package/dist/types/domains.d.mts +89 -0
  235. package/dist/types/domains.d.mts.map +1 -0
  236. package/dist/types.cjs +1 -2
  237. package/dist/types.d.cts +2 -132
  238. package/dist/types.d.mts +2 -132
  239. package/dist/types.mjs +1 -2
  240. package/llms.txt +9 -0
  241. package/package.json +18 -6
  242. package/skills/doom-pi-config/SKILL.md +6 -3
  243. package/skills/doom-pi-config/references/config-contract.md +123 -8
  244. package/dist/atomicJson.cjs.map +0 -1
  245. package/dist/atomicJson.d.cts.map +0 -1
  246. package/dist/atomicJson.d.mts.map +0 -1
  247. package/dist/atomicJson.mjs.map +0 -1
  248. package/dist/config/piConfig.cjs.map +0 -1
  249. package/dist/config/piConfig.d.cts.map +0 -1
  250. package/dist/config/piConfig.d.mts.map +0 -1
  251. package/dist/config/piConfig.mjs.map +0 -1
  252. package/dist/config/schema.d.cts.map +0 -1
  253. package/dist/config/schema.d.mts.map +0 -1
  254. package/dist/config.cjs.map +0 -1
  255. package/dist/config.d.cts.map +0 -1
  256. package/dist/config.d.mts.map +0 -1
  257. package/dist/config.mjs.map +0 -1
  258. package/dist/configWriter.cjs.map +0 -1
  259. package/dist/configWriter.d.cts.map +0 -1
  260. package/dist/configWriter.d.mts.map +0 -1
  261. package/dist/configWriter.mjs.map +0 -1
  262. package/dist/container.cjs.map +0 -1
  263. package/dist/container.d.cts.map +0 -1
  264. package/dist/container.d.mts.map +0 -1
  265. package/dist/container.mjs.map +0 -1
  266. package/dist/domains.cjs.map +0 -1
  267. package/dist/domains.d.cts.map +0 -1
  268. package/dist/domains.d.mts.map +0 -1
  269. package/dist/domains.mjs.map +0 -1
  270. package/dist/extensions/doom.cjs.map +0 -1
  271. package/dist/extensions/doom.d.cts.map +0 -1
  272. package/dist/extensions/doom.d.mts.map +0 -1
  273. package/dist/extensions/doom.mjs.map +0 -1
  274. package/dist/extensions/pi.cjs.map +0 -1
  275. package/dist/extensions/pi.d.cts.map +0 -1
  276. package/dist/extensions/pi.d.mts.map +0 -1
  277. package/dist/extensions/pi.mjs.map +0 -1
  278. package/dist/harnessState.cjs.map +0 -1
  279. package/dist/harnessState.d.cts.map +0 -1
  280. package/dist/harnessState.d.mts.map +0 -1
  281. package/dist/harnessState.mjs.map +0 -1
  282. package/dist/harnessStore.cjs.map +0 -1
  283. package/dist/harnessStore.d.cts.map +0 -1
  284. package/dist/harnessStore.d.mts.map +0 -1
  285. package/dist/harnessStore.mjs.map +0 -1
  286. package/dist/init.cjs.map +0 -1
  287. package/dist/init.d.cts.map +0 -1
  288. package/dist/init.d.mts.map +0 -1
  289. package/dist/init.mjs.map +0 -1
  290. package/dist/layeredConfig.cjs.map +0 -1
  291. package/dist/layeredConfig.d.cts.map +0 -1
  292. package/dist/layeredConfig.d.mts.map +0 -1
  293. package/dist/layeredConfig.mjs.map +0 -1
  294. package/dist/majorModes.cjs.map +0 -1
  295. package/dist/majorModes.d.cts.map +0 -1
  296. package/dist/majorModes.d.mts.map +0 -1
  297. package/dist/majorModes.mjs.map +0 -1
  298. package/dist/piContext.cjs.map +0 -1
  299. package/dist/piContext.d.cts.map +0 -1
  300. package/dist/piContext.d.mts.map +0 -1
  301. package/dist/piContext.mjs.map +0 -1
  302. package/dist/profiles.cjs.map +0 -1
  303. package/dist/profiles.d.cts.map +0 -1
  304. package/dist/profiles.d.mts.map +0 -1
  305. package/dist/profiles.mjs.map +0 -1
  306. package/dist/types.cjs.map +0 -1
  307. package/dist/types.d.cts.map +0 -1
  308. package/dist/types.d.mts.map +0 -1
  309. package/dist/types.mjs.map +0 -1
@@ -0,0 +1,20 @@
1
+ import { DoomConfigContext } from "../../types/config.mjs";
2
+ import { ExtensionAPI, ExtensionContext, ExtensionFactory } from "@earendil-works/pi-coding-agent";
3
+ //#region src/adapters/pi/piContext.d.ts
4
+ declare const DOOM_CONFIG_ENTRY_TYPE = "doom-pi:config:v1";
5
+ interface DoomConfigSelection {
6
+ readonly version: 1;
7
+ readonly majorMode: string;
8
+ readonly domains: readonly string[];
9
+ readonly profile?: string;
10
+ }
11
+ declare function readDoomConfigSelection(ctx: Pick<ExtensionContext, 'sessionManager'>): DoomConfigSelection | undefined;
12
+ declare function createDoomConfigContext(ctx: Pick<ExtensionContext, 'cwd' | 'sessionManager'>): DoomConfigContext;
13
+ declare function createDoomConfigContextAsync(ctx: Pick<ExtensionContext, 'cwd' | 'sessionManager'>): Promise<DoomConfigContext>;
14
+ declare function appendDoomConfigSelection(pi: Pick<ExtensionAPI, 'appendEntry'>, selection: DoomConfigSelection): void;
15
+ declare function provideDoomConfigContext(ctx: Pick<ExtensionContext, 'sessionManager'>, context: DoomConfigContext): () => void;
16
+ declare function requireDoomConfigContext(ctx: Pick<ExtensionContext, 'sessionManager'>): DoomConfigContext;
17
+ declare const doomConfigExtension: ExtensionFactory;
18
+ //#endregion
19
+ export { DOOM_CONFIG_ENTRY_TYPE, DoomConfigSelection, appendDoomConfigSelection, createDoomConfigContext, createDoomConfigContextAsync, doomConfigExtension, provideDoomConfigContext, readDoomConfigSelection, requireDoomConfigContext };
20
+ //# sourceMappingURL=piContext.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piContext.d.mts","names":[],"sources":["../../../src/adapters/pi/piContext.ts"],"mappings":";;;cAOa;UAEI;WACN;WACA;WACA;WACA;;iBAwCK,wBACd,KAAK,KAAK,sCACT;iBAuBa,wBAAwB,KAAK,KAAK,8CAA8C;iBAK1E,6BACpB,KAAK,KAAK,8CACT,QAAQ;iBAMK,0BAA0B,IAAI,KAAK,8BAA8B,WAAW;iBAI5E,yBACd,KAAK,KAAK,qCACV,SAAS;iBAWK,yBAAyB,KAAK,KAAK,sCAAsC;cAM5E,qBAAqB"}
@@ -0,0 +1,2 @@
1
+ import{loadDoomConfig as e,loadDoomConfigAsync as t}from"../config.mjs";import{getHarnessState as n}from"../harnessStore.mjs";import{registerDoomConfigHelp as r}from"./helpContribution.mjs";import{createDoomTelemetry as i}from"@agimon-ai/doompi-telemetry";const a=`doom-pi:config:v1`,o=new WeakMap;function s(e){if(typeof e!=`object`||!e)return!1;let t=e;return t.version===1&&typeof t.majorMode==`string`&&Array.isArray(t.domains)&&t.domains.every(e=>typeof e==`string`)&&(t.profile===void 0||typeof t.profile==`string`)}function c(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n?.type===`custom`&&n.customType===`doom-pi:config:v1`&&s(n.data))return n.data}}function l(e){if(typeof e!=`object`||!e||Object.isFrozen(e))return e;for(let t of Object.values(e))l(t);return Object.freeze(e)}function u(e){return c(e.sessionManager.getBranch())}function d(e){let t=n(),r=u(e);return{harness:r?{...t,majorMode:r.majorMode,domains:[...r.domains],profile:r.profile}:t,requiresRelaunch:!!(r&&(r.majorMode!==t.majorMode||r.profile!==t.profile||r.domains.join(`,`)!==t.domains.join(`,`))),root:t.root}}function f(t){let{harness:n,requiresRelaunch:r,root:i}=d(t);return l({settings:e(i??t.cwd),harness:n,requiresRelaunch:r})}async function p(e){let{harness:n,requiresRelaunch:r,root:i}=d(e);return l({settings:await t(i??e.cwd),harness:n,requiresRelaunch:r})}function m(e,t){e.appendEntry(a,t)}function h(e,t){let n={context:t,generation:Symbol(`doom-config-context`)};return o.set(e.sessionManager,n),()=>{o.get(e.sessionManager)?.generation===n.generation&&o.delete(e.sessionManager)}}function g(e){let t=o.get(e.sessionManager);if(!t)throw Error(`Doom config context is unavailable. Load @agimon-ai/doompi-config/pi.`);return t.context}const _=e=>{let t=r(e),n,a;e.on(`session_start`,async(e,t)=>{n?.();let r=await p(t);n=h(t,r),a??=i({serviceName:`doom-config`,packageName:`@agimon-ai/doompi-config`,cwd:t.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),a.recordEvent(`doom_config.context_bound`,{"config.major_mode":r.harness.majorMode,"config.domain_count":r.harness.domains.length,"config.has_profile":r.harness.profile!==void 0,"config.requires_relaunch":r.requiresRelaunch})}),e.on(`session_shutdown`,async()=>{n=void 0;try{await a?.shutdown()}finally{a=void 0,t.dispose()}})};export{a as DOOM_CONFIG_ENTRY_TYPE,m as appendDoomConfigSelection,f as createDoomConfigContext,p as createDoomConfigContextAsync,_ as doomConfigExtension,h as provideDoomConfigContext,u as readDoomConfigSelection,g as requireDoomConfigContext};
2
+ //# sourceMappingURL=piContext.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piContext.mjs","names":[],"sources":["../../../src/adapters/pi/piContext.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext, ExtensionFactory, SessionEntry } from '@earendil-works/pi-coding-agent';\nimport type { DeepReadonly, DoomConfigContext, HarnessState } from '../../types/config.ts';\nimport { loadDoomConfig, loadDoomConfigAsync } from '../config.ts';\nimport { getHarnessState } from '../harnessStore.ts';\nimport { registerDoomConfigHelp } from './helpContribution.ts';\n\nexport const DOOM_CONFIG_ENTRY_TYPE = 'doom-pi:config:v1';\n\nexport interface DoomConfigSelection {\n readonly version: 1;\n readonly majorMode: string;\n readonly domains: readonly string[];\n readonly profile?: string;\n}\n\ninterface ConfigBinding {\n readonly context: DoomConfigContext;\n readonly generation: symbol;\n}\n\nconst configBindings = new WeakMap<ExtensionContext['sessionManager'], ConfigBinding>();\n\nfunction isSelection(value: unknown): value is DoomConfigSelection {\n if (typeof value !== 'object' || value === null) return false;\n const selection = value as Partial<DoomConfigSelection>;\n return (\n selection.version === 1 &&\n typeof selection.majorMode === 'string' &&\n Array.isArray(selection.domains) &&\n selection.domains.every((domain) => typeof domain === 'string') &&\n (selection.profile === undefined || typeof selection.profile === 'string')\n );\n}\n\nfunction branchSelection(entries: readonly SessionEntry[]): DoomConfigSelection | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.type === 'custom' && entry.customType === DOOM_CONFIG_ENTRY_TYPE && isSelection(entry.data)) {\n return entry.data;\n }\n }\n return undefined;\n}\n\nfunction deepFreeze<TValue>(value: TValue): DeepReadonly<TValue> {\n if (typeof value !== 'object' || value === null || Object.isFrozen(value)) {\n return value as DeepReadonly<TValue>;\n }\n for (const child of Object.values(value)) deepFreeze(child);\n return Object.freeze(value) as DeepReadonly<TValue>;\n}\n\nexport function readDoomConfigSelection(\n ctx: Pick<ExtensionContext, 'sessionManager'>,\n): DoomConfigSelection | undefined {\n return branchSelection(ctx.sessionManager.getBranch());\n}\n\nfunction resolveContextState(ctx: Pick<ExtensionContext, 'sessionManager'>): {\n harness: HarnessState;\n requiresRelaunch: boolean;\n root: string | undefined;\n} {\n const bootstrap = getHarnessState();\n const selection = readDoomConfigSelection(ctx);\n const harness: HarnessState = selection\n ? { ...bootstrap, majorMode: selection.majorMode, domains: [...selection.domains], profile: selection.profile }\n : bootstrap;\n const requiresRelaunch = Boolean(\n selection &&\n (selection.majorMode !== bootstrap.majorMode ||\n selection.profile !== bootstrap.profile ||\n selection.domains.join(',') !== bootstrap.domains.join(',')),\n );\n return { harness, requiresRelaunch, root: bootstrap.root };\n}\n\nexport function createDoomConfigContext(ctx: Pick<ExtensionContext, 'cwd' | 'sessionManager'>): DoomConfigContext {\n const { harness, requiresRelaunch, root } = resolveContextState(ctx);\n return deepFreeze({ settings: loadDoomConfig(root ?? ctx.cwd), harness, requiresRelaunch });\n}\n\nexport async function createDoomConfigContextAsync(\n ctx: Pick<ExtensionContext, 'cwd' | 'sessionManager'>,\n): Promise<DoomConfigContext> {\n const { harness, requiresRelaunch, root } = resolveContextState(ctx);\n const settings = await loadDoomConfigAsync(root ?? ctx.cwd);\n return deepFreeze({ settings, harness, requiresRelaunch });\n}\n\nexport function appendDoomConfigSelection(pi: Pick<ExtensionAPI, 'appendEntry'>, selection: DoomConfigSelection): void {\n pi.appendEntry(DOOM_CONFIG_ENTRY_TYPE, selection);\n}\n\nexport function provideDoomConfigContext(\n ctx: Pick<ExtensionContext, 'sessionManager'>,\n context: DoomConfigContext,\n): () => void {\n const binding = { context, generation: Symbol('doom-config-context') };\n configBindings.set(ctx.sessionManager, binding);\n return () => {\n if (configBindings.get(ctx.sessionManager)?.generation === binding.generation) {\n configBindings.delete(ctx.sessionManager);\n }\n };\n}\n\nexport function requireDoomConfigContext(ctx: Pick<ExtensionContext, 'sessionManager'>): DoomConfigContext {\n const binding = configBindings.get(ctx.sessionManager);\n if (!binding) throw new Error('Doom config context is unavailable. Load @agimon-ai/doompi-config/pi.');\n return binding.context;\n}\n\nexport const doomConfigExtension: ExtensionFactory = (pi) => {\n const help = registerDoomConfigHelp(pi);\n let dispose: (() => void) | undefined;\n let telemetry: DoomTelemetry | undefined;\n pi.on('session_start', async (_event, ctx) => {\n dispose?.();\n const context = await createDoomConfigContextAsync(ctx);\n dispose = provideDoomConfigContext(ctx, context);\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-config',\n packageName: '@agimon-ai/doompi-config',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n // Binding is startup-critical; exporting telemetry is not. Do not make\n // later session_start consumers wait for endpoint discovery or health checks.\n void telemetry.recordEvent('doom_config.context_bound', {\n 'config.major_mode': context.harness.majorMode,\n 'config.domain_count': context.harness.domains.length,\n 'config.has_profile': context.harness.profile !== undefined,\n 'config.requires_relaunch': context.requiresRelaunch,\n });\n });\n pi.on('session_shutdown', async () => {\n // Other extensions consume config during shutdown. Keep the WeakMap entry\n // alive for that phase and let it disappear with Pi's sessionManager.\n dispose = undefined;\n try {\n await telemetry?.shutdown();\n } finally {\n telemetry = undefined;\n help.dispose();\n }\n });\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("node:os");r=e.__toESM(r,1);let i=require("@earendil-works/pi-coding-agent");const a=`settings.json`;function o(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function s(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];n[e]=o(t)&&o(r)?s(t,r):r}return n}function c(e){if(!t.default.existsSync(e))return{};let n;try{n=JSON.parse(t.default.readFileSync(e,`utf8`))}catch(t){throw Error(`Could not parse Pi settings at ${e}`,{cause:t})}if(!o(n))throw Error(`Pi settings at ${e} must be a JSON object`);return n}async function l(e){let n;try{n=JSON.parse(await t.default.promises.readFile(e,`utf8`))}catch(t){if(t.code===`ENOENT`)return{};throw Error(`Could not parse Pi settings at ${e}`,{cause:t})}if(!o(n))throw Error(`Pi settings at ${e} must be a JSON object`);return n}function u(e){return e.reduce((e,t)=>s(e,c(t)),{})}async function d(e){let t={};for(let n of e)t=s(t,await l(n));return t}function f(e){return typeof e==`function`?e():e}function p(e,t=r.default.homedir(),o=t===r.default.homedir()?(0,i.getAgentDir)():n.default.join(t,i.CONFIG_DIR_NAME,`agent`)){return{canonicalUser:n.default.join(o,a),canonicalProject:n.default.join(e,i.CONFIG_DIR_NAME,a),legacyUser:[n.default.join(t,i.CONFIG_DIR_NAME,a)],legacyProject:[n.default.join(e,`pi`,a)]}}function m(e){let t=p(e.repoRoot,e.homeDirectory),n=[...t.legacyUser,...e.userConfigPaths??[],t.canonicalUser],r=[...t.legacyProject,...e.projectConfigPaths??[],t.canonicalProject],i=e.defaults??{},a=u(n),o=f(e.isProjectTrusted)?u(r):{};return[i,a,e.overlay??{},o,e.environment??{},e.cli??{},e.programmatic??{}].reduce(s,{})}async function h(e){let t=p(e.repoRoot,e.homeDirectory),n=[...t.legacyUser,...e.userConfigPaths??[],t.canonicalUser],r=[...t.legacyProject,...e.projectConfigPaths??[],t.canonicalProject],i=await d(n),a=f(e.isProjectTrusted)?await d(r):{};return[e.defaults??{},i,e.overlay??{},a,e.environment??{},e.cli??{},e.programmatic??{}].reduce(s,{})}exports.loadPiConfig=m,exports.loadPiConfigAsync=h,exports.piConfigPaths=p;
2
+ //# sourceMappingURL=piConfig.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig.cjs","names":["fs","os","getAgentDir","path","CONFIG_DIR_NAME"],"sources":["../../src/adapters/piConfig.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME, getAgentDir } from '@earendil-works/pi-coding-agent';\nimport type { PiConfig, PiConfigLoadOptions, PiConfigPaths } from '../schemas/config/schema.ts';\n\nconst SETTINGS_FILE_NAME = 'settings.json';\nconst LEGACY_CONFIG_DIR_NAME = 'pi';\n\nfunction isObject(value: unknown): value is PiConfig {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeConfig(base: PiConfig, override: PiConfig): PiConfig {\n const result: PiConfig = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const current = result[key];\n result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;\n }\n return result;\n}\n\nfunction readConfig(filePath: string): PiConfig {\n if (!fs.existsSync(filePath)) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n } catch (error) {\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nasync function readConfigAsync(filePath: string): Promise<PiConfig> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await fs.promises.readFile(filePath, 'utf8'));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nfunction readConfigPaths(paths: readonly string[]): PiConfig {\n return paths.reduce<PiConfig>((config, filePath) => mergeConfig(config, readConfig(filePath)), {});\n}\n\nasync function readConfigPathsAsync(paths: readonly string[]): Promise<PiConfig> {\n let config: PiConfig = {};\n for (const filePath of paths) config = mergeConfig(config, await readConfigAsync(filePath));\n return config;\n}\n\nfunction projectIsTrusted(value: PiConfigLoadOptions['isProjectTrusted']): boolean {\n return typeof value === 'function' ? value() : value;\n}\n\nexport function piConfigPaths(\n repoRoot: string,\n homeDirectory = os.homedir(),\n agentDirectory = homeDirectory === os.homedir() ? getAgentDir() : path.join(homeDirectory, CONFIG_DIR_NAME, 'agent'),\n): PiConfigPaths {\n return {\n canonicalUser: path.join(agentDirectory, SETTINGS_FILE_NAME),\n canonicalProject: path.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n legacyUser: [path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n legacyProject: [path.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n };\n}\n\nexport function loadPiConfig(options: PiConfigLoadOptions): PiConfig {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const defaults = options.defaults ?? {};\n const user = readConfigPaths(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};\n return [\n defaults,\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\nexport async function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig> {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const user = await readConfigPathsAsync(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? await readConfigPathsAsync(projectPaths) : {};\n return [\n options.defaults ?? {},\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n"],"mappings":"sOAMA,MAAM,EAAqB,gBAG3B,SAAS,EAAS,EAAmC,CACnD,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,SAAS,EAAY,EAAgB,EAA8B,CACjE,IAAM,EAAmB,CAAE,GAAG,CAAK,EACnC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAQ,EAAG,CACnD,IAAM,EAAU,EAAO,GACvB,EAAO,GAAO,EAAS,CAAO,GAAK,EAAS,CAAK,EAAI,EAAY,EAAS,CAAK,EAAI,CACrF,CACA,OAAO,CACT,CAEA,SAAS,EAAW,EAA4B,CAC9C,GAAI,CAACA,EAAAA,QAAG,WAAW,CAAQ,EAAG,MAAO,CAAC,EACtC,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAMA,EAAAA,QAAG,aAAa,EAAU,MAAM,CAAC,CACvD,OAAS,EAAO,CACd,MAAU,MAAM,kCAAkC,IAAY,CAAE,MAAO,CAAM,CAAC,CAChF,CACA,GAAI,CAAC,EAAS,CAAM,EAAG,MAAU,MAAM,kBAAkB,EAAS,uBAAuB,EACzF,OAAO,CACT,CAEA,eAAe,EAAgB,EAAqC,CAClE,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,MAAMA,EAAAA,QAAG,SAAS,SAAS,EAAU,MAAM,CAAC,CAClE,OAAS,EAAO,CACd,GAAK,EAAgC,OAAS,SAAU,MAAO,CAAC,EAChE,MAAU,MAAM,kCAAkC,IAAY,CAAE,MAAO,CAAM,CAAC,CAChF,CACA,GAAI,CAAC,EAAS,CAAM,EAAG,MAAU,MAAM,kBAAkB,EAAS,uBAAuB,EACzF,OAAO,CACT,CAEA,SAAS,EAAgB,EAAoC,CAC3D,OAAO,EAAM,QAAkB,EAAQ,IAAa,EAAY,EAAQ,EAAW,CAAQ,CAAC,EAAG,CAAC,CAAC,CACnG,CAEA,eAAe,EAAqB,EAA6C,CAC/E,IAAI,EAAmB,CAAC,EACxB,IAAK,IAAM,KAAY,EAAO,EAAS,EAAY,EAAQ,MAAM,EAAgB,CAAQ,CAAC,EAC1F,OAAO,CACT,CAEA,SAAS,EAAiB,EAAyD,CACjF,OAAO,OAAO,GAAU,WAAa,EAAM,EAAI,CACjD,CAEA,SAAgB,EACd,EACA,EAAgBC,EAAAA,QAAG,QAAQ,EAC3B,EAAiB,IAAkBA,EAAAA,QAAG,QAAQ,GAAA,EAAIC,EAAAA,YAAAA,CAAY,EAAIC,EAAAA,QAAK,KAAK,EAAeC,EAAAA,gBAAiB,OAAO,EACpG,CACf,MAAO,CACL,cAAeD,EAAAA,QAAK,KAAK,EAAgB,CAAkB,EAC3D,iBAAkBA,EAAAA,QAAK,KAAK,EAAUC,EAAAA,gBAAiB,CAAkB,EACzE,WAAY,CAACD,EAAAA,QAAK,KAAK,EAAeC,EAAAA,gBAAiB,CAAkB,CAAC,EAC1E,cAAe,CAACD,EAAAA,QAAK,KAAK,EAAU,KAAwB,CAAkB,CAAC,CACjF,CACF,CAEA,SAAgB,EAAa,EAAwC,CACnE,IAAM,EAAQ,EAAc,EAAQ,SAAU,EAAQ,aAAa,EAC7D,EAAY,CAAC,GAAG,EAAM,WAAY,GAAI,EAAQ,iBAAmB,CAAC,EAAI,EAAM,aAAa,EACzF,EAAe,CAAC,GAAG,EAAM,cAAe,GAAI,EAAQ,oBAAsB,CAAC,EAAI,EAAM,gBAAgB,EACrG,EAAW,EAAQ,UAAY,CAAC,EAChC,EAAO,EAAgB,CAAS,EAChC,EAAiB,EAAiB,EAAQ,gBAAgB,EAAI,EAAgB,CAAY,EAAI,CAAC,EACrG,MAAO,CACL,EACA,EACA,EAAQ,SAAW,CAAC,EACpB,EACA,EAAQ,aAAe,CAAC,EACxB,EAAQ,KAAO,CAAC,EAChB,EAAQ,cAAgB,CAAC,CAC3B,CAAC,CAAC,OAAO,EAAa,CAAC,CAAC,CAC1B,CAEA,eAAsB,EAAkB,EAAiD,CACvF,IAAM,EAAQ,EAAc,EAAQ,SAAU,EAAQ,aAAa,EAC7D,EAAY,CAAC,GAAG,EAAM,WAAY,GAAI,EAAQ,iBAAmB,CAAC,EAAI,EAAM,aAAa,EACzF,EAAe,CAAC,GAAG,EAAM,cAAe,GAAI,EAAQ,oBAAsB,CAAC,EAAI,EAAM,gBAAgB,EACrG,EAAO,MAAM,EAAqB,CAAS,EAC3C,EAAiB,EAAiB,EAAQ,gBAAgB,EAAI,MAAM,EAAqB,CAAY,EAAI,CAAC,EAChH,MAAO,CACL,EAAQ,UAAY,CAAC,EACrB,EACA,EAAQ,SAAW,CAAC,EACpB,EACA,EAAQ,aAAe,CAAC,EACxB,EAAQ,KAAO,CAAC,EAChB,EAAQ,cAAgB,CAAC,CAC3B,CAAC,CAAC,OAAO,EAAa,CAAC,CAAC,CAC1B"}
@@ -0,0 +1,8 @@
1
+ import { PiConfig, PiConfigLoadOptions, PiConfigPaths } from "../schemas/config/schema.cjs";
2
+ //#region src/adapters/piConfig.d.ts
3
+ declare function piConfigPaths(repoRoot: string, homeDirectory?: string, agentDirectory?: string): PiConfigPaths;
4
+ declare function loadPiConfig(options: PiConfigLoadOptions): PiConfig;
5
+ declare function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig>;
6
+ //#endregion
7
+ export { loadPiConfig, loadPiConfigAsync, piConfigPaths };
8
+ //# sourceMappingURL=piConfig.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig.d.cts","names":[],"sources":["../../src/adapters/piConfig.ts"],"mappings":";;iBA4DgB,cACd,kBACA,wBACA,0BACC;iBASa,aAAa,SAAS,sBAAsB;iBAkBtC,kBAAkB,SAAS,sBAAsB,QAAQ"}
@@ -0,0 +1,8 @@
1
+ import { PiConfig, PiConfigLoadOptions, PiConfigPaths } from "../schemas/config/schema.mjs";
2
+ //#region src/adapters/piConfig.d.ts
3
+ declare function piConfigPaths(repoRoot: string, homeDirectory?: string, agentDirectory?: string): PiConfigPaths;
4
+ declare function loadPiConfig(options: PiConfigLoadOptions): PiConfig;
5
+ declare function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig>;
6
+ //#endregion
7
+ export { loadPiConfig, loadPiConfigAsync, piConfigPaths };
8
+ //# sourceMappingURL=piConfig.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig.d.mts","names":[],"sources":["../../src/adapters/piConfig.ts"],"mappings":";;iBA4DgB,cACd,kBACA,wBACA,0BACC;iBASa,aAAa,SAAS,sBAAsB;iBAkBtC,kBAAkB,SAAS,sBAAsB,QAAQ"}
@@ -0,0 +1,2 @@
1
+ import e from"node:fs";import t from"node:path";import n from"node:os";import{CONFIG_DIR_NAME as r,getAgentDir as i}from"@earendil-works/pi-coding-agent";const a=`settings.json`;function o(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function s(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];n[e]=o(t)&&o(r)?s(t,r):r}return n}function c(t){if(!e.existsSync(t))return{};let n;try{n=JSON.parse(e.readFileSync(t,`utf8`))}catch(e){throw Error(`Could not parse Pi settings at ${t}`,{cause:e})}if(!o(n))throw Error(`Pi settings at ${t} must be a JSON object`);return n}async function l(t){let n;try{n=JSON.parse(await e.promises.readFile(t,`utf8`))}catch(e){if(e.code===`ENOENT`)return{};throw Error(`Could not parse Pi settings at ${t}`,{cause:e})}if(!o(n))throw Error(`Pi settings at ${t} must be a JSON object`);return n}function u(e){return e.reduce((e,t)=>s(e,c(t)),{})}async function d(e){let t={};for(let n of e)t=s(t,await l(n));return t}function f(e){return typeof e==`function`?e():e}function p(e,o=n.homedir(),s=o===n.homedir()?i():t.join(o,r,`agent`)){return{canonicalUser:t.join(s,a),canonicalProject:t.join(e,r,a),legacyUser:[t.join(o,r,a)],legacyProject:[t.join(e,`pi`,a)]}}function m(e){let t=p(e.repoRoot,e.homeDirectory),n=[...t.legacyUser,...e.userConfigPaths??[],t.canonicalUser],r=[...t.legacyProject,...e.projectConfigPaths??[],t.canonicalProject],i=e.defaults??{},a=u(n),o=f(e.isProjectTrusted)?u(r):{};return[i,a,e.overlay??{},o,e.environment??{},e.cli??{},e.programmatic??{}].reduce(s,{})}async function h(e){let t=p(e.repoRoot,e.homeDirectory),n=[...t.legacyUser,...e.userConfigPaths??[],t.canonicalUser],r=[...t.legacyProject,...e.projectConfigPaths??[],t.canonicalProject],i=await d(n),a=f(e.isProjectTrusted)?await d(r):{};return[e.defaults??{},i,e.overlay??{},a,e.environment??{},e.cli??{},e.programmatic??{}].reduce(s,{})}export{m as loadPiConfig,h as loadPiConfigAsync,p as piConfigPaths};
2
+ //# sourceMappingURL=piConfig.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig.mjs","names":[],"sources":["../../src/adapters/piConfig.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME, getAgentDir } from '@earendil-works/pi-coding-agent';\nimport type { PiConfig, PiConfigLoadOptions, PiConfigPaths } from '../schemas/config/schema.ts';\n\nconst SETTINGS_FILE_NAME = 'settings.json';\nconst LEGACY_CONFIG_DIR_NAME = 'pi';\n\nfunction isObject(value: unknown): value is PiConfig {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeConfig(base: PiConfig, override: PiConfig): PiConfig {\n const result: PiConfig = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const current = result[key];\n result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;\n }\n return result;\n}\n\nfunction readConfig(filePath: string): PiConfig {\n if (!fs.existsSync(filePath)) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n } catch (error) {\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nasync function readConfigAsync(filePath: string): Promise<PiConfig> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await fs.promises.readFile(filePath, 'utf8'));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nfunction readConfigPaths(paths: readonly string[]): PiConfig {\n return paths.reduce<PiConfig>((config, filePath) => mergeConfig(config, readConfig(filePath)), {});\n}\n\nasync function readConfigPathsAsync(paths: readonly string[]): Promise<PiConfig> {\n let config: PiConfig = {};\n for (const filePath of paths) config = mergeConfig(config, await readConfigAsync(filePath));\n return config;\n}\n\nfunction projectIsTrusted(value: PiConfigLoadOptions['isProjectTrusted']): boolean {\n return typeof value === 'function' ? value() : value;\n}\n\nexport function piConfigPaths(\n repoRoot: string,\n homeDirectory = os.homedir(),\n agentDirectory = homeDirectory === os.homedir() ? getAgentDir() : path.join(homeDirectory, CONFIG_DIR_NAME, 'agent'),\n): PiConfigPaths {\n return {\n canonicalUser: path.join(agentDirectory, SETTINGS_FILE_NAME),\n canonicalProject: path.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n legacyUser: [path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n legacyProject: [path.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n };\n}\n\nexport function loadPiConfig(options: PiConfigLoadOptions): PiConfig {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const defaults = options.defaults ?? {};\n const user = readConfigPaths(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};\n return [\n defaults,\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\nexport async function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig> {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const user = await readConfigPathsAsync(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? await readConfigPathsAsync(projectPaths) : {};\n return [\n options.defaults ?? {},\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:crypto");t=e.__toESM(t,1);let n=require("node:fs");n=e.__toESM(n,1);let r=require("node:path");r=e.__toESM(r,1);const i=`https://agent-plugins.org/schemas/`,a=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,o=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,s=[`.codex-plugin/plugin.json`,`.claude-plugin/plugin.json`,`.cursor-plugin/plugin.json`],c=[`.agents/plugins/marketplace.json`,`.agents/plugins/api_marketplace.json`,`.claude-plugin/marketplace.json`,`.cursor-plugin/marketplace.json`];function l(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function u(e,t){if(!l(e))throw Error(`${t} must be an object`);return e}function d(e,t){if(e!==void 0){if(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}}function f(e,t){let n=d(e,t);if(!n)throw Error(`${t} must be a non-empty string`);return n}function p(e,t,n){let r=Object.keys(e).filter(e=>!t.includes(e));if(r.length>0)throw Error(`${n} contains unsupported field "${r[0]}"`)}function m(e,t){if(!a.test(e))throw Error(`${t} must start with an alphanumeric character and contain only alphanumerics, ., _, or -`)}function h(e,t){let n=e.split(`@`);if(n.length>2||n.some(e=>!a.test(e)))throw Error(`${t} must be a plugin name or plugin@marketplace identifier`)}function g(e,t){let n=d(e,t);if(!n)return;let r=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);if(r.startsWith(`/`)||r.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${t} must stay within the remote repository root`);return r}function _(e,t,n){let i=f(e,n);if(/^(?:https?|ssh|file):\/\//.test(i)||/^git@[^:]+:.+/.test(i)||r.default.isAbsolute(i))return i;if(i.startsWith(`./`)||i.startsWith(`.\\`)){let e=i.replaceAll(`\\`,`/`).slice(2);if(!e||e.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${n} must stay within its declaring root`);return r.default.resolve(t,e)}if(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\.git)?$/.test(i))return`https://github.com/${i.endsWith(`.git`)?i:`${i}.git`}`;throw Error(`${n} is not a supported Git URL`)}function v(e,t,n){if(e===`.`||e===`./`)return t.root;let i=t.manifestPath.endsWith(`.cursor-plugin/marketplace.json`),a=e.startsWith(`./`)?e.slice(2):i?e:void 0;if(!a)throw Error(`${n} must start with ./`);let o=a.replaceAll(`\\`,`/`);if(o.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${n} must stay within the marketplace root`);return r.default.resolve(t.root,o)}function y(e,t,n,i){let a=f(e.source,`${n}.source`);if(a===`local`){p(e,[`source`,`path`,`description`],n);let a=f(e.path,`${n}.path`);return{type:`local`,path:i?v(a,i,`${n}.path`):r.default.resolve(t,a)}}if(a===`url`||a===`git-subdir`){p(e,[`source`,`url`,`path`,`ref`,`sha`,`description`],n);let r=g(e.path,`${n}.path`);if(a===`git-subdir`&&!r)throw Error(`${n}.path must be a non-empty string for git-subdir sources`);let o=d(e.ref,`${n}.ref`),s=d(e.sha,`${n}.sha`);return{type:`git`,url:_(e.url,i?.root??t,`${n}.url`),...r?{path:r}:{},...o?{ref:o}:{},...s?{sha:s}:{}}}if(a===`npm`){p(e,[`source`,`package`,`version`,`registry`,`description`],n);let t=f(e.package,`${n}.package`);if(!o.test(t))throw Error(`${n}.package must be a valid npm package name`);let r=d(e.version,`${n}.version`),i=d(e.registry,`${n}.registry`);return{type:`npm`,package:t,...r?{version:r}:{},...i?{registry:i}:{}}}throw Error(`${n}.source must be local, url, git-subdir, or npm`)}function b(e,t,n,i){if(typeof e==`string`){let a=f(e,n);return{type:`local`,path:i?v(a,i,n):r.default.resolve(t,a)}}return y(u(e,n),t,n,i)}function x(e,t,n){if(typeof e==`string`)return{source:b(e,t,n)};let i=u(e,n),a=d(i.description,`${n}.description`);return i.source===void 0&&typeof i.path==`string`?(p(i,[`path`,`description`],n),{source:{type:`local`,path:r.default.resolve(t,f(i.path,`${n}.path`))},...a?{description:a}:{}}):typeof i.source==`string`&&![`local`,`url`,`git-subdir`,`npm`].includes(i.source)||l(i.source)?(p(i,[`source`,`description`],n),{source:b(i.source,t,`${n}.source`),...a?{description:a}:{}}):{source:y(i,t,n),...a?{description:a}:{}}}function S(e){let t=r.default.resolve(e);for(let e of c){let n=r.default.normalize(e);if(!t.endsWith(n))continue;let i=t;for(let t of e.split(`/`))i=r.default.dirname(i);return i}}function C(e){if(n.default.existsSync(e)&&n.default.statSync(e).isFile()){let t=S(e);return t?{manifestPath:r.default.resolve(e),root:t}:void 0}for(let t of c){let i=r.default.join(e,t);if(n.default.existsSync(i)&&n.default.statSync(i).isFile())return{manifestPath:r.default.resolve(i),root:r.default.resolve(e)}}}function w(e,t){let r;try{r=JSON.parse(n.default.readFileSync(e,`utf8`))}catch(n){throw Error(`${t} at ${e} is invalid JSON: ${n instanceof Error?n.message:String(n)}`)}return u(r,`${t} at ${e}`)}function T(e){let t=r.default.join(e,`plugin.json`);try{let e=n.default.lstatSync(t);if(e.isSymbolicLink()||!e.isFile())return;let r=JSON.parse(n.default.readFileSync(t,`utf8`));if((l(r)&&typeof r.$schema==`string`?r.$schema:void 0)?.startsWith(i))return t}catch{}return s.map(t=>r.default.join(e,t)).find(e=>n.default.existsSync(e)&&n.default.statSync(e).isFile())}function E(e,t){let n=T(e);if(n)try{let e=w(n,`Plugin manifest`),t=d(e.$schema,`${n}.$schema`),r=d(e.name,`${n}.name`),a=d(e.version,`${n}.version`),o=d(e.description,`${n}.description`);return{path:n,...r?{name:r}:{},...a?{version:a}:{},...o?{description:o}:{},...t?.startsWith(i)?{agentPluginSchema:t}:{}}}catch(e){return t.push(e instanceof Error?e.message:String(e)),{path:n}}}function D(e,t,n){let i=n.length,a=E(e,n);if(!a||n.length!==i)return!1;let o=a.name??r.default.basename(e);try{m(o,`Plugin name in ${a.path}`)}catch(e){return n.push(e instanceof Error?e.message:String(e)),!1}return t[o]={source:{type:`local`,path:e},...a.description?{description:a.description}:{},manifest:a},!0}function O(e,t,i){if(!n.default.existsSync(e)||!n.default.statSync(e).isDirectory())return 0;if(T(e))return+!!D(e,t,i);let a=0,o=n.default.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isDirectory()).sort((e,t)=>e.name.localeCompare(t.name));for(let n of o)D(r.default.join(e,n.name),t,i)&&(a+=1);return a}function k(e,t,n){let r=w(e.manifestPath,`Marketplace manifest`),i=f(r.name,`${e.manifestPath}.name`);if(m(i,`${e.manifestPath}.name`),!Array.isArray(r.plugins))throw Error(`${e.manifestPath}.plugins must be an array`);for(let a=0;a<r.plugins.length;a+=1){let o=`${e.manifestPath}.plugins[${a}]`;try{let s=u(r.plugins[a],o),c=f(s.name,`${o}.name`);m(c,`${o}.name`);let l=`${c}@${i}`;if(Object.hasOwn(t,l))continue;let p=b(s.source,e.root,`${o}.source`,e),h=d(s.description,`${o}.description`),g=p.type===`local`?E(p.path,n):void 0,_=h??g?.description;t[l]={source:p,marketplace:i,..._?{description:_}:{},...g?{manifest:g}:{}}}catch(e){n.push(e instanceof Error?e.message:String(e))}}}function A(e){if(e.value===void 0)return[];let t=u(e.value,`plugins in ${e.filePath}`);if(p(t,[`roots`,`entries`],`plugins in ${e.filePath}`),t.roots===void 0)return[];if(!Array.isArray(t.roots))throw Error(`plugins.roots in ${e.filePath} must be an array`);return t.roots.map((t,n)=>r.default.resolve(e.baseDirectory,f(t,`plugins.roots[${n}] in ${e.filePath}`)))}function j(e,t,n){if(e.value===void 0)return;let r=u(e.value,`plugins in ${e.filePath}`);if(r.entries===void 0)return;let i=u(r.entries,`plugins.entries in ${e.filePath}`);for(let[r,a]of Object.entries(i)){h(r,`Plugin entry "${r}" in ${e.filePath}`);let i=x(a,e.baseDirectory,`plugins.entries.${r} in ${e.filePath}`),o=i.source.type===`local`?E(i.source.path,n):void 0,s=i.description??o?.description;t[r]={source:i.source,...s?{description:s}:{},...o?{manifest:o}:{}}}}function M(e,n){if(e.type===`local`)return e.path;let i=e.type===`git`?[`git`,e.url,e.path??``,e.ref??``,e.sha??``]:[`npm`,e.package,e.version??``,e.registry??``],a=t.default.createHash(`sha256`).update(JSON.stringify(i)).digest(`hex`);return r.default.join(n,`plugin-cache`,a)}function N(e,t,n){let r=[],i={},a=[...new Set(e.flatMap(A))],o=[n,t,...a],s=[],c=new Set;for(let e of o){let t=C(e);if(t&&!c.has(t.manifestPath)){c.add(t.manifestPath),s.push(t.manifestPath);try{k(t,i,r)}catch(e){r.push(e instanceof Error?e.message:String(e))}}}for(let e of a)C(e)||O(e,i,r)===0&&r.push(`Plugin root contains neither a supported marketplace nor discoverable plugins: ${e}`);for(let t of e)j(t,i,r);return{roots:a,marketplaces:s,entries:i,diagnostics:r}}function P(e){return e.type!==`local`}exports.MARKETPLACE_MANIFEST_RELATIVE_PATHS=c,exports.findPluginManifestPath=T,exports.isRemotePluginSource=P,exports.loadPluginCatalog=N,exports.pluginDirectoryForSource=M;
2
+ //# sourceMappingURL=pluginCatalog.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginCatalog.cjs","names":["path","fs","crypto"],"sources":["../../src/adapters/pluginCatalog.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type {\n GitPluginSource,\n PluginCatalog,\n PluginCatalogEntry,\n PluginManifestMetadata,\n PluginSource,\n} from '../types/domains.ts';\n\nconst AGENT_PLUGIN_SCHEMA_PREFIX = 'https://agent-plugins.org/schemas/';\nconst CACHE_DIRECTORY = 'plugin-cache';\nconst PLUGIN_ID_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nconst NPM_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/;\nconst LEGACY_PLUGIN_MANIFEST_PATHS = [\n '.codex-plugin/plugin.json',\n '.claude-plugin/plugin.json',\n '.cursor-plugin/plugin.json',\n] as const;\n\nexport const MARKETPLACE_MANIFEST_RELATIVE_PATHS = [\n '.agents/plugins/marketplace.json',\n '.agents/plugins/api_marketplace.json',\n '.claude-plugin/marketplace.json',\n '.cursor-plugin/marketplace.json',\n] as const;\n\nexport interface PluginCatalogConfigSource {\n filePath: string;\n baseDirectory: string;\n value: unknown;\n}\n\ninterface MarketplaceLocation {\n manifestPath: string;\n root: string;\n}\n\ninterface ParsedConfiguredEntry {\n source: PluginSource;\n description?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requireRecord(value: unknown, label: string): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(`${label} must be an object`);\n return value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction requireString(value: unknown, label: string): string {\n const result = optionalString(value, label);\n if (!result) throw new Error(`${label} must be a non-empty string`);\n return result;\n}\n\nfunction assertOnlyKeys(record: Record<string, unknown>, allowed: readonly string[], label: string): void {\n const unexpected = Object.keys(record).filter((key) => !allowed.includes(key));\n if (unexpected.length > 0) throw new Error(`${label} contains unsupported field \"${unexpected[0]}\"`);\n}\n\nfunction validatePluginIdSegment(value: string, label: string): void {\n if (!PLUGIN_ID_SEGMENT.test(value)) {\n throw new Error(`${label} must start with an alphanumeric character and contain only alphanumerics, ., _, or -`);\n }\n}\n\nfunction validatePluginId(value: string, label: string): void {\n const segments = value.split('@');\n if (segments.length > 2 || segments.some((segment) => !PLUGIN_ID_SEGMENT.test(segment))) {\n throw new Error(`${label} must be a plugin name or plugin@marketplace identifier`);\n }\n}\n\nfunction normalizeRemoteSubdirectory(value: unknown, label: string): string | undefined {\n const raw = optionalString(value, label);\n if (!raw) return undefined;\n const normalized = raw.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n if (\n normalized.startsWith('/') ||\n normalized.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')\n ) {\n throw new Error(`${label} must stay within the remote repository root`);\n }\n return normalized;\n}\n\nfunction normalizeGitUrl(value: unknown, baseDirectory: string, label: string): string {\n const url = requireString(value, label);\n if (/^(?:https?|ssh|file):\\/\\//.test(url) || /^git@[^:]+:.+/.test(url) || path.isAbsolute(url)) return url;\n if (url.startsWith('./') || url.startsWith('.\\\\')) {\n const relative = url.replaceAll('\\\\', '/').slice(2);\n if (!relative || relative.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')) {\n throw new Error(`${label} must stay within its declaring root`);\n }\n return path.resolve(baseDirectory, relative);\n }\n if (/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+(?:\\.git)?$/.test(url)) {\n return `https://github.com/${url.endsWith('.git') ? url : `${url}.git`}`;\n }\n throw new Error(`${label} is not a supported Git URL`);\n}\n\nfunction resolveMarketplaceLocalPath(rawPath: string, marketplace: MarketplaceLocation, label: string): string {\n if (rawPath === '.' || rawPath === './') return marketplace.root;\n const cursorMarketplace = marketplace.manifestPath.endsWith('.cursor-plugin/marketplace.json');\n const relative = rawPath.startsWith('./') ? rawPath.slice(2) : cursorMarketplace ? rawPath : undefined;\n if (!relative) throw new Error(`${label} must start with ./`);\n const normalized = relative.replaceAll('\\\\', '/');\n if (normalized.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')) {\n throw new Error(`${label} must stay within the marketplace root`);\n }\n return path.resolve(marketplace.root, normalized);\n}\n\nfunction parseSourceObject(\n value: Record<string, unknown>,\n baseDirectory: string,\n label: string,\n marketplace?: MarketplaceLocation,\n): PluginSource {\n const sourceType = requireString(value.source, `${label}.source`);\n if (sourceType === 'local') {\n assertOnlyKeys(value, ['source', 'path', 'description'], label);\n const rawPath = requireString(value.path, `${label}.path`);\n return {\n type: 'local',\n path: marketplace\n ? resolveMarketplaceLocalPath(rawPath, marketplace, `${label}.path`)\n : path.resolve(baseDirectory, rawPath),\n };\n }\n if (sourceType === 'url' || sourceType === 'git-subdir') {\n assertOnlyKeys(value, ['source', 'url', 'path', 'ref', 'sha', 'description'], label);\n const remotePath = normalizeRemoteSubdirectory(value.path, `${label}.path`);\n if (sourceType === 'git-subdir' && !remotePath) {\n throw new Error(`${label}.path must be a non-empty string for git-subdir sources`);\n }\n const ref = optionalString(value.ref, `${label}.ref`);\n const sha = optionalString(value.sha, `${label}.sha`);\n return {\n type: 'git',\n url: normalizeGitUrl(value.url, marketplace?.root ?? baseDirectory, `${label}.url`),\n ...(remotePath ? { path: remotePath } : {}),\n ...(ref ? { ref } : {}),\n ...(sha ? { sha } : {}),\n };\n }\n if (sourceType === 'npm') {\n assertOnlyKeys(value, ['source', 'package', 'version', 'registry', 'description'], label);\n const packageName = requireString(value.package, `${label}.package`);\n if (!NPM_PACKAGE_NAME.test(packageName)) throw new Error(`${label}.package must be a valid npm package name`);\n const version = optionalString(value.version, `${label}.version`);\n const registry = optionalString(value.registry, `${label}.registry`);\n return {\n type: 'npm',\n package: packageName,\n ...(version ? { version } : {}),\n ...(registry ? { registry } : {}),\n };\n }\n throw new Error(`${label}.source must be local, url, git-subdir, or npm`);\n}\n\nfunction parsePluginSource(\n value: unknown,\n baseDirectory: string,\n label: string,\n marketplace?: MarketplaceLocation,\n): PluginSource {\n if (typeof value === 'string') {\n const rawPath = requireString(value, label);\n return {\n type: 'local',\n path: marketplace\n ? resolveMarketplaceLocalPath(rawPath, marketplace, label)\n : path.resolve(baseDirectory, rawPath),\n };\n }\n return parseSourceObject(requireRecord(value, label), baseDirectory, label, marketplace);\n}\n\nfunction parseConfiguredEntry(value: unknown, baseDirectory: string, label: string): ParsedConfiguredEntry {\n if (typeof value === 'string') return { source: parsePluginSource(value, baseDirectory, label) };\n const record = requireRecord(value, label);\n const description = optionalString(record.description, `${label}.description`);\n if (record.source === undefined && typeof record.path === 'string') {\n assertOnlyKeys(record, ['path', 'description'], label);\n return {\n source: { type: 'local', path: path.resolve(baseDirectory, requireString(record.path, `${label}.path`)) },\n ...(description ? { description } : {}),\n };\n }\n if (typeof record.source === 'string' && !['local', 'url', 'git-subdir', 'npm'].includes(record.source)) {\n assertOnlyKeys(record, ['source', 'description'], label);\n return {\n source: parsePluginSource(record.source, baseDirectory, `${label}.source`),\n ...(description ? { description } : {}),\n };\n }\n if (isRecord(record.source)) {\n assertOnlyKeys(record, ['source', 'description'], label);\n return {\n source: parsePluginSource(record.source, baseDirectory, `${label}.source`),\n ...(description ? { description } : {}),\n };\n }\n return {\n source: parseSourceObject(record, baseDirectory, label),\n ...(description ? { description } : {}),\n };\n}\n\nfunction marketplaceRootFromManifest(manifestPath: string): string | undefined {\n const normalized = path.resolve(manifestPath);\n for (const relativePath of MARKETPLACE_MANIFEST_RELATIVE_PATHS) {\n const suffix = path.normalize(relativePath);\n if (!normalized.endsWith(suffix)) continue;\n let root = normalized;\n for (const _segment of relativePath.split('/')) root = path.dirname(root);\n return root;\n }\n return undefined;\n}\n\nfunction findMarketplace(rootOrManifest: string): MarketplaceLocation | undefined {\n if (fs.existsSync(rootOrManifest) && fs.statSync(rootOrManifest).isFile()) {\n const root = marketplaceRootFromManifest(rootOrManifest);\n return root ? { manifestPath: path.resolve(rootOrManifest), root } : undefined;\n }\n for (const relativePath of MARKETPLACE_MANIFEST_RELATIVE_PATHS) {\n const manifestPath = path.join(rootOrManifest, relativePath);\n if (fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile()) {\n return { manifestPath: path.resolve(manifestPath), root: path.resolve(rootOrManifest) };\n }\n }\n return undefined;\n}\n\nfunction readJsonRecord(filePath: string, label: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as unknown;\n } catch (error) {\n throw new Error(\n `${label} at ${filePath} is invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n return requireRecord(parsed, `${label} at ${filePath}`);\n}\n\n/** Matches Codex manifest precedence, including schema-gated root plugin.json. */\nexport function findPluginManifestPath(pluginRoot: string): string | undefined {\n const rootManifest = path.join(pluginRoot, 'plugin.json');\n try {\n const metadata = fs.lstatSync(rootManifest);\n if (metadata.isSymbolicLink() || !metadata.isFile()) return undefined;\n const parsed = JSON.parse(fs.readFileSync(rootManifest, 'utf8')) as unknown;\n const schema = isRecord(parsed) && typeof parsed.$schema === 'string' ? parsed.$schema : undefined;\n if (schema?.startsWith(AGENT_PLUGIN_SCHEMA_PREFIX)) return rootManifest;\n } catch {\n // A missing, unreadable, or unrelated root manifest does not outrank legacy manifests.\n }\n return LEGACY_PLUGIN_MANIFEST_PATHS.map((relativePath) => path.join(pluginRoot, relativePath)).find(\n (manifestPath) => fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile(),\n );\n}\n\nfunction readPluginManifestMetadata(pluginRoot: string, diagnostics: string[]): PluginManifestMetadata | undefined {\n const manifestPath = findPluginManifestPath(pluginRoot);\n if (!manifestPath) return undefined;\n try {\n const manifest = readJsonRecord(manifestPath, 'Plugin manifest');\n const schema = optionalString(manifest.$schema, `${manifestPath}.$schema`);\n const name = optionalString(manifest.name, `${manifestPath}.name`);\n const version = optionalString(manifest.version, `${manifestPath}.version`);\n const description = optionalString(manifest.description, `${manifestPath}.description`);\n return {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(schema?.startsWith(AGENT_PLUGIN_SCHEMA_PREFIX) ? { agentPluginSchema: schema } : {}),\n };\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n return { path: manifestPath };\n }\n}\n\nfunction discoverPluginRoot(\n pluginRoot: string,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): boolean {\n const diagnosticCount = diagnostics.length;\n const manifest = readPluginManifestMetadata(pluginRoot, diagnostics);\n if (!manifest || diagnostics.length !== diagnosticCount) return false;\n const name = manifest.name ?? path.basename(pluginRoot);\n try {\n validatePluginIdSegment(name, `Plugin name in ${manifest.path}`);\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n return false;\n }\n entries[name] = {\n source: { type: 'local', path: pluginRoot },\n ...(manifest.description ? { description: manifest.description } : {}),\n manifest,\n };\n return true;\n}\n\nfunction discoverPluginFolder(\n root: string,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): number {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) return 0;\n if (findPluginManifestPath(root)) return discoverPluginRoot(root, entries, diagnostics) ? 1 : 0;\n\n let discovered = 0;\n const children = fs\n .readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .sort((left, right) => left.name.localeCompare(right.name));\n for (const child of children) {\n if (discoverPluginRoot(path.join(root, child.name), entries, diagnostics)) discovered += 1;\n }\n return discovered;\n}\n\nfunction parseMarketplace(\n marketplace: MarketplaceLocation,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): void {\n const document = readJsonRecord(marketplace.manifestPath, 'Marketplace manifest');\n const marketplaceName = requireString(document.name, `${marketplace.manifestPath}.name`);\n validatePluginIdSegment(marketplaceName, `${marketplace.manifestPath}.name`);\n if (!Array.isArray(document.plugins)) throw new Error(`${marketplace.manifestPath}.plugins must be an array`);\n for (let index = 0; index < document.plugins.length; index += 1) {\n const label = `${marketplace.manifestPath}.plugins[${index}]`;\n try {\n const plugin = requireRecord(document.plugins[index], label);\n const pluginName = requireString(plugin.name, `${label}.name`);\n validatePluginIdSegment(pluginName, `${label}.name`);\n const id = `${pluginName}@${marketplaceName}`;\n if (Object.hasOwn(entries, id)) continue;\n const source = parsePluginSource(plugin.source, marketplace.root, `${label}.source`, marketplace);\n const description = optionalString(plugin.description, `${label}.description`);\n const manifest = source.type === 'local' ? readPluginManifestMetadata(source.path, diagnostics) : undefined;\n const resolvedDescription = description ?? manifest?.description;\n entries[id] = {\n source,\n marketplace: marketplaceName,\n ...(resolvedDescription ? { description: resolvedDescription } : {}),\n ...(manifest ? { manifest } : {}),\n };\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n }\n }\n}\n\nfunction parseConfiguredRoots(source: PluginCatalogConfigSource): string[] {\n if (source.value === undefined) return [];\n const document = requireRecord(source.value, `plugins in ${source.filePath}`);\n assertOnlyKeys(document, ['roots', 'entries'], `plugins in ${source.filePath}`);\n if (document.roots === undefined) return [];\n if (!Array.isArray(document.roots)) throw new Error(`plugins.roots in ${source.filePath} must be an array`);\n return document.roots.map((root, index) =>\n path.resolve(source.baseDirectory, requireString(root, `plugins.roots[${index}] in ${source.filePath}`)),\n );\n}\n\nfunction applyConfiguredEntries(\n source: PluginCatalogConfigSource,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): void {\n if (source.value === undefined) return;\n const document = requireRecord(source.value, `plugins in ${source.filePath}`);\n if (document.entries === undefined) return;\n const configuredEntries = requireRecord(document.entries, `plugins.entries in ${source.filePath}`);\n for (const [name, value] of Object.entries(configuredEntries)) {\n validatePluginId(name, `Plugin entry \"${name}\" in ${source.filePath}`);\n const parsed = parseConfiguredEntry(value, source.baseDirectory, `plugins.entries.${name} in ${source.filePath}`);\n const manifest =\n parsed.source.type === 'local' ? readPluginManifestMetadata(parsed.source.path, diagnostics) : undefined;\n const description = parsed.description ?? manifest?.description;\n entries[name] = {\n source: parsed.source,\n ...(description ? { description } : {}),\n ...(manifest ? { manifest } : {}),\n };\n }\n}\n\nexport function pluginDirectoryForSource(source: PluginSource, homeDoomDirectory: string): string {\n if (source.type === 'local') return source.path;\n const identity =\n source.type === 'git'\n ? ['git', source.url, source.path ?? '', source.ref ?? '', source.sha ?? '']\n : ['npm', source.package, source.version ?? '', source.registry ?? ''];\n const digest = crypto.createHash('sha256').update(JSON.stringify(identity)).digest('hex');\n return path.join(homeDoomDirectory, CACHE_DIRECTORY, digest);\n}\n\nexport function loadPluginCatalog(\n sources: readonly PluginCatalogConfigSource[],\n repoRoot: string,\n homeDirectory: string,\n): PluginCatalog {\n const diagnostics: string[] = [];\n const entries: Record<string, PluginCatalogEntry> = {};\n const roots = [...new Set(sources.flatMap(parseConfiguredRoots))];\n const candidates = [homeDirectory, repoRoot, ...roots];\n const marketplaces: string[] = [];\n const seenMarketplaces = new Set<string>();\n\n for (const candidate of candidates) {\n const marketplace = findMarketplace(candidate);\n if (!marketplace) continue;\n if (seenMarketplaces.has(marketplace.manifestPath)) continue;\n seenMarketplaces.add(marketplace.manifestPath);\n marketplaces.push(marketplace.manifestPath);\n try {\n parseMarketplace(marketplace, entries, diagnostics);\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n }\n }\n\n for (const root of roots) {\n if (findMarketplace(root)) continue;\n if (discoverPluginFolder(root, entries, diagnostics) === 0) {\n diagnostics.push(`Plugin root contains neither a supported marketplace nor discoverable plugins: ${root}`);\n }\n }\n\n for (const source of sources) applyConfiguredEntries(source, entries, diagnostics);\n return { roots, marketplaces, entries, diagnostics };\n}\n\nexport function isRemotePluginSource(\n source: PluginSource,\n): source is GitPluginSource | Extract<PluginSource, { type: 'npm' }> {\n return source.type !== 'local';\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { GitPluginSource, PluginSource } from "../types/domains.cjs";
2
+ //#region src/adapters/pluginCatalog.d.ts
3
+ declare const MARKETPLACE_MANIFEST_RELATIVE_PATHS: readonly [".agents/plugins/marketplace.json", ".agents/plugins/api_marketplace.json", ".claude-plugin/marketplace.json", ".cursor-plugin/marketplace.json"];
4
+ /** Matches Codex manifest precedence, including schema-gated root plugin.json. */
5
+ declare function findPluginManifestPath(pluginRoot: string): string | undefined;
6
+ declare function pluginDirectoryForSource(source: PluginSource, homeDoomDirectory: string): string;
7
+ declare function isRemotePluginSource(source: PluginSource): source is GitPluginSource | Extract<PluginSource, {
8
+ type: 'npm';
9
+ }>;
10
+ //#endregion
11
+ export { MARKETPLACE_MANIFEST_RELATIVE_PATHS, findPluginManifestPath, isRemotePluginSource, pluginDirectoryForSource };
12
+ //# sourceMappingURL=pluginCatalog.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginCatalog.d.cts","names":[],"sources":["../../src/adapters/pluginCatalog.ts"],"mappings":";;cAqBa;;iBAgPG,uBAAuB;iBAmJvB,yBAAyB,QAAQ,cAAc;iBA8C/C,qBACd,QAAQ,eACP,UAAU,kBAAkB,QAAQ;EAAgB"}
@@ -0,0 +1,12 @@
1
+ import { GitPluginSource, PluginSource } from "../types/domains.mjs";
2
+ //#region src/adapters/pluginCatalog.d.ts
3
+ declare const MARKETPLACE_MANIFEST_RELATIVE_PATHS: readonly [".agents/plugins/marketplace.json", ".agents/plugins/api_marketplace.json", ".claude-plugin/marketplace.json", ".cursor-plugin/marketplace.json"];
4
+ /** Matches Codex manifest precedence, including schema-gated root plugin.json. */
5
+ declare function findPluginManifestPath(pluginRoot: string): string | undefined;
6
+ declare function pluginDirectoryForSource(source: PluginSource, homeDoomDirectory: string): string;
7
+ declare function isRemotePluginSource(source: PluginSource): source is GitPluginSource | Extract<PluginSource, {
8
+ type: 'npm';
9
+ }>;
10
+ //#endregion
11
+ export { MARKETPLACE_MANIFEST_RELATIVE_PATHS, findPluginManifestPath, isRemotePluginSource, pluginDirectoryForSource };
12
+ //# sourceMappingURL=pluginCatalog.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginCatalog.d.mts","names":[],"sources":["../../src/adapters/pluginCatalog.ts"],"mappings":";;cAqBa;;iBAgPG,uBAAuB;iBAmJvB,yBAAyB,QAAQ,cAAc;iBA8C/C,qBACd,QAAQ,eACP,UAAU,kBAAkB,QAAQ;EAAgB"}
@@ -0,0 +1,2 @@
1
+ import e from"node:crypto";import t from"node:fs";import n from"node:path";const r=`https://agent-plugins.org/schemas/`,i=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,a=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,o=[`.codex-plugin/plugin.json`,`.claude-plugin/plugin.json`,`.cursor-plugin/plugin.json`],s=[`.agents/plugins/marketplace.json`,`.agents/plugins/api_marketplace.json`,`.claude-plugin/marketplace.json`,`.cursor-plugin/marketplace.json`];function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e,t){if(!c(e))throw Error(`${t} must be an object`);return e}function u(e,t){if(e!==void 0){if(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}}function d(e,t){let n=u(e,t);if(!n)throw Error(`${t} must be a non-empty string`);return n}function f(e,t,n){let r=Object.keys(e).filter(e=>!t.includes(e));if(r.length>0)throw Error(`${n} contains unsupported field "${r[0]}"`)}function p(e,t){if(!i.test(e))throw Error(`${t} must start with an alphanumeric character and contain only alphanumerics, ., _, or -`)}function m(e,t){let n=e.split(`@`);if(n.length>2||n.some(e=>!i.test(e)))throw Error(`${t} must be a plugin name or plugin@marketplace identifier`)}function h(e,t){let n=u(e,t);if(!n)return;let r=n.replaceAll(`\\`,`/`).replace(/^\.\//,``);if(r.startsWith(`/`)||r.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${t} must stay within the remote repository root`);return r}function g(e,t,r){let i=d(e,r);if(/^(?:https?|ssh|file):\/\//.test(i)||/^git@[^:]+:.+/.test(i)||n.isAbsolute(i))return i;if(i.startsWith(`./`)||i.startsWith(`.\\`)){let e=i.replaceAll(`\\`,`/`).slice(2);if(!e||e.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${r} must stay within its declaring root`);return n.resolve(t,e)}if(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\.git)?$/.test(i))return`https://github.com/${i.endsWith(`.git`)?i:`${i}.git`}`;throw Error(`${r} is not a supported Git URL`)}function _(e,t,r){if(e===`.`||e===`./`)return t.root;let i=t.manifestPath.endsWith(`.cursor-plugin/marketplace.json`),a=e.startsWith(`./`)?e.slice(2):i?e:void 0;if(!a)throw Error(`${r} must start with ./`);let o=a.replaceAll(`\\`,`/`);if(o.split(`/`).some(e=>e===``||e===`.`||e===`..`))throw Error(`${r} must stay within the marketplace root`);return n.resolve(t.root,o)}function v(e,t,r,i){let o=d(e.source,`${r}.source`);if(o===`local`){f(e,[`source`,`path`,`description`],r);let a=d(e.path,`${r}.path`);return{type:`local`,path:i?_(a,i,`${r}.path`):n.resolve(t,a)}}if(o===`url`||o===`git-subdir`){f(e,[`source`,`url`,`path`,`ref`,`sha`,`description`],r);let n=h(e.path,`${r}.path`);if(o===`git-subdir`&&!n)throw Error(`${r}.path must be a non-empty string for git-subdir sources`);let a=u(e.ref,`${r}.ref`),s=u(e.sha,`${r}.sha`);return{type:`git`,url:g(e.url,i?.root??t,`${r}.url`),...n?{path:n}:{},...a?{ref:a}:{},...s?{sha:s}:{}}}if(o===`npm`){f(e,[`source`,`package`,`version`,`registry`,`description`],r);let t=d(e.package,`${r}.package`);if(!a.test(t))throw Error(`${r}.package must be a valid npm package name`);let n=u(e.version,`${r}.version`),i=u(e.registry,`${r}.registry`);return{type:`npm`,package:t,...n?{version:n}:{},...i?{registry:i}:{}}}throw Error(`${r}.source must be local, url, git-subdir, or npm`)}function y(e,t,r,i){if(typeof e==`string`){let a=d(e,r);return{type:`local`,path:i?_(a,i,r):n.resolve(t,a)}}return v(l(e,r),t,r,i)}function b(e,t,r){if(typeof e==`string`)return{source:y(e,t,r)};let i=l(e,r),a=u(i.description,`${r}.description`);return i.source===void 0&&typeof i.path==`string`?(f(i,[`path`,`description`],r),{source:{type:`local`,path:n.resolve(t,d(i.path,`${r}.path`))},...a?{description:a}:{}}):typeof i.source==`string`&&![`local`,`url`,`git-subdir`,`npm`].includes(i.source)||c(i.source)?(f(i,[`source`,`description`],r),{source:y(i.source,t,`${r}.source`),...a?{description:a}:{}}):{source:v(i,t,r),...a?{description:a}:{}}}function x(e){let t=n.resolve(e);for(let e of s){let r=n.normalize(e);if(!t.endsWith(r))continue;let i=t;for(let t of e.split(`/`))i=n.dirname(i);return i}}function S(e){if(t.existsSync(e)&&t.statSync(e).isFile()){let t=x(e);return t?{manifestPath:n.resolve(e),root:t}:void 0}for(let r of s){let i=n.join(e,r);if(t.existsSync(i)&&t.statSync(i).isFile())return{manifestPath:n.resolve(i),root:n.resolve(e)}}}function C(e,n){let r;try{r=JSON.parse(t.readFileSync(e,`utf8`))}catch(t){throw Error(`${n} at ${e} is invalid JSON: ${t instanceof Error?t.message:String(t)}`)}return l(r,`${n} at ${e}`)}function w(e){let i=n.join(e,`plugin.json`);try{let e=t.lstatSync(i);if(e.isSymbolicLink()||!e.isFile())return;let n=JSON.parse(t.readFileSync(i,`utf8`));if((c(n)&&typeof n.$schema==`string`?n.$schema:void 0)?.startsWith(r))return i}catch{}return o.map(t=>n.join(e,t)).find(e=>t.existsSync(e)&&t.statSync(e).isFile())}function T(e,t){let n=w(e);if(n)try{let e=C(n,`Plugin manifest`),t=u(e.$schema,`${n}.$schema`),i=u(e.name,`${n}.name`),a=u(e.version,`${n}.version`),o=u(e.description,`${n}.description`);return{path:n,...i?{name:i}:{},...a?{version:a}:{},...o?{description:o}:{},...t?.startsWith(r)?{agentPluginSchema:t}:{}}}catch(e){return t.push(e instanceof Error?e.message:String(e)),{path:n}}}function E(e,t,r){let i=r.length,a=T(e,r);if(!a||r.length!==i)return!1;let o=a.name??n.basename(e);try{p(o,`Plugin name in ${a.path}`)}catch(e){return r.push(e instanceof Error?e.message:String(e)),!1}return t[o]={source:{type:`local`,path:e},...a.description?{description:a.description}:{},manifest:a},!0}function D(e,r,i){if(!t.existsSync(e)||!t.statSync(e).isDirectory())return 0;if(w(e))return+!!E(e,r,i);let a=0,o=t.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isDirectory()).sort((e,t)=>e.name.localeCompare(t.name));for(let t of o)E(n.join(e,t.name),r,i)&&(a+=1);return a}function O(e,t,n){let r=C(e.manifestPath,`Marketplace manifest`),i=d(r.name,`${e.manifestPath}.name`);if(p(i,`${e.manifestPath}.name`),!Array.isArray(r.plugins))throw Error(`${e.manifestPath}.plugins must be an array`);for(let a=0;a<r.plugins.length;a+=1){let o=`${e.manifestPath}.plugins[${a}]`;try{let s=l(r.plugins[a],o),c=d(s.name,`${o}.name`);p(c,`${o}.name`);let f=`${c}@${i}`;if(Object.hasOwn(t,f))continue;let m=y(s.source,e.root,`${o}.source`,e),h=u(s.description,`${o}.description`),g=m.type===`local`?T(m.path,n):void 0,_=h??g?.description;t[f]={source:m,marketplace:i,..._?{description:_}:{},...g?{manifest:g}:{}}}catch(e){n.push(e instanceof Error?e.message:String(e))}}}function k(e){if(e.value===void 0)return[];let t=l(e.value,`plugins in ${e.filePath}`);if(f(t,[`roots`,`entries`],`plugins in ${e.filePath}`),t.roots===void 0)return[];if(!Array.isArray(t.roots))throw Error(`plugins.roots in ${e.filePath} must be an array`);return t.roots.map((t,r)=>n.resolve(e.baseDirectory,d(t,`plugins.roots[${r}] in ${e.filePath}`)))}function A(e,t,n){if(e.value===void 0)return;let r=l(e.value,`plugins in ${e.filePath}`);if(r.entries===void 0)return;let i=l(r.entries,`plugins.entries in ${e.filePath}`);for(let[r,a]of Object.entries(i)){m(r,`Plugin entry "${r}" in ${e.filePath}`);let i=b(a,e.baseDirectory,`plugins.entries.${r} in ${e.filePath}`),o=i.source.type===`local`?T(i.source.path,n):void 0,s=i.description??o?.description;t[r]={source:i.source,...s?{description:s}:{},...o?{manifest:o}:{}}}}function j(t,r){if(t.type===`local`)return t.path;let i=t.type===`git`?[`git`,t.url,t.path??``,t.ref??``,t.sha??``]:[`npm`,t.package,t.version??``,t.registry??``],a=e.createHash(`sha256`).update(JSON.stringify(i)).digest(`hex`);return n.join(r,`plugin-cache`,a)}function M(e,t,n){let r=[],i={},a=[...new Set(e.flatMap(k))],o=[n,t,...a],s=[],c=new Set;for(let e of o){let t=S(e);if(t&&!c.has(t.manifestPath)){c.add(t.manifestPath),s.push(t.manifestPath);try{O(t,i,r)}catch(e){r.push(e instanceof Error?e.message:String(e))}}}for(let e of a)S(e)||D(e,i,r)===0&&r.push(`Plugin root contains neither a supported marketplace nor discoverable plugins: ${e}`);for(let t of e)A(t,i,r);return{roots:a,marketplaces:s,entries:i,diagnostics:r}}function N(e){return e.type!==`local`}export{s as MARKETPLACE_MANIFEST_RELATIVE_PATHS,w as findPluginManifestPath,N as isRemotePluginSource,M as loadPluginCatalog,j as pluginDirectoryForSource};
2
+ //# sourceMappingURL=pluginCatalog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginCatalog.mjs","names":[],"sources":["../../src/adapters/pluginCatalog.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type {\n GitPluginSource,\n PluginCatalog,\n PluginCatalogEntry,\n PluginManifestMetadata,\n PluginSource,\n} from '../types/domains.ts';\n\nconst AGENT_PLUGIN_SCHEMA_PREFIX = 'https://agent-plugins.org/schemas/';\nconst CACHE_DIRECTORY = 'plugin-cache';\nconst PLUGIN_ID_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nconst NPM_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/;\nconst LEGACY_PLUGIN_MANIFEST_PATHS = [\n '.codex-plugin/plugin.json',\n '.claude-plugin/plugin.json',\n '.cursor-plugin/plugin.json',\n] as const;\n\nexport const MARKETPLACE_MANIFEST_RELATIVE_PATHS = [\n '.agents/plugins/marketplace.json',\n '.agents/plugins/api_marketplace.json',\n '.claude-plugin/marketplace.json',\n '.cursor-plugin/marketplace.json',\n] as const;\n\nexport interface PluginCatalogConfigSource {\n filePath: string;\n baseDirectory: string;\n value: unknown;\n}\n\ninterface MarketplaceLocation {\n manifestPath: string;\n root: string;\n}\n\ninterface ParsedConfiguredEntry {\n source: PluginSource;\n description?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requireRecord(value: unknown, label: string): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(`${label} must be an object`);\n return value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction requireString(value: unknown, label: string): string {\n const result = optionalString(value, label);\n if (!result) throw new Error(`${label} must be a non-empty string`);\n return result;\n}\n\nfunction assertOnlyKeys(record: Record<string, unknown>, allowed: readonly string[], label: string): void {\n const unexpected = Object.keys(record).filter((key) => !allowed.includes(key));\n if (unexpected.length > 0) throw new Error(`${label} contains unsupported field \"${unexpected[0]}\"`);\n}\n\nfunction validatePluginIdSegment(value: string, label: string): void {\n if (!PLUGIN_ID_SEGMENT.test(value)) {\n throw new Error(`${label} must start with an alphanumeric character and contain only alphanumerics, ., _, or -`);\n }\n}\n\nfunction validatePluginId(value: string, label: string): void {\n const segments = value.split('@');\n if (segments.length > 2 || segments.some((segment) => !PLUGIN_ID_SEGMENT.test(segment))) {\n throw new Error(`${label} must be a plugin name or plugin@marketplace identifier`);\n }\n}\n\nfunction normalizeRemoteSubdirectory(value: unknown, label: string): string | undefined {\n const raw = optionalString(value, label);\n if (!raw) return undefined;\n const normalized = raw.replaceAll('\\\\', '/').replace(/^\\.\\//, '');\n if (\n normalized.startsWith('/') ||\n normalized.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')\n ) {\n throw new Error(`${label} must stay within the remote repository root`);\n }\n return normalized;\n}\n\nfunction normalizeGitUrl(value: unknown, baseDirectory: string, label: string): string {\n const url = requireString(value, label);\n if (/^(?:https?|ssh|file):\\/\\//.test(url) || /^git@[^:]+:.+/.test(url) || path.isAbsolute(url)) return url;\n if (url.startsWith('./') || url.startsWith('.\\\\')) {\n const relative = url.replaceAll('\\\\', '/').slice(2);\n if (!relative || relative.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')) {\n throw new Error(`${label} must stay within its declaring root`);\n }\n return path.resolve(baseDirectory, relative);\n }\n if (/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+(?:\\.git)?$/.test(url)) {\n return `https://github.com/${url.endsWith('.git') ? url : `${url}.git`}`;\n }\n throw new Error(`${label} is not a supported Git URL`);\n}\n\nfunction resolveMarketplaceLocalPath(rawPath: string, marketplace: MarketplaceLocation, label: string): string {\n if (rawPath === '.' || rawPath === './') return marketplace.root;\n const cursorMarketplace = marketplace.manifestPath.endsWith('.cursor-plugin/marketplace.json');\n const relative = rawPath.startsWith('./') ? rawPath.slice(2) : cursorMarketplace ? rawPath : undefined;\n if (!relative) throw new Error(`${label} must start with ./`);\n const normalized = relative.replaceAll('\\\\', '/');\n if (normalized.split('/').some((segment) => segment === '' || segment === '.' || segment === '..')) {\n throw new Error(`${label} must stay within the marketplace root`);\n }\n return path.resolve(marketplace.root, normalized);\n}\n\nfunction parseSourceObject(\n value: Record<string, unknown>,\n baseDirectory: string,\n label: string,\n marketplace?: MarketplaceLocation,\n): PluginSource {\n const sourceType = requireString(value.source, `${label}.source`);\n if (sourceType === 'local') {\n assertOnlyKeys(value, ['source', 'path', 'description'], label);\n const rawPath = requireString(value.path, `${label}.path`);\n return {\n type: 'local',\n path: marketplace\n ? resolveMarketplaceLocalPath(rawPath, marketplace, `${label}.path`)\n : path.resolve(baseDirectory, rawPath),\n };\n }\n if (sourceType === 'url' || sourceType === 'git-subdir') {\n assertOnlyKeys(value, ['source', 'url', 'path', 'ref', 'sha', 'description'], label);\n const remotePath = normalizeRemoteSubdirectory(value.path, `${label}.path`);\n if (sourceType === 'git-subdir' && !remotePath) {\n throw new Error(`${label}.path must be a non-empty string for git-subdir sources`);\n }\n const ref = optionalString(value.ref, `${label}.ref`);\n const sha = optionalString(value.sha, `${label}.sha`);\n return {\n type: 'git',\n url: normalizeGitUrl(value.url, marketplace?.root ?? baseDirectory, `${label}.url`),\n ...(remotePath ? { path: remotePath } : {}),\n ...(ref ? { ref } : {}),\n ...(sha ? { sha } : {}),\n };\n }\n if (sourceType === 'npm') {\n assertOnlyKeys(value, ['source', 'package', 'version', 'registry', 'description'], label);\n const packageName = requireString(value.package, `${label}.package`);\n if (!NPM_PACKAGE_NAME.test(packageName)) throw new Error(`${label}.package must be a valid npm package name`);\n const version = optionalString(value.version, `${label}.version`);\n const registry = optionalString(value.registry, `${label}.registry`);\n return {\n type: 'npm',\n package: packageName,\n ...(version ? { version } : {}),\n ...(registry ? { registry } : {}),\n };\n }\n throw new Error(`${label}.source must be local, url, git-subdir, or npm`);\n}\n\nfunction parsePluginSource(\n value: unknown,\n baseDirectory: string,\n label: string,\n marketplace?: MarketplaceLocation,\n): PluginSource {\n if (typeof value === 'string') {\n const rawPath = requireString(value, label);\n return {\n type: 'local',\n path: marketplace\n ? resolveMarketplaceLocalPath(rawPath, marketplace, label)\n : path.resolve(baseDirectory, rawPath),\n };\n }\n return parseSourceObject(requireRecord(value, label), baseDirectory, label, marketplace);\n}\n\nfunction parseConfiguredEntry(value: unknown, baseDirectory: string, label: string): ParsedConfiguredEntry {\n if (typeof value === 'string') return { source: parsePluginSource(value, baseDirectory, label) };\n const record = requireRecord(value, label);\n const description = optionalString(record.description, `${label}.description`);\n if (record.source === undefined && typeof record.path === 'string') {\n assertOnlyKeys(record, ['path', 'description'], label);\n return {\n source: { type: 'local', path: path.resolve(baseDirectory, requireString(record.path, `${label}.path`)) },\n ...(description ? { description } : {}),\n };\n }\n if (typeof record.source === 'string' && !['local', 'url', 'git-subdir', 'npm'].includes(record.source)) {\n assertOnlyKeys(record, ['source', 'description'], label);\n return {\n source: parsePluginSource(record.source, baseDirectory, `${label}.source`),\n ...(description ? { description } : {}),\n };\n }\n if (isRecord(record.source)) {\n assertOnlyKeys(record, ['source', 'description'], label);\n return {\n source: parsePluginSource(record.source, baseDirectory, `${label}.source`),\n ...(description ? { description } : {}),\n };\n }\n return {\n source: parseSourceObject(record, baseDirectory, label),\n ...(description ? { description } : {}),\n };\n}\n\nfunction marketplaceRootFromManifest(manifestPath: string): string | undefined {\n const normalized = path.resolve(manifestPath);\n for (const relativePath of MARKETPLACE_MANIFEST_RELATIVE_PATHS) {\n const suffix = path.normalize(relativePath);\n if (!normalized.endsWith(suffix)) continue;\n let root = normalized;\n for (const _segment of relativePath.split('/')) root = path.dirname(root);\n return root;\n }\n return undefined;\n}\n\nfunction findMarketplace(rootOrManifest: string): MarketplaceLocation | undefined {\n if (fs.existsSync(rootOrManifest) && fs.statSync(rootOrManifest).isFile()) {\n const root = marketplaceRootFromManifest(rootOrManifest);\n return root ? { manifestPath: path.resolve(rootOrManifest), root } : undefined;\n }\n for (const relativePath of MARKETPLACE_MANIFEST_RELATIVE_PATHS) {\n const manifestPath = path.join(rootOrManifest, relativePath);\n if (fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile()) {\n return { manifestPath: path.resolve(manifestPath), root: path.resolve(rootOrManifest) };\n }\n }\n return undefined;\n}\n\nfunction readJsonRecord(filePath: string, label: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as unknown;\n } catch (error) {\n throw new Error(\n `${label} at ${filePath} is invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n return requireRecord(parsed, `${label} at ${filePath}`);\n}\n\n/** Matches Codex manifest precedence, including schema-gated root plugin.json. */\nexport function findPluginManifestPath(pluginRoot: string): string | undefined {\n const rootManifest = path.join(pluginRoot, 'plugin.json');\n try {\n const metadata = fs.lstatSync(rootManifest);\n if (metadata.isSymbolicLink() || !metadata.isFile()) return undefined;\n const parsed = JSON.parse(fs.readFileSync(rootManifest, 'utf8')) as unknown;\n const schema = isRecord(parsed) && typeof parsed.$schema === 'string' ? parsed.$schema : undefined;\n if (schema?.startsWith(AGENT_PLUGIN_SCHEMA_PREFIX)) return rootManifest;\n } catch {\n // A missing, unreadable, or unrelated root manifest does not outrank legacy manifests.\n }\n return LEGACY_PLUGIN_MANIFEST_PATHS.map((relativePath) => path.join(pluginRoot, relativePath)).find(\n (manifestPath) => fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile(),\n );\n}\n\nfunction readPluginManifestMetadata(pluginRoot: string, diagnostics: string[]): PluginManifestMetadata | undefined {\n const manifestPath = findPluginManifestPath(pluginRoot);\n if (!manifestPath) return undefined;\n try {\n const manifest = readJsonRecord(manifestPath, 'Plugin manifest');\n const schema = optionalString(manifest.$schema, `${manifestPath}.$schema`);\n const name = optionalString(manifest.name, `${manifestPath}.name`);\n const version = optionalString(manifest.version, `${manifestPath}.version`);\n const description = optionalString(manifest.description, `${manifestPath}.description`);\n return {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(schema?.startsWith(AGENT_PLUGIN_SCHEMA_PREFIX) ? { agentPluginSchema: schema } : {}),\n };\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n return { path: manifestPath };\n }\n}\n\nfunction discoverPluginRoot(\n pluginRoot: string,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): boolean {\n const diagnosticCount = diagnostics.length;\n const manifest = readPluginManifestMetadata(pluginRoot, diagnostics);\n if (!manifest || diagnostics.length !== diagnosticCount) return false;\n const name = manifest.name ?? path.basename(pluginRoot);\n try {\n validatePluginIdSegment(name, `Plugin name in ${manifest.path}`);\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n return false;\n }\n entries[name] = {\n source: { type: 'local', path: pluginRoot },\n ...(manifest.description ? { description: manifest.description } : {}),\n manifest,\n };\n return true;\n}\n\nfunction discoverPluginFolder(\n root: string,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): number {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) return 0;\n if (findPluginManifestPath(root)) return discoverPluginRoot(root, entries, diagnostics) ? 1 : 0;\n\n let discovered = 0;\n const children = fs\n .readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .sort((left, right) => left.name.localeCompare(right.name));\n for (const child of children) {\n if (discoverPluginRoot(path.join(root, child.name), entries, diagnostics)) discovered += 1;\n }\n return discovered;\n}\n\nfunction parseMarketplace(\n marketplace: MarketplaceLocation,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): void {\n const document = readJsonRecord(marketplace.manifestPath, 'Marketplace manifest');\n const marketplaceName = requireString(document.name, `${marketplace.manifestPath}.name`);\n validatePluginIdSegment(marketplaceName, `${marketplace.manifestPath}.name`);\n if (!Array.isArray(document.plugins)) throw new Error(`${marketplace.manifestPath}.plugins must be an array`);\n for (let index = 0; index < document.plugins.length; index += 1) {\n const label = `${marketplace.manifestPath}.plugins[${index}]`;\n try {\n const plugin = requireRecord(document.plugins[index], label);\n const pluginName = requireString(plugin.name, `${label}.name`);\n validatePluginIdSegment(pluginName, `${label}.name`);\n const id = `${pluginName}@${marketplaceName}`;\n if (Object.hasOwn(entries, id)) continue;\n const source = parsePluginSource(plugin.source, marketplace.root, `${label}.source`, marketplace);\n const description = optionalString(plugin.description, `${label}.description`);\n const manifest = source.type === 'local' ? readPluginManifestMetadata(source.path, diagnostics) : undefined;\n const resolvedDescription = description ?? manifest?.description;\n entries[id] = {\n source,\n marketplace: marketplaceName,\n ...(resolvedDescription ? { description: resolvedDescription } : {}),\n ...(manifest ? { manifest } : {}),\n };\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n }\n }\n}\n\nfunction parseConfiguredRoots(source: PluginCatalogConfigSource): string[] {\n if (source.value === undefined) return [];\n const document = requireRecord(source.value, `plugins in ${source.filePath}`);\n assertOnlyKeys(document, ['roots', 'entries'], `plugins in ${source.filePath}`);\n if (document.roots === undefined) return [];\n if (!Array.isArray(document.roots)) throw new Error(`plugins.roots in ${source.filePath} must be an array`);\n return document.roots.map((root, index) =>\n path.resolve(source.baseDirectory, requireString(root, `plugins.roots[${index}] in ${source.filePath}`)),\n );\n}\n\nfunction applyConfiguredEntries(\n source: PluginCatalogConfigSource,\n entries: Record<string, PluginCatalogEntry>,\n diagnostics: string[],\n): void {\n if (source.value === undefined) return;\n const document = requireRecord(source.value, `plugins in ${source.filePath}`);\n if (document.entries === undefined) return;\n const configuredEntries = requireRecord(document.entries, `plugins.entries in ${source.filePath}`);\n for (const [name, value] of Object.entries(configuredEntries)) {\n validatePluginId(name, `Plugin entry \"${name}\" in ${source.filePath}`);\n const parsed = parseConfiguredEntry(value, source.baseDirectory, `plugins.entries.${name} in ${source.filePath}`);\n const manifest =\n parsed.source.type === 'local' ? readPluginManifestMetadata(parsed.source.path, diagnostics) : undefined;\n const description = parsed.description ?? manifest?.description;\n entries[name] = {\n source: parsed.source,\n ...(description ? { description } : {}),\n ...(manifest ? { manifest } : {}),\n };\n }\n}\n\nexport function pluginDirectoryForSource(source: PluginSource, homeDoomDirectory: string): string {\n if (source.type === 'local') return source.path;\n const identity =\n source.type === 'git'\n ? ['git', source.url, source.path ?? '', source.ref ?? '', source.sha ?? '']\n : ['npm', source.package, source.version ?? '', source.registry ?? ''];\n const digest = crypto.createHash('sha256').update(JSON.stringify(identity)).digest('hex');\n return path.join(homeDoomDirectory, CACHE_DIRECTORY, digest);\n}\n\nexport function loadPluginCatalog(\n sources: readonly PluginCatalogConfigSource[],\n repoRoot: string,\n homeDirectory: string,\n): PluginCatalog {\n const diagnostics: string[] = [];\n const entries: Record<string, PluginCatalogEntry> = {};\n const roots = [...new Set(sources.flatMap(parseConfiguredRoots))];\n const candidates = [homeDirectory, repoRoot, ...roots];\n const marketplaces: string[] = [];\n const seenMarketplaces = new Set<string>();\n\n for (const candidate of candidates) {\n const marketplace = findMarketplace(candidate);\n if (!marketplace) continue;\n if (seenMarketplaces.has(marketplace.manifestPath)) continue;\n seenMarketplaces.add(marketplace.manifestPath);\n marketplaces.push(marketplace.manifestPath);\n try {\n parseMarketplace(marketplace, entries, diagnostics);\n } catch (error) {\n diagnostics.push(error instanceof Error ? error.message : String(error));\n }\n }\n\n for (const root of roots) {\n if (findMarketplace(root)) continue;\n if (discoverPluginFolder(root, entries, diagnostics) === 0) {\n diagnostics.push(`Plugin root contains neither a supported marketplace nor discoverable plugins: ${root}`);\n }\n }\n\n for (const source of sources) applyConfiguredEntries(source, entries, diagnostics);\n return { roots, marketplaces, entries, diagnostics };\n}\n\nexport function isRemotePluginSource(\n source: PluginSource,\n): source is GitPluginSource | Extract<PluginSource, { type: 'npm' }> {\n return source.type !== 'local';\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ 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:path");r=e.__toESM(r,1);let i=require("node:os");i=e.__toESM(i,1);const a=[`profile.md`,`SOUL.md`,`AGENTS.md`],o=new Set([`persona`,`env`]),s=new Set([`roots`,`entries`]),c=`profiles`;function l(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function u(e,t){let n=r.default.relative(e,t);return n===``||!r.default.isAbsolute(n)&&n!==`..`&&!n.startsWith(`..${r.default.sep}`)}function d(e,t){if(t===void 0)return{};if(!l(t))throw Error(`Profile "${e}" env must be a string mapping`);let n={};for(let[r,i]of Object.entries(t)){if(typeof i!=`string`)throw Error(`Profile "${e}" env.${r} must be a string`);n[r]=i}return n}function f(e,t,n){if(e===void 0)return[];if(!Array.isArray(e))throw Error(`profiles.roots in ${t} must be an array`);return e.map((e,i)=>{if(typeof e!=`string`||e.trim().length===0)throw Error(`profiles.roots[${i}] in ${t} must be a non-empty string`);return r.default.resolve(n,e.trim())})}function p(e){if(!l(e.document)||!l(e.document[c]))throw Error(`${e.filePath} must contain a profiles mapping`);let t=Object.keys(e.document).filter(e=>e!==c);if(t.length>0)throw Error(`${e.filePath} may only contain profiles; unsupported: ${t.join(`, `)}`);let n=e.document[c];if(!(Object.hasOwn(n,`roots`)||Object.hasOwn(n,`entries`)))return{filePath:e.filePath,baseDirectory:e.baseDirectory,roots:[],entries:n};let r=Object.keys(n).filter(e=>!s.has(e));if(r.length>0)throw Error(`profiles in ${e.filePath} may only contain roots and entries; unsupported: ${r.join(`, `)}`);if(n.entries!==void 0&&!l(n.entries))throw Error(`profiles.entries in ${e.filePath} must be a mapping`);return{filePath:e.filePath,baseDirectory:e.baseDirectory,roots:f(n.roots,e.filePath,e.baseDirectory),entries:n.entries??{}}}function m(e,t,r){let i=n.default.realpathSync(t);if(!r.some(e=>u(n.default.realpathSync(e),i)))throw Error(`Profile "${e}" persona must stay inside agents/ or a configured profile root`)}function h(e,t,i,a){if(!l(a))throw Error(`Profile "${i}" must be a mapping`);let s=Object.keys(a).filter(e=>!o.has(e));if(s.length>0)throw Error(`Profile "${i}" may only set persona and env; unsupported: ${s.join(`, `)}`);if(typeof a.persona!=`string`||a.persona.trim().length===0)throw Error(`Profile "${i}" must set a persona`);if(r.default.isAbsolute(a.persona))throw Error(`Profile "${i}" persona must be relative to the config that declares it`);let c=a.persona,f=r.default.resolve(e,c),p=[r.default.resolve(e,`agents`),...t].filter(e=>u(e,f));if(p.length===0)throw Error(`Profile "${i}" persona must stay inside agents/ or a configured profile root`);if(!n.default.existsSync(f)||!n.default.statSync(f).isDirectory())throw Error(`Profile "${i}" references a missing persona: ${c}`);if(m(i,f,p),!S(e,c))throw Error(`Profile "${i}" persona has no readable persona files: ${c}`);return{name:i,persona:c,personaRoot:e,env:d(i,a.env)}}function g(e){return a.some(t=>{try{return n.default.lstatSync(r.default.join(e,t)).isFile()}catch{return!1}})}function _(e,t,i){if(g(e))try{if(!u(n.default.realpathSync(t),n.default.realpathSync(e)))return;let a=r.default.relative(i,e)||`.`;return S(i,a)?{name:r.default.basename(e),persona:a,personaRoot:i,env:{}}:void 0}catch{return}}function v(e,t){if(!n.default.existsSync(e)||!n.default.statSync(e).isDirectory())throw Error(`Configured profile root is not a directory: ${e}`);let i=_(e,e,t);return i?[i]:n.default.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isDirectory()).sort((e,t)=>e.name.localeCompare(t.name)).flatMap(n=>{let i=_(r.default.join(e,n.name),e,t);return i?[i]:[]})}function y(e,n=i.default.homedir()){let r=t.readDoomConfigSources(`profiles.yaml`,e,n).map(p),a=new Map;for(let e of r)for(let t of e.roots)for(let n of v(t,e.baseDirectory))a.set(n.name,n);for(let e of r)for(let[t,n]of Object.entries(e.entries))a.set(t,h(e.baseDirectory,e.roots,t,n));return[...a.values()].sort((e,t)=>e.name.localeCompare(t.name))}function b(e,t,n){let r=y(e,n).find(e=>e.name===t);if(!r)throw Error(`Unknown profile: ${t}`);return r}function x(e,t){return y(e,t).map(e=>e.name)}function S(e,t){let i=[],o=n.default.realpathSync(r.default.join(e,t));for(let e of a){let a=r.default.join(o,e);if(!n.default.existsSync(a))continue;let s=n.default.realpathSync(a),c=r.default.relative(o,s);if(c===`..`||c.startsWith(`..${r.default.sep}`))throw Error(`Persona file must stay inside ${t}: ${e}`);let l=n.default.readFileSync(s,`utf8`).trim();l&&i.push(l)}if(i.length!==0)return[`[PERSONA] You are operating as the person described below (source: ${t}).`,...i].join(`
2
+
3
+ `)}function C(e,t){let n={};for(let[r,i]of Object.entries(t))e[r]===void 0&&(e[r]=i,n[r]=i);return n}function w(e,t,n){for(let[n,r]of Object.entries(t))e[n]===r&&delete e[n];return C(e,n)}exports.PERSONA_FILES=a,exports.applyProfileEnvironment=C,exports.buildPersonaPrompt=S,exports.listProfileNames=x,exports.loadProfiles=y,exports.replaceProfileEnvironment=w,exports.resolveProfile=b;
4
+ //# sourceMappingURL=profiles.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.cjs","names":["path","fs","os","readDoomConfigSources"],"sources":["../../src/adapters/profiles.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { readDoomConfigSources } from './layeredConfig.ts';\n\n/** Files that make up one repository persona, concatenated in this order. */\nexport const PERSONA_FILES = ['profile.md', 'SOUL.md', 'AGENTS.md'];\n\nexport interface AgentProfile {\n name: string;\n /** Directory relative to personaRoot, which remains the persona source. */\n persona: string;\n /**\n * Root the persona path resolves against: the repository root for a\n * repository profile, the global `.doom` directory for a global one.\n */\n personaRoot: string;\n /** Environment defaults. Values already exported by the caller win. */\n env: Record<string, string>;\n}\n\ninterface ProfileConfigLayer {\n filePath: string;\n baseDirectory: string;\n roots: string[];\n entries: Record<string, unknown>;\n}\n\nconst PROFILE_KEYS = new Set(['persona', 'env']);\nconst PROFILE_CATALOG_KEYS = new Set(['roots', 'entries']);\nconst PROFILES_FILE = 'profiles.yaml';\nconst PROFILES_ROOT_KEY = 'profiles';\nconst AGENTS_DIRECTORY = 'agents';\nconst PARENT_DIRECTORY = '..';\nconst TEXT_ENCODING = 'utf8';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isPathInside(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return (\n relative === '' ||\n (!path.isAbsolute(relative) &&\n relative !== PARENT_DIRECTORY &&\n !relative.startsWith(`${PARENT_DIRECTORY}${path.sep}`))\n );\n}\n\nfunction parseEnvironment(name: string, value: unknown): Record<string, string> {\n if (value === undefined) return {};\n if (!isRecord(value)) throw new Error(`Profile \"${name}\" env must be a string mapping`);\n\n const environment: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry !== 'string') throw new Error(`Profile \"${name}\" env.${key} must be a string`);\n environment[key] = entry;\n }\n return environment;\n}\n\nfunction parseProfileRoots(value: unknown, filePath: string, baseDirectory: string): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) throw new Error(`profiles.roots in ${filePath} must be an array`);\n return value.map((entry, index) => {\n if (typeof entry !== 'string' || entry.trim().length === 0) {\n throw new Error(`profiles.roots[${index}] in ${filePath} must be a non-empty string`);\n }\n return path.resolve(baseDirectory, entry.trim());\n });\n}\n\nfunction parseProfileLayer(source: { filePath: string; baseDirectory: string; document: unknown }): ProfileConfigLayer {\n if (!isRecord(source.document) || !isRecord(source.document[PROFILES_ROOT_KEY])) {\n throw new Error(`${source.filePath} must contain a profiles mapping`);\n }\n const unsupportedDocumentKeys = Object.keys(source.document).filter((key) => key !== PROFILES_ROOT_KEY);\n if (unsupportedDocumentKeys.length > 0) {\n throw new Error(`${source.filePath} may only contain profiles; unsupported: ${unsupportedDocumentKeys.join(', ')}`);\n }\n\n const profiles = source.document[PROFILES_ROOT_KEY];\n const usesCatalogShape = Object.hasOwn(profiles, 'roots') || Object.hasOwn(profiles, 'entries');\n if (!usesCatalogShape) {\n return { filePath: source.filePath, baseDirectory: source.baseDirectory, roots: [], entries: profiles };\n }\n\n const unsupportedCatalogKeys = Object.keys(profiles).filter((key) => !PROFILE_CATALOG_KEYS.has(key));\n if (unsupportedCatalogKeys.length > 0) {\n throw new Error(\n `profiles in ${source.filePath} may only contain roots and entries; unsupported: ${unsupportedCatalogKeys.join(', ')}`,\n );\n }\n if (profiles.entries !== undefined && !isRecord(profiles.entries)) {\n throw new Error(`profiles.entries in ${source.filePath} must be a mapping`);\n }\n return {\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n roots: parseProfileRoots(profiles.roots, source.filePath, source.baseDirectory),\n entries: profiles.entries ?? {},\n };\n}\n\nfunction assertProfileInsideAllowedRoot(name: string, personaPath: string, lexicalRoots: readonly string[]): void {\n const realPersonaPath = fs.realpathSync(personaPath);\n if (!lexicalRoots.some((root) => isPathInside(fs.realpathSync(root), realPersonaPath))) {\n throw new Error(`Profile \"${name}\" persona must stay inside agents/ or a configured profile root`);\n }\n}\n\nfunction parseProfile(\n personaRoot: string,\n configuredRoots: readonly string[],\n name: string,\n value: unknown,\n): AgentProfile {\n if (!isRecord(value)) throw new Error(`Profile \"${name}\" must be a mapping`);\n\n const unsupported = Object.keys(value).filter((key) => !PROFILE_KEYS.has(key));\n if (unsupported.length > 0) {\n throw new Error(`Profile \"${name}\" may only set persona and env; unsupported: ${unsupported.join(', ')}`);\n }\n if (typeof value.persona !== 'string' || value.persona.trim().length === 0) {\n throw new Error(`Profile \"${name}\" must set a persona`);\n }\n if (path.isAbsolute(value.persona)) {\n throw new Error(`Profile \"${name}\" persona must be relative to the config that declares it`);\n }\n\n const persona = value.persona;\n const personaPath = path.resolve(personaRoot, persona);\n const lexicalRoots = [path.resolve(personaRoot, AGENTS_DIRECTORY), ...configuredRoots].filter((root) =>\n isPathInside(root, personaPath),\n );\n if (lexicalRoots.length === 0) {\n throw new Error(`Profile \"${name}\" persona must stay inside agents/ or a configured profile root`);\n }\n if (!fs.existsSync(personaPath) || !fs.statSync(personaPath).isDirectory()) {\n throw new Error(`Profile \"${name}\" references a missing persona: ${persona}`);\n }\n assertProfileInsideAllowedRoot(name, personaPath, lexicalRoots);\n if (!buildPersonaPrompt(personaRoot, persona)) {\n throw new Error(`Profile \"${name}\" persona has no readable persona files: ${persona}`);\n }\n\n return { name, persona, personaRoot, env: parseEnvironment(name, value.env) };\n}\n\nfunction containsPersonaFile(directory: string): boolean {\n return PERSONA_FILES.some((file) => {\n try {\n return fs.lstatSync(path.join(directory, file)).isFile();\n } catch {\n return false;\n }\n });\n}\n\nfunction discoverProfile(directory: string, configuredRoot: string, personaRoot: string): AgentProfile | undefined {\n if (!containsPersonaFile(directory)) return undefined;\n try {\n const realConfiguredRoot = fs.realpathSync(configuredRoot);\n const realDirectory = fs.realpathSync(directory);\n if (!isPathInside(realConfiguredRoot, realDirectory)) return undefined;\n const persona = path.relative(personaRoot, directory) || '.';\n if (!buildPersonaPrompt(personaRoot, persona)) return undefined;\n return { name: path.basename(directory), persona, personaRoot, env: {} };\n } catch {\n // Automatic discovery ignores unreadable or unsafe candidates; explicit entries remain fatal.\n return undefined;\n }\n}\n\nfunction discoverProfileRoot(root: string, personaRoot: string): AgentProfile[] {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {\n throw new Error(`Configured profile root is not a directory: ${root}`);\n }\n\n const rootProfile = discoverProfile(root, root, personaRoot);\n if (rootProfile) return [rootProfile];\n\n return fs\n .readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .sort((left, right) => left.name.localeCompare(right.name))\n .flatMap((entry) => {\n const profile = discoverProfile(path.join(root, entry.name), root, personaRoot);\n return profile ? [profile] : [];\n });\n}\n\n/**\n * Loads profiles from the global and repository configs, repository last.\n *\n * Configured roots accumulate and inspect themselves or their direct-child\n * directories for persona files. Later discoveries replace earlier names, and\n * explicit entries replace discoveries. Legacy flat profile mappings remain\n * accepted as explicit entries.\n */\nexport function loadProfiles(repoRoot: string, homeDirectory: string = os.homedir()): AgentProfile[] {\n const layers = readDoomConfigSources<unknown>(PROFILES_FILE, repoRoot, homeDirectory).map(parseProfileLayer);\n const byName = new Map<string, AgentProfile>();\n\n for (const layer of layers) {\n for (const root of layer.roots) {\n for (const profile of discoverProfileRoot(root, layer.baseDirectory)) byName.set(profile.name, profile);\n }\n }\n\n for (const layer of layers) {\n for (const [name, value] of Object.entries(layer.entries)) {\n byName.set(name, parseProfile(layer.baseDirectory, layer.roots, name, value));\n }\n }\n\n return [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));\n}\n\n/** Resolves one selected profile and fails clearly when its name is unknown. */\nexport function resolveProfile(repoRoot: string, name: string, homeDirectory?: string): AgentProfile {\n const profile = loadProfiles(repoRoot, homeDirectory).find((candidate) => candidate.name === name);\n if (!profile) throw new Error(`Unknown profile: ${name}`);\n return profile;\n}\n\nexport function listProfileNames(repoRoot: string, homeDirectory?: string): string[] {\n return loadProfiles(repoRoot, homeDirectory).map((profile) => profile.name);\n}\n\n/** Builds the persona system-prompt block, or undefined when nothing is readable. */\nexport function buildPersonaPrompt(personaRoot: string, personaDirectory: string): string | undefined {\n const sections: string[] = [];\n const personaPath = fs.realpathSync(path.join(personaRoot, personaDirectory));\n for (const file of PERSONA_FILES) {\n const filePath = path.join(personaPath, file);\n if (!fs.existsSync(filePath)) continue;\n const realFilePath = fs.realpathSync(filePath);\n const relativeFilePath = path.relative(personaPath, realFilePath);\n if (relativeFilePath === PARENT_DIRECTORY || relativeFilePath.startsWith(`${PARENT_DIRECTORY}${path.sep}`)) {\n throw new Error(`Persona file must stay inside ${personaDirectory}: ${file}`);\n }\n const content = fs.readFileSync(realFilePath, TEXT_ENCODING).trim();\n if (content) sections.push(content);\n }\n if (sections.length === 0) return undefined;\n return [`[PERSONA] You are operating as the person described below (source: ${personaDirectory}).`, ...sections].join(\n '\\n\\n',\n );\n}\n\n/** Applies profile environment defaults and returns only the values it contributed. */\nexport function applyProfileEnvironment(\n environment: NodeJS.ProcessEnv,\n defaults: Record<string, string>,\n): Record<string, string> {\n const applied: Record<string, string> = {};\n for (const [key, value] of Object.entries(defaults)) {\n if (environment[key] !== undefined) continue;\n environment[key] = value;\n applied[key] = value;\n }\n return applied;\n}\n\n/** Replaces environment defaults previously contributed by another profile. */\nexport function replaceProfileEnvironment(\n environment: NodeJS.ProcessEnv,\n previous: Record<string, string>,\n next: Record<string, string>,\n): Record<string, string> {\n for (const [key, value] of Object.entries(previous)) {\n if (environment[key] === value) delete environment[key];\n }\n return applyProfileEnvironment(environment, next);\n}\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ //#region src/adapters/profiles.d.ts
2
+ /** Files that make up one repository persona, concatenated in this order. */
3
+ declare const PERSONA_FILES: string[];
4
+ interface AgentProfile {
5
+ name: string;
6
+ /** Directory relative to personaRoot, which remains the persona source. */
7
+ persona: string;
8
+ /**
9
+ * Root the persona path resolves against: the repository root for a
10
+ * repository profile, the global `.doom` directory for a global one.
11
+ */
12
+ personaRoot: string;
13
+ /** Environment defaults. Values already exported by the caller win. */
14
+ env: Record<string, string>;
15
+ }
16
+ /**
17
+ * Loads profiles from the global and repository configs, repository last.
18
+ *
19
+ * Configured roots accumulate and inspect themselves or their direct-child
20
+ * directories for persona files. Later discoveries replace earlier names, and
21
+ * explicit entries replace discoveries. Legacy flat profile mappings remain
22
+ * accepted as explicit entries.
23
+ */
24
+ declare function loadProfiles(repoRoot: string, homeDirectory?: string): AgentProfile[];
25
+ /** Resolves one selected profile and fails clearly when its name is unknown. */
26
+ declare function resolveProfile(repoRoot: string, name: string, homeDirectory?: string): AgentProfile;
27
+ declare function listProfileNames(repoRoot: string, homeDirectory?: string): string[];
28
+ /** Builds the persona system-prompt block, or undefined when nothing is readable. */
29
+ declare function buildPersonaPrompt(personaRoot: string, personaDirectory: string): string | undefined;
30
+ /** Applies profile environment defaults and returns only the values it contributed. */
31
+ declare function applyProfileEnvironment(environment: NodeJS.ProcessEnv, defaults: Record<string, string>): Record<string, string>;
32
+ /** Replaces environment defaults previously contributed by another profile. */
33
+ declare function replaceProfileEnvironment(environment: NodeJS.ProcessEnv, previous: Record<string, string>, next: Record<string, string>): Record<string, string>;
34
+ //#endregion
35
+ export { AgentProfile, PERSONA_FILES, applyProfileEnvironment, buildPersonaPrompt, listProfileNames, loadProfiles, replaceProfileEnvironment, resolveProfile };
36
+ //# sourceMappingURL=profiles.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.cts","names":[],"sources":["../../src/adapters/profiles.ts"],"mappings":";;cAMa;UAEI;EACf;;EAEA;;;;;EAKA;;EAEA,KAAK;;;;;;;;;;iBAuLS,aAAa,kBAAkB,yBAAuC;;iBAoBtE,eAAe,kBAAkB,cAAc,yBAAyB;iBAMxE,iBAAiB,kBAAkB;;iBAKnC,mBAAmB,qBAAqB;;iBAqBxC,wBACd,aAAa,OAAO,YACpB,UAAU,yBACT;;iBAWa,0BACd,aAAa,OAAO,YACpB,UAAU,wBACV,MAAM,yBACL"}
@@ -0,0 +1,36 @@
1
+ //#region src/adapters/profiles.d.ts
2
+ /** Files that make up one repository persona, concatenated in this order. */
3
+ declare const PERSONA_FILES: string[];
4
+ interface AgentProfile {
5
+ name: string;
6
+ /** Directory relative to personaRoot, which remains the persona source. */
7
+ persona: string;
8
+ /**
9
+ * Root the persona path resolves against: the repository root for a
10
+ * repository profile, the global `.doom` directory for a global one.
11
+ */
12
+ personaRoot: string;
13
+ /** Environment defaults. Values already exported by the caller win. */
14
+ env: Record<string, string>;
15
+ }
16
+ /**
17
+ * Loads profiles from the global and repository configs, repository last.
18
+ *
19
+ * Configured roots accumulate and inspect themselves or their direct-child
20
+ * directories for persona files. Later discoveries replace earlier names, and
21
+ * explicit entries replace discoveries. Legacy flat profile mappings remain
22
+ * accepted as explicit entries.
23
+ */
24
+ declare function loadProfiles(repoRoot: string, homeDirectory?: string): AgentProfile[];
25
+ /** Resolves one selected profile and fails clearly when its name is unknown. */
26
+ declare function resolveProfile(repoRoot: string, name: string, homeDirectory?: string): AgentProfile;
27
+ declare function listProfileNames(repoRoot: string, homeDirectory?: string): string[];
28
+ /** Builds the persona system-prompt block, or undefined when nothing is readable. */
29
+ declare function buildPersonaPrompt(personaRoot: string, personaDirectory: string): string | undefined;
30
+ /** Applies profile environment defaults and returns only the values it contributed. */
31
+ declare function applyProfileEnvironment(environment: NodeJS.ProcessEnv, defaults: Record<string, string>): Record<string, string>;
32
+ /** Replaces environment defaults previously contributed by another profile. */
33
+ declare function replaceProfileEnvironment(environment: NodeJS.ProcessEnv, previous: Record<string, string>, next: Record<string, string>): Record<string, string>;
34
+ //#endregion
35
+ export { AgentProfile, PERSONA_FILES, applyProfileEnvironment, buildPersonaPrompt, listProfileNames, loadProfiles, replaceProfileEnvironment, resolveProfile };
36
+ //# sourceMappingURL=profiles.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.mts","names":[],"sources":["../../src/adapters/profiles.ts"],"mappings":";;cAMa;UAEI;EACf;;EAEA;;;;;EAKA;;EAEA,KAAK;;;;;;;;;;iBAuLS,aAAa,kBAAkB,yBAAuC;;iBAoBtE,eAAe,kBAAkB,cAAc,yBAAyB;iBAMxE,iBAAiB,kBAAkB;;iBAKnC,mBAAmB,qBAAqB;;iBAqBxC,wBACd,aAAa,OAAO,YACpB,UAAU,yBACT;;iBAWa,0BACd,aAAa,OAAO,YACpB,UAAU,wBACV,MAAM,yBACL"}
@@ -0,0 +1,4 @@
1
+ import{readDoomConfigSources as e}from"./layeredConfig.mjs";import t from"node:fs";import n from"node:path";import r from"node:os";const i=[`profile.md`,`SOUL.md`,`AGENTS.md`],a=new Set([`persona`,`env`]),o=new Set([`roots`,`entries`]),s=`profiles`;function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e,t){let r=n.relative(e,t);return r===``||!n.isAbsolute(r)&&r!==`..`&&!r.startsWith(`..${n.sep}`)}function u(e,t){if(t===void 0)return{};if(!c(t))throw Error(`Profile "${e}" env must be a string mapping`);let n={};for(let[r,i]of Object.entries(t)){if(typeof i!=`string`)throw Error(`Profile "${e}" env.${r} must be a string`);n[r]=i}return n}function d(e,t,r){if(e===void 0)return[];if(!Array.isArray(e))throw Error(`profiles.roots in ${t} must be an array`);return e.map((e,i)=>{if(typeof e!=`string`||e.trim().length===0)throw Error(`profiles.roots[${i}] in ${t} must be a non-empty string`);return n.resolve(r,e.trim())})}function f(e){if(!c(e.document)||!c(e.document[s]))throw Error(`${e.filePath} must contain a profiles mapping`);let t=Object.keys(e.document).filter(e=>e!==s);if(t.length>0)throw Error(`${e.filePath} may only contain profiles; unsupported: ${t.join(`, `)}`);let n=e.document[s];if(!(Object.hasOwn(n,`roots`)||Object.hasOwn(n,`entries`)))return{filePath:e.filePath,baseDirectory:e.baseDirectory,roots:[],entries:n};let r=Object.keys(n).filter(e=>!o.has(e));if(r.length>0)throw Error(`profiles in ${e.filePath} may only contain roots and entries; unsupported: ${r.join(`, `)}`);if(n.entries!==void 0&&!c(n.entries))throw Error(`profiles.entries in ${e.filePath} must be a mapping`);return{filePath:e.filePath,baseDirectory:e.baseDirectory,roots:d(n.roots,e.filePath,e.baseDirectory),entries:n.entries??{}}}function p(e,n,r){let i=t.realpathSync(n);if(!r.some(e=>l(t.realpathSync(e),i)))throw Error(`Profile "${e}" persona must stay inside agents/ or a configured profile root`)}function m(e,r,i,o){if(!c(o))throw Error(`Profile "${i}" must be a mapping`);let s=Object.keys(o).filter(e=>!a.has(e));if(s.length>0)throw Error(`Profile "${i}" may only set persona and env; unsupported: ${s.join(`, `)}`);if(typeof o.persona!=`string`||o.persona.trim().length===0)throw Error(`Profile "${i}" must set a persona`);if(n.isAbsolute(o.persona))throw Error(`Profile "${i}" persona must be relative to the config that declares it`);let d=o.persona,f=n.resolve(e,d),m=[n.resolve(e,`agents`),...r].filter(e=>l(e,f));if(m.length===0)throw Error(`Profile "${i}" persona must stay inside agents/ or a configured profile root`);if(!t.existsSync(f)||!t.statSync(f).isDirectory())throw Error(`Profile "${i}" references a missing persona: ${d}`);if(p(i,f,m),!x(e,d))throw Error(`Profile "${i}" persona has no readable persona files: ${d}`);return{name:i,persona:d,personaRoot:e,env:u(i,o.env)}}function h(e){return i.some(r=>{try{return t.lstatSync(n.join(e,r)).isFile()}catch{return!1}})}function g(e,r,i){if(h(e))try{if(!l(t.realpathSync(r),t.realpathSync(e)))return;let a=n.relative(i,e)||`.`;return x(i,a)?{name:n.basename(e),persona:a,personaRoot:i,env:{}}:void 0}catch{return}}function _(e,r){if(!t.existsSync(e)||!t.statSync(e).isDirectory())throw Error(`Configured profile root is not a directory: ${e}`);let i=g(e,e,r);return i?[i]:t.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isDirectory()).sort((e,t)=>e.name.localeCompare(t.name)).flatMap(t=>{let i=g(n.join(e,t.name),e,r);return i?[i]:[]})}function v(t,n=r.homedir()){let i=e(`profiles.yaml`,t,n).map(f),a=new Map;for(let e of i)for(let t of e.roots)for(let n of _(t,e.baseDirectory))a.set(n.name,n);for(let e of i)for(let[t,n]of Object.entries(e.entries))a.set(t,m(e.baseDirectory,e.roots,t,n));return[...a.values()].sort((e,t)=>e.name.localeCompare(t.name))}function y(e,t,n){let r=v(e,n).find(e=>e.name===t);if(!r)throw Error(`Unknown profile: ${t}`);return r}function b(e,t){return v(e,t).map(e=>e.name)}function x(e,r){let a=[],o=t.realpathSync(n.join(e,r));for(let e of i){let i=n.join(o,e);if(!t.existsSync(i))continue;let s=t.realpathSync(i),c=n.relative(o,s);if(c===`..`||c.startsWith(`..${n.sep}`))throw Error(`Persona file must stay inside ${r}: ${e}`);let l=t.readFileSync(s,`utf8`).trim();l&&a.push(l)}if(a.length!==0)return[`[PERSONA] You are operating as the person described below (source: ${r}).`,...a].join(`
2
+
3
+ `)}function S(e,t){let n={};for(let[r,i]of Object.entries(t))e[r]===void 0&&(e[r]=i,n[r]=i);return n}function C(e,t,n){for(let[n,r]of Object.entries(t))e[n]===r&&delete e[n];return S(e,n)}export{i as PERSONA_FILES,S as applyProfileEnvironment,x as buildPersonaPrompt,b as listProfileNames,v as loadProfiles,C as replaceProfileEnvironment,y as resolveProfile};
4
+ //# sourceMappingURL=profiles.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.mjs","names":[],"sources":["../../src/adapters/profiles.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { readDoomConfigSources } from './layeredConfig.ts';\n\n/** Files that make up one repository persona, concatenated in this order. */\nexport const PERSONA_FILES = ['profile.md', 'SOUL.md', 'AGENTS.md'];\n\nexport interface AgentProfile {\n name: string;\n /** Directory relative to personaRoot, which remains the persona source. */\n persona: string;\n /**\n * Root the persona path resolves against: the repository root for a\n * repository profile, the global `.doom` directory for a global one.\n */\n personaRoot: string;\n /** Environment defaults. Values already exported by the caller win. */\n env: Record<string, string>;\n}\n\ninterface ProfileConfigLayer {\n filePath: string;\n baseDirectory: string;\n roots: string[];\n entries: Record<string, unknown>;\n}\n\nconst PROFILE_KEYS = new Set(['persona', 'env']);\nconst PROFILE_CATALOG_KEYS = new Set(['roots', 'entries']);\nconst PROFILES_FILE = 'profiles.yaml';\nconst PROFILES_ROOT_KEY = 'profiles';\nconst AGENTS_DIRECTORY = 'agents';\nconst PARENT_DIRECTORY = '..';\nconst TEXT_ENCODING = 'utf8';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isPathInside(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return (\n relative === '' ||\n (!path.isAbsolute(relative) &&\n relative !== PARENT_DIRECTORY &&\n !relative.startsWith(`${PARENT_DIRECTORY}${path.sep}`))\n );\n}\n\nfunction parseEnvironment(name: string, value: unknown): Record<string, string> {\n if (value === undefined) return {};\n if (!isRecord(value)) throw new Error(`Profile \"${name}\" env must be a string mapping`);\n\n const environment: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry !== 'string') throw new Error(`Profile \"${name}\" env.${key} must be a string`);\n environment[key] = entry;\n }\n return environment;\n}\n\nfunction parseProfileRoots(value: unknown, filePath: string, baseDirectory: string): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) throw new Error(`profiles.roots in ${filePath} must be an array`);\n return value.map((entry, index) => {\n if (typeof entry !== 'string' || entry.trim().length === 0) {\n throw new Error(`profiles.roots[${index}] in ${filePath} must be a non-empty string`);\n }\n return path.resolve(baseDirectory, entry.trim());\n });\n}\n\nfunction parseProfileLayer(source: { filePath: string; baseDirectory: string; document: unknown }): ProfileConfigLayer {\n if (!isRecord(source.document) || !isRecord(source.document[PROFILES_ROOT_KEY])) {\n throw new Error(`${source.filePath} must contain a profiles mapping`);\n }\n const unsupportedDocumentKeys = Object.keys(source.document).filter((key) => key !== PROFILES_ROOT_KEY);\n if (unsupportedDocumentKeys.length > 0) {\n throw new Error(`${source.filePath} may only contain profiles; unsupported: ${unsupportedDocumentKeys.join(', ')}`);\n }\n\n const profiles = source.document[PROFILES_ROOT_KEY];\n const usesCatalogShape = Object.hasOwn(profiles, 'roots') || Object.hasOwn(profiles, 'entries');\n if (!usesCatalogShape) {\n return { filePath: source.filePath, baseDirectory: source.baseDirectory, roots: [], entries: profiles };\n }\n\n const unsupportedCatalogKeys = Object.keys(profiles).filter((key) => !PROFILE_CATALOG_KEYS.has(key));\n if (unsupportedCatalogKeys.length > 0) {\n throw new Error(\n `profiles in ${source.filePath} may only contain roots and entries; unsupported: ${unsupportedCatalogKeys.join(', ')}`,\n );\n }\n if (profiles.entries !== undefined && !isRecord(profiles.entries)) {\n throw new Error(`profiles.entries in ${source.filePath} must be a mapping`);\n }\n return {\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n roots: parseProfileRoots(profiles.roots, source.filePath, source.baseDirectory),\n entries: profiles.entries ?? {},\n };\n}\n\nfunction assertProfileInsideAllowedRoot(name: string, personaPath: string, lexicalRoots: readonly string[]): void {\n const realPersonaPath = fs.realpathSync(personaPath);\n if (!lexicalRoots.some((root) => isPathInside(fs.realpathSync(root), realPersonaPath))) {\n throw new Error(`Profile \"${name}\" persona must stay inside agents/ or a configured profile root`);\n }\n}\n\nfunction parseProfile(\n personaRoot: string,\n configuredRoots: readonly string[],\n name: string,\n value: unknown,\n): AgentProfile {\n if (!isRecord(value)) throw new Error(`Profile \"${name}\" must be a mapping`);\n\n const unsupported = Object.keys(value).filter((key) => !PROFILE_KEYS.has(key));\n if (unsupported.length > 0) {\n throw new Error(`Profile \"${name}\" may only set persona and env; unsupported: ${unsupported.join(', ')}`);\n }\n if (typeof value.persona !== 'string' || value.persona.trim().length === 0) {\n throw new Error(`Profile \"${name}\" must set a persona`);\n }\n if (path.isAbsolute(value.persona)) {\n throw new Error(`Profile \"${name}\" persona must be relative to the config that declares it`);\n }\n\n const persona = value.persona;\n const personaPath = path.resolve(personaRoot, persona);\n const lexicalRoots = [path.resolve(personaRoot, AGENTS_DIRECTORY), ...configuredRoots].filter((root) =>\n isPathInside(root, personaPath),\n );\n if (lexicalRoots.length === 0) {\n throw new Error(`Profile \"${name}\" persona must stay inside agents/ or a configured profile root`);\n }\n if (!fs.existsSync(personaPath) || !fs.statSync(personaPath).isDirectory()) {\n throw new Error(`Profile \"${name}\" references a missing persona: ${persona}`);\n }\n assertProfileInsideAllowedRoot(name, personaPath, lexicalRoots);\n if (!buildPersonaPrompt(personaRoot, persona)) {\n throw new Error(`Profile \"${name}\" persona has no readable persona files: ${persona}`);\n }\n\n return { name, persona, personaRoot, env: parseEnvironment(name, value.env) };\n}\n\nfunction containsPersonaFile(directory: string): boolean {\n return PERSONA_FILES.some((file) => {\n try {\n return fs.lstatSync(path.join(directory, file)).isFile();\n } catch {\n return false;\n }\n });\n}\n\nfunction discoverProfile(directory: string, configuredRoot: string, personaRoot: string): AgentProfile | undefined {\n if (!containsPersonaFile(directory)) return undefined;\n try {\n const realConfiguredRoot = fs.realpathSync(configuredRoot);\n const realDirectory = fs.realpathSync(directory);\n if (!isPathInside(realConfiguredRoot, realDirectory)) return undefined;\n const persona = path.relative(personaRoot, directory) || '.';\n if (!buildPersonaPrompt(personaRoot, persona)) return undefined;\n return { name: path.basename(directory), persona, personaRoot, env: {} };\n } catch {\n // Automatic discovery ignores unreadable or unsafe candidates; explicit entries remain fatal.\n return undefined;\n }\n}\n\nfunction discoverProfileRoot(root: string, personaRoot: string): AgentProfile[] {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {\n throw new Error(`Configured profile root is not a directory: ${root}`);\n }\n\n const rootProfile = discoverProfile(root, root, personaRoot);\n if (rootProfile) return [rootProfile];\n\n return fs\n .readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .sort((left, right) => left.name.localeCompare(right.name))\n .flatMap((entry) => {\n const profile = discoverProfile(path.join(root, entry.name), root, personaRoot);\n return profile ? [profile] : [];\n });\n}\n\n/**\n * Loads profiles from the global and repository configs, repository last.\n *\n * Configured roots accumulate and inspect themselves or their direct-child\n * directories for persona files. Later discoveries replace earlier names, and\n * explicit entries replace discoveries. Legacy flat profile mappings remain\n * accepted as explicit entries.\n */\nexport function loadProfiles(repoRoot: string, homeDirectory: string = os.homedir()): AgentProfile[] {\n const layers = readDoomConfigSources<unknown>(PROFILES_FILE, repoRoot, homeDirectory).map(parseProfileLayer);\n const byName = new Map<string, AgentProfile>();\n\n for (const layer of layers) {\n for (const root of layer.roots) {\n for (const profile of discoverProfileRoot(root, layer.baseDirectory)) byName.set(profile.name, profile);\n }\n }\n\n for (const layer of layers) {\n for (const [name, value] of Object.entries(layer.entries)) {\n byName.set(name, parseProfile(layer.baseDirectory, layer.roots, name, value));\n }\n }\n\n return [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));\n}\n\n/** Resolves one selected profile and fails clearly when its name is unknown. */\nexport function resolveProfile(repoRoot: string, name: string, homeDirectory?: string): AgentProfile {\n const profile = loadProfiles(repoRoot, homeDirectory).find((candidate) => candidate.name === name);\n if (!profile) throw new Error(`Unknown profile: ${name}`);\n return profile;\n}\n\nexport function listProfileNames(repoRoot: string, homeDirectory?: string): string[] {\n return loadProfiles(repoRoot, homeDirectory).map((profile) => profile.name);\n}\n\n/** Builds the persona system-prompt block, or undefined when nothing is readable. */\nexport function buildPersonaPrompt(personaRoot: string, personaDirectory: string): string | undefined {\n const sections: string[] = [];\n const personaPath = fs.realpathSync(path.join(personaRoot, personaDirectory));\n for (const file of PERSONA_FILES) {\n const filePath = path.join(personaPath, file);\n if (!fs.existsSync(filePath)) continue;\n const realFilePath = fs.realpathSync(filePath);\n const relativeFilePath = path.relative(personaPath, realFilePath);\n if (relativeFilePath === PARENT_DIRECTORY || relativeFilePath.startsWith(`${PARENT_DIRECTORY}${path.sep}`)) {\n throw new Error(`Persona file must stay inside ${personaDirectory}: ${file}`);\n }\n const content = fs.readFileSync(realFilePath, TEXT_ENCODING).trim();\n if (content) sections.push(content);\n }\n if (sections.length === 0) return undefined;\n return [`[PERSONA] You are operating as the person described below (source: ${personaDirectory}).`, ...sections].join(\n '\\n\\n',\n );\n}\n\n/** Applies profile environment defaults and returns only the values it contributed. */\nexport function applyProfileEnvironment(\n environment: NodeJS.ProcessEnv,\n defaults: Record<string, string>,\n): Record<string, string> {\n const applied: Record<string, string> = {};\n for (const [key, value] of Object.entries(defaults)) {\n if (environment[key] !== undefined) continue;\n environment[key] = value;\n applied[key] = value;\n }\n return applied;\n}\n\n/** Replaces environment defaults previously contributed by another profile. */\nexport function replaceProfileEnvironment(\n environment: NodeJS.ProcessEnv,\n previous: Record<string, string>,\n next: Record<string, string>,\n): Record<string, string> {\n for (const [key, value] of Object.entries(previous)) {\n if (environment[key] === value) delete environment[key];\n }\n return applyProfileEnvironment(environment, next);\n}\n"],"mappings":"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"}
@@ -1,2 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("node:crypto");function i(e,i){t.default.mkdirSync(n.default.dirname(e),{mode:448,recursive:!0});let a=`${e}.${process.pid}.${(0,r.randomUUID)()}.tmp`;try{t.default.writeFileSync(a,`${JSON.stringify(i,null,2)}\n`,{mode:384}),t.default.renameSync(a,e)}catch(e){throw t.default.rmSync(a,{force:!0}),e}}exports.writePrivateAtomicJson=i;
2
- //# sourceMappingURL=atomicJson.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/atomicJson.cjs");exports.writePrivateAtomicJson=e.writePrivateAtomicJson;