@agimon-ai/doompi-config 0.0.1-alpha.24 → 0.0.1-alpha.26

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 (67) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/domains.cjs +1 -1
  3. package/dist/adapters/domains.cjs.map +1 -1
  4. package/dist/adapters/domains.d.cts.map +1 -1
  5. package/dist/adapters/domains.d.mts.map +1 -1
  6. package/dist/adapters/domains.mjs +1 -1
  7. package/dist/adapters/domains.mjs.map +1 -1
  8. package/dist/adapters/harnessState.cjs +1 -1
  9. package/dist/adapters/harnessState.cjs.map +1 -1
  10. package/dist/adapters/harnessState.d.cts +4 -4
  11. package/dist/adapters/harnessState.d.cts.map +1 -1
  12. package/dist/adapters/harnessState.d.mts +4 -4
  13. package/dist/adapters/harnessState.d.mts.map +1 -1
  14. package/dist/adapters/harnessState.mjs +1 -1
  15. package/dist/adapters/harnessState.mjs.map +1 -1
  16. package/dist/adapters/pi/configExtension.cjs +1 -1
  17. package/dist/adapters/pi/configExtension.cjs.map +1 -1
  18. package/dist/adapters/pi/configExtension.d.cts.map +1 -1
  19. package/dist/adapters/pi/configExtension.d.mts.map +1 -1
  20. package/dist/adapters/pi/configExtension.mjs +1 -1
  21. package/dist/adapters/pi/configExtension.mjs.map +1 -1
  22. package/dist/adapters/pi/helpContribution.cjs +1 -1
  23. package/dist/adapters/pi/helpContribution.cjs.map +1 -1
  24. package/dist/adapters/pi/helpContribution.mjs +1 -1
  25. package/dist/adapters/pi/helpContribution.mjs.map +1 -1
  26. package/dist/adapters/pi/piContext.cjs +1 -1
  27. package/dist/adapters/pi/piContext.cjs.map +1 -1
  28. package/dist/adapters/pi/piContext.d.cts +6 -5
  29. package/dist/adapters/pi/piContext.d.cts.map +1 -1
  30. package/dist/adapters/pi/piContext.d.mts +6 -5
  31. package/dist/adapters/pi/piContext.d.mts.map +1 -1
  32. package/dist/adapters/pi/piContext.mjs +1 -1
  33. package/dist/adapters/pi/piContext.mjs.map +1 -1
  34. package/dist/adapters/piConfig.cjs +1 -1
  35. package/dist/adapters/piConfig.cjs.map +1 -1
  36. package/dist/adapters/piConfig.d.cts.map +1 -1
  37. package/dist/adapters/piConfig.d.mts.map +1 -1
  38. package/dist/adapters/piConfig.mjs +1 -1
  39. package/dist/adapters/piConfig.mjs.map +1 -1
  40. package/dist/index.cjs +1 -1
  41. package/dist/index.d.cts +2 -3
  42. package/dist/index.d.mts +2 -3
  43. package/dist/index.mjs +1 -1
  44. package/dist/providers/doomConfigService.cjs +1 -1
  45. package/dist/providers/doomConfigService.cjs.map +1 -1
  46. package/dist/providers/doomConfigService.mjs +1 -1
  47. package/dist/providers/doomConfigService.mjs.map +1 -1
  48. package/dist/types/config.cjs +1 -2
  49. package/dist/types/config.d.cts +14 -6
  50. package/dist/types/config.d.cts.map +1 -1
  51. package/dist/types/config.d.mts +14 -6
  52. package/dist/types/config.d.mts.map +1 -1
  53. package/dist/types/config.mjs +1 -2
  54. package/dist/types/domains.d.cts +2 -0
  55. package/dist/types/domains.d.cts.map +1 -1
  56. package/dist/types/domains.d.mts +2 -0
  57. package/dist/types/domains.d.mts.map +1 -1
  58. package/dist/types.cjs +1 -1
  59. package/dist/types.d.cts +2 -2
  60. package/dist/types.d.mts +2 -2
  61. package/package.json +3 -3
  62. package/dist/providers/doomConfigService.d.cts +0 -19
  63. package/dist/providers/doomConfigService.d.cts.map +0 -1
  64. package/dist/providers/doomConfigService.d.mts +0 -19
  65. package/dist/providers/doomConfigService.d.mts.map +0 -1
  66. package/dist/types/config.cjs.map +0 -1
  67. package/dist/types/config.mjs.map +0 -1
package/README.md CHANGED
@@ -72,7 +72,7 @@ A repository `modes.yaml` may set an inherited named `layers.<name>` or `majorMo
72
72
 
73
73
  ## Pi extension
74
74
 
75
- The package manifest and `@agimon-ai/doompi-config/extensions/pi` expose the same sole standard Pi factory. It owns a fresh package-local Cordis root and provides the typed configuration context used by both DoomPi and vanilla Pi sessions.
75
+ The package manifest and `@agimon-ai/doompi-config/extensions/pi` expose the same sole standard Pi factory. It joins the runner-scoped Cordis host, mounts one package plugin fiber, and provides the typed `doom/config` service used by both DoomPi and vanilla Pi sessions. An individually installed package uses the host bridge's shared standalone fallback rather than constructing a package-local root.
76
76
 
77
77
  ## Public API
78
78
 
@@ -1,2 +1,2 @@
1
- const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./config.cjs"),n=require("../services/domains.cjs"),r=require("./layeredConfig.cjs"),i=require("./pluginCatalog.cjs");let a=require("node:fs");a=e.__toESM(a,1);let o=require("node:path");o=e.__toESM(o,1);let s=require("node:os");s=e.__toESM(s,1);const c=`Plugin directory does not exist`,l=`.doom/domains.yaml`;function u(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function d(e,t){if(!u(e))throw Error(`${t} must be an object`);return e}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(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}function m(e,t){if(e!==void 0)return p(e,t)}function h(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array of non-empty strings`);return[...new Set(e.map((e,n)=>p(e,`${t}[${n}]`)))]}function g(e,t){if(e!==void 0){if(typeof e!=`boolean`)throw Error(`${t} must be a boolean`);return e}}function _(e){return h(e,`defaultDomains in ${l}`)}function v(e,t){if(typeof e==`string`)return p(e,t);let n=d(e,t);f(n,[`name`,`skills`,`agents`,`hooks`,`mcp`],t);let r=n.skills===void 0?void 0:h(n.skills,`${t}.skills`),i=n.agents===void 0?void 0:h(n.agents,`${t}.agents`),a=g(n.hooks,`${t}.hooks`),o=g(n.mcp,`${t}.mcp`);return{name:p(n.name,`${t}.name`),...r?{skills:r}:{},...i?{agents:i}:{},...a===void 0?{}:{hooks:a},...o===void 0?{}:{mcp:o}}}function y(e,t){let n=d(e,t);return f(n,[`servers`,`proxy`],t),{...n.servers===void 0?{}:{servers:h(n.servers,`${t}.servers`)},...n.proxy===void 0?{}:{proxy:h(n.proxy,`${t}.proxy`)}}}function b(e,t){let n=d(e,t);f(n,[`description`,`plugins`,`mcp`,`sharedSkills`],t);let r=m(n.description,`${t}.description`);if(n.plugins!==void 0&&!Array.isArray(n.plugins))throw Error(`${t}.plugins must be an array`);let i=g(n.sharedSkills,`${t}.sharedSkills`);return{...r?{description:r}:{},...Array.isArray(n.plugins)?{plugins:n.plugins.map((e,n)=>v(e,`${t}.plugins[${n}]`))}:{},...n.mcp===void 0?{}:{mcp:y(n.mcp,`${t}.mcp`)},...i===void 0?{}:{sharedSkills:i}}}function x(e,t){if(e===void 0)return{};let n=d(e,t);return Object.fromEntries(Object.entries(n).map(([e,n])=>[e,h(n,`${t}.${e}`)]))}function S(e,t=s.default.homedir()){let a=r.readDoomConfigSources(`domains.yaml`,e,t),o={},c={},u;for(let e of a){let t=d(e.document,e.filePath);if(f(t,[`plugins`,`domains`,`aliases`,`defaultDomains`],e.filePath),Object.assign(o,x(t.aliases,`aliases in ${e.filePath}`)),t.domains!==void 0){let n=d(t.domains,`domains in ${e.filePath}`);for(let[t,r]of Object.entries(n))c[t]={...b(r,`domains.${t} in ${e.filePath}`),baseDirectory:e.baseDirectory}}Object.hasOwn(t,`defaultDomains`)&&(u=_(t.defaultDomains))}let p=i.loadPluginCatalog(a.map(e=>({filePath:e.filePath,baseDirectory:e.baseDirectory,value:d(e.document,e.filePath).plugins})),e,t);if(u){for(let e of n.expandDomainNames({plugins:p,domains:c,aliases:o},u))if(!Object.hasOwn(c,e))throw Error(`Unknown default domain "${e}" in ${l}`)}return{plugins:p,domains:c,aliases:o,...u?{defaultDomains:u}:{}}}function C(e,t){let n=S(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function w(e,t,r){let i=S(e,r),a=n.expandDomainNames(i,t);return a.length===0||a.some(e=>i.domains[e]?.sharedSkills!==!1)}function T(e,r,l,u=s.default.homedir()){let d=S(e,u),f=[],p=new Set,m=t.globalDoomConfigDirectory(u);for(let e of n.expandDomainNames(d,r)){let t=d.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let n of t.plugins??[]){let t=typeof n!=`string`,r=t?n.name:n,o=d.plugins.entries[r];if(!o)throw Error(`Unknown plugin "${r}" referenced by domain "${e}"`);let s=i.pluginDirectoryForSource(o.source,m);if(o.source.type===`local`&&(!a.default.existsSync(s)||!a.default.statSync(s).isDirectory()))throw Error(`${c}: ${s}`);p.has(s)||(p.add(s),f.push({name:r,directory:s,source:o.source,...o.manifest?.agentPluginSchema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?{skillDiscovery:`direct-children`}:{},...t&&n.skills?{skills:n.skills}:{},...t&&n.agents?{agents:n.agents}:{},...t&&n.hooks!==void 0?{hooks:n.hooks}:{},...t&&n.mcp!==void 0?{mcp:n.mcp}:{}}))}}for(let e of l){let t=o.default.resolve(e);if(!a.default.existsSync(t)||!a.default.statSync(t).isDirectory())throw Error(`${c}: ${t}`);p.has(t)||(p.add(t),f.push({name:o.default.basename(t),directory:t,source:{type:`local`,path:t}}))}return f}function E(e,t,n,r){return T(e,t,n,r).map(e=>e.directory)}const D=`DOOMPI_DOMAINS`,O=`default`,k=`marketing`;function A(e){return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function j(e,t,n){let r=t[D];return r===void 0?n===void 0?A(e===k?k:O):[...n]:A(r)}exports.DEFAULT_DOMAIN=O,exports.DOOMPI_DOMAINS_ENV=D,exports.DOOM_DIR=r.DOOM_DIR,exports.defaultDomainsForMajorMode=j,exports.listDomainNames=C,exports.loadDomains=S,exports.resolvePluginDirectories=E,exports.resolvePluginEntries=T,exports.resolveSharedSkills=w;
1
+ const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./config.cjs"),n=require("../services/domains.cjs"),r=require("./layeredConfig.cjs"),i=require("./pluginCatalog.cjs");let a=require("node:fs");a=e.__toESM(a,1);let o=require("node:path");o=e.__toESM(o,1);let s=require("node:os");s=e.__toESM(s,1);const c=`Plugin directory does not exist`,l=`.doom/domains.yaml`;function u(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function d(e,t){if(!u(e))throw Error(`${t} must be an object`);return e}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(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}function m(e,t){if(e!==void 0)return p(e,t)}function h(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array of non-empty strings`);return[...new Set(e.map((e,n)=>p(e,`${t}[${n}]`)))]}function g(e,t){if(e!==void 0){if(typeof e!=`boolean`)throw Error(`${t} must be a boolean`);return e}}function _(e){return h(e,`defaultDomains in ${l}`)}function v(e,t){if(typeof e==`string`)return p(e,t);let n=d(e,t);f(n,[`name`,`skills`,`agents`,`hooks`,`mcp`],t);let r=n.skills===void 0?void 0:h(n.skills,`${t}.skills`),i=n.agents===void 0?void 0:h(n.agents,`${t}.agents`),a=g(n.hooks,`${t}.hooks`),o=g(n.mcp,`${t}.mcp`);return{name:p(n.name,`${t}.name`),...r?{skills:r}:{},...i?{agents:i}:{},...a===void 0?{}:{hooks:a},...o===void 0?{}:{mcp:o}}}function y(e,t){let n=d(e,t);return f(n,[`servers`,`proxy`],t),{...n.servers===void 0?{}:{servers:h(n.servers,`${t}.servers`)},...n.proxy===void 0?{}:{proxy:h(n.proxy,`${t}.proxy`)}}}function b(e,t){let n=d(e,t);f(n,[`description`,`plugins`,`mcp`,`sharedSkills`],t);let r=m(n.description,`${t}.description`);if(n.plugins!==void 0&&!Array.isArray(n.plugins))throw Error(`${t}.plugins must be an array`);let i=g(n.sharedSkills,`${t}.sharedSkills`);return{...r?{description:r}:{},...Array.isArray(n.plugins)?{plugins:n.plugins.map((e,n)=>v(e,`${t}.plugins[${n}]`))}:{},...n.mcp===void 0?{}:{mcp:y(n.mcp,`${t}.mcp`)},...i===void 0?{}:{sharedSkills:i}}}function x(e,t){if(e===void 0)return{};let n=d(e,t);return Object.fromEntries(Object.entries(n).map(([e,n])=>[e,h(n,`${t}.${e}`)]))}function S(e,t=s.default.homedir()){let a=r.readDoomConfigSources(`domains.yaml`,e,t),o={},c={},u;for(let e of a){let t=d(e.document,e.filePath);if(f(t,[`plugins`,`domains`,`aliases`,`defaultDomains`],e.filePath),Object.assign(o,x(t.aliases,`aliases in ${e.filePath}`)),t.domains!==void 0){let n=d(t.domains,`domains in ${e.filePath}`);for(let[t,r]of Object.entries(n))c[t]={...b(r,`domains.${t} in ${e.filePath}`),baseDirectory:e.baseDirectory}}Object.hasOwn(t,`defaultDomains`)&&(u=_(t.defaultDomains))}let p=i.loadPluginCatalog(a.map(e=>({filePath:e.filePath,baseDirectory:e.baseDirectory,value:d(e.document,e.filePath).plugins})),e,t);if(u){for(let e of n.expandDomainNames({plugins:p,domains:c,aliases:o},u))if(!Object.hasOwn(c,e))throw Error(`Unknown default domain "${e}" in ${l}`)}return{plugins:p,domains:c,aliases:o,...u?{defaultDomains:u}:{}}}function C(e,t){let n=S(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function w(e,t,r){let i=S(e,r),a=n.expandDomainNames(i,t);return a.length===0||a.some(e=>i.domains[e]?.sharedSkills!==!1)}function T(e,r,l,u=s.default.homedir()){let d=S(e,u),f=[],p=new Set,m=t.globalDoomConfigDirectory(u);for(let e of n.expandDomainNames(d,r)){let t=d.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let n of t.plugins??[]){let t=typeof n!=`string`,r=t?n.name:n,o=d.plugins.entries[r];if(!o)throw Error(`Unknown plugin "${r}" referenced by domain "${e}"`);let s=i.pluginDirectoryForSource(o.source,m);if(o.source.type===`local`&&(!a.default.existsSync(s)||!a.default.statSync(s).isDirectory()))throw Error(`${c}: ${s}`);p.has(s)||(p.add(s),f.push({name:r,directory:s,source:o.source,...o.manifest?{manifest:o.manifest}:{},...o.manifest?.agentPluginSchema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?{skillDiscovery:`direct-children`}:{},...t&&n.skills?{skills:n.skills}:{},...t&&n.agents?{agents:n.agents}:{},...t&&n.hooks!==void 0?{hooks:n.hooks}:{},...t&&n.mcp!==void 0?{mcp:n.mcp}:{}}))}}for(let e of l){let t=o.default.resolve(e);if(!a.default.existsSync(t)||!a.default.statSync(t).isDirectory())throw Error(`${c}: ${t}`);p.has(t)||(p.add(t),f.push({name:o.default.basename(t),directory:t,source:{type:`local`,path:t}}))}return f}function E(e,t,n,r){return T(e,t,n,r).map(e=>e.directory)}const D=`DOOMPI_DOMAINS`,O=`default`,k=`marketing`;function A(e){return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function j(e,t,n){let r=t[D];return r===void 0?n===void 0?A(e===k?k:O):[...n]:A(r)}exports.DEFAULT_DOMAIN=O,exports.DOOMPI_DOMAINS_ENV=D,exports.DOOM_DIR=r.DOOM_DIR,exports.defaultDomainsForMajorMode=j,exports.listDomainNames=C,exports.loadDomains=S,exports.resolvePluginDirectories=E,exports.resolvePluginEntries=T,exports.resolveSharedSkills=w;
2
2
  //# sourceMappingURL=domains.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"domains.cjs","names":["os","readDoomConfigSources","loadPluginCatalog","expandDomainNames","globalDoomConfigDirectory","pluginDirectoryForSource","fs","path"],"sources":["../../src/adapters/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { expandDomainNames } from '../services/domains.ts';\nimport type {\n DomainDefinition,\n DomainManifest,\n DomainMcpAllowlist,\n DomainPlugin,\n PluginEntry,\n ResolvedDomain,\n} from '../types/domains.ts';\nimport { globalDoomConfigDirectory } from './config.ts';\nimport { readDoomConfigSources } from './layeredConfig.ts';\nimport { loadPluginCatalog, pluginDirectoryForSource } from './pluginCatalog.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst UNKNOWN_PLUGIN_ERROR = 'Unknown plugin';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst DEFAULT_DOMAINS_PATH = '.doom/domains.yaml';\nconst SUPPORTED_AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\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 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 requireString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, label);\n}\n\nfunction parseStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value)) throw new Error(`${label} must be an array of non-empty strings`);\n return [...new Set(value.map((entry, index) => requireString(entry, `${label}[${index}]`)))];\n}\n\nfunction parseOptionalBoolean(value: unknown, label: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') throw new Error(`${label} must be a boolean`);\n return value;\n}\n\nfunction parseDefaultDomains(value: unknown): string[] {\n return parseStringArray(value, `defaultDomains in ${DEFAULT_DOMAINS_PATH}`);\n}\n\nfunction parseDomainPlugin(value: unknown, label: string): DomainPlugin {\n if (typeof value === 'string') return requireString(value, label);\n const plugin = requireRecord(value, label);\n assertOnlyKeys(plugin, ['name', 'skills', 'agents', 'hooks', 'mcp'], label);\n const skills = plugin.skills === undefined ? undefined : parseStringArray(plugin.skills, `${label}.skills`);\n const agents = plugin.agents === undefined ? undefined : parseStringArray(plugin.agents, `${label}.agents`);\n const hooks = parseOptionalBoolean(plugin.hooks, `${label}.hooks`);\n const mcp = parseOptionalBoolean(plugin.mcp, `${label}.mcp`);\n return {\n name: requireString(plugin.name, `${label}.name`),\n ...(skills ? { skills } : {}),\n ...(agents ? { agents } : {}),\n ...(hooks === undefined ? {} : { hooks }),\n ...(mcp === undefined ? {} : { mcp }),\n };\n}\n\nfunction parseMcpAllowlist(value: unknown, label: string): DomainMcpAllowlist {\n const mcp = requireRecord(value, label);\n assertOnlyKeys(mcp, ['servers', 'proxy'], label);\n return {\n ...(mcp.servers === undefined ? {} : { servers: parseStringArray(mcp.servers, `${label}.servers`) }),\n ...(mcp.proxy === undefined ? {} : { proxy: parseStringArray(mcp.proxy, `${label}.proxy`) }),\n };\n}\n\nfunction parseDomain(value: unknown, label: string): DomainDefinition {\n const domain = requireRecord(value, label);\n assertOnlyKeys(domain, ['description', 'plugins', 'mcp', 'sharedSkills'], label);\n const description = optionalString(domain.description, `${label}.description`);\n if (domain.plugins !== undefined && !Array.isArray(domain.plugins)) {\n throw new Error(`${label}.plugins must be an array`);\n }\n const sharedSkills = parseOptionalBoolean(domain.sharedSkills, `${label}.sharedSkills`);\n return {\n ...(description ? { description } : {}),\n ...(Array.isArray(domain.plugins)\n ? { plugins: domain.plugins.map((plugin, index) => parseDomainPlugin(plugin, `${label}.plugins[${index}]`)) }\n : {}),\n ...(domain.mcp === undefined ? {} : { mcp: parseMcpAllowlist(domain.mcp, `${label}.mcp`) }),\n ...(sharedSkills === undefined ? {} : { sharedSkills }),\n };\n}\n\nfunction parseAliases(value: unknown, label: string): Record<string, string[]> {\n if (value === undefined) return {};\n const aliases = requireRecord(value, label);\n return Object.fromEntries(\n Object.entries(aliases).map(([name, domains]) => [name, parseStringArray(domains, `${label}.${name}`)]),\n );\n}\n\n/**\n * Reads domains and plugin catalogs from global and repository configs.\n *\n * Named domains and explicit plugin entries are replaced by later repository\n * definitions. Configured roots accumulate, with exact marketplace manifests\n * deduplicated in discovery order. Explicit entries override discovered IDs.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<unknown>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n const domains: Record<string, ResolvedDomain> = {};\n let defaultDomains: string[] | undefined;\n\n for (const source of sources) {\n const document = requireRecord(source.document, source.filePath);\n assertOnlyKeys(document, ['plugins', 'domains', 'aliases', 'defaultDomains'], source.filePath);\n Object.assign(aliases, parseAliases(document.aliases, `aliases in ${source.filePath}`));\n if (document.domains !== undefined) {\n const sourceDomains = requireRecord(document.domains, `domains in ${source.filePath}`);\n for (const [name, definition] of Object.entries(sourceDomains)) {\n domains[name] = {\n ...parseDomain(definition, `domains.${name} in ${source.filePath}`),\n baseDirectory: source.baseDirectory,\n };\n }\n }\n if (Object.hasOwn(document, 'defaultDomains')) defaultDomains = parseDefaultDomains(document.defaultDomains);\n }\n\n const plugins = loadPluginCatalog(\n sources.map((source) => ({\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n value: requireRecord(source.document, source.filePath).plugins,\n })),\n repoRoot,\n homeDirectory,\n );\n\n if (defaultDomains) {\n for (const name of expandDomainNames({ plugins, domains, aliases }, defaultDomains)) {\n if (!Object.hasOwn(domains, name)) {\n throw new Error(`Unknown default domain \"${name}\" in ${DEFAULT_DOMAINS_PATH}`);\n }\n }\n }\n return { plugins, domains, aliases, ...(defaultDomains ? { defaultDomains } : {}) };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/**\n * Whether to include .claude/skills as shared fallbacks.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves named domain plugins while preserving each subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory: string = os.homedir(),\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n const homeDoomDirectory = globalDoomConfigDirectory(homeDirectory);\n\n for (const domainName of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[domainName];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${domainName}`);\n for (const selection of domain.plugins ?? []) {\n const isSubset = typeof selection !== 'string';\n const pluginName = isSubset ? selection.name : selection;\n const plugin = manifest.plugins.entries[pluginName];\n if (!plugin) throw new Error(`${UNKNOWN_PLUGIN_ERROR} \"${pluginName}\" referenced by domain \"${domainName}\"`);\n const directory = pluginDirectoryForSource(plugin.source, homeDoomDirectory);\n if (plugin.source.type === 'local' && (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory())) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: pluginName,\n directory,\n source: plugin.source,\n ...(plugin.manifest?.agentPluginSchema === SUPPORTED_AGENT_PLUGIN_SCHEMA\n ? { skillDiscovery: 'direct-children' as const }\n : {}),\n ...(isSubset && selection.skills ? { skills: selection.skills } : {}),\n ...(isSubset && selection.agents ? { agents: selection.agents } : {}),\n ...(isSubset && selection.hooks !== undefined ? { hooks: selection.hooks } : {}),\n ...(isSubset && selection.mcp !== undefined ? { mcp: selection.mcp } : {}),\n });\n }\n }\n\n for (const configuredDirectory of explicitDirectories) {\n const directory = path.resolve(configuredDirectory);\n if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: path.basename(directory),\n directory,\n source: { type: 'local', path: directory },\n });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n\nexport const DOOMPI_DOMAINS_ENV = 'DOOMPI_DOMAINS';\nexport const DEFAULT_DOMAIN = 'default';\nconst MARKETING_MAJOR_MODE = 'marketing';\n\nfunction parseDomainList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n}\n\n/**\n * Domains selected when the caller names none.\n *\n * Configuration keeps this axis independent of the major mode. The\n * major-mode-derived choice is retained only as the compatibility fallback for\n * domains files that declare no defaultDomains.\n */\nexport function defaultDomainsForMajorMode(\n majorMode: string,\n environment: NodeJS.ProcessEnv,\n defaultDomains?: readonly string[],\n): string[] {\n const inherited = environment[DOOMPI_DOMAINS_ENV];\n // An explicitly empty variable means no domains, so this tests for the key\n // rather than for a truthy value.\n if (inherited !== undefined) return parseDomainList(inherited);\n if (defaultDomains !== undefined) return [...defaultDomains];\n return parseDomainList(majorMode === MARKETING_MAJOR_MODE ? MARKETING_MAJOR_MODE : DEFAULT_DOMAIN);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"domains.cjs","names":["os","readDoomConfigSources","loadPluginCatalog","expandDomainNames","globalDoomConfigDirectory","pluginDirectoryForSource","fs","path"],"sources":["../../src/adapters/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { expandDomainNames } from '../services/domains.ts';\nimport type {\n DomainDefinition,\n DomainManifest,\n DomainMcpAllowlist,\n DomainPlugin,\n PluginEntry,\n ResolvedDomain,\n} from '../types/domains.ts';\nimport { globalDoomConfigDirectory } from './config.ts';\nimport { readDoomConfigSources } from './layeredConfig.ts';\nimport { loadPluginCatalog, pluginDirectoryForSource } from './pluginCatalog.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst UNKNOWN_PLUGIN_ERROR = 'Unknown plugin';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst DEFAULT_DOMAINS_PATH = '.doom/domains.yaml';\nconst SUPPORTED_AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\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 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 requireString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, label);\n}\n\nfunction parseStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value)) throw new Error(`${label} must be an array of non-empty strings`);\n return [...new Set(value.map((entry, index) => requireString(entry, `${label}[${index}]`)))];\n}\n\nfunction parseOptionalBoolean(value: unknown, label: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') throw new Error(`${label} must be a boolean`);\n return value;\n}\n\nfunction parseDefaultDomains(value: unknown): string[] {\n return parseStringArray(value, `defaultDomains in ${DEFAULT_DOMAINS_PATH}`);\n}\n\nfunction parseDomainPlugin(value: unknown, label: string): DomainPlugin {\n if (typeof value === 'string') return requireString(value, label);\n const plugin = requireRecord(value, label);\n assertOnlyKeys(plugin, ['name', 'skills', 'agents', 'hooks', 'mcp'], label);\n const skills = plugin.skills === undefined ? undefined : parseStringArray(plugin.skills, `${label}.skills`);\n const agents = plugin.agents === undefined ? undefined : parseStringArray(plugin.agents, `${label}.agents`);\n const hooks = parseOptionalBoolean(plugin.hooks, `${label}.hooks`);\n const mcp = parseOptionalBoolean(plugin.mcp, `${label}.mcp`);\n return {\n name: requireString(plugin.name, `${label}.name`),\n ...(skills ? { skills } : {}),\n ...(agents ? { agents } : {}),\n ...(hooks === undefined ? {} : { hooks }),\n ...(mcp === undefined ? {} : { mcp }),\n };\n}\n\nfunction parseMcpAllowlist(value: unknown, label: string): DomainMcpAllowlist {\n const mcp = requireRecord(value, label);\n assertOnlyKeys(mcp, ['servers', 'proxy'], label);\n return {\n ...(mcp.servers === undefined ? {} : { servers: parseStringArray(mcp.servers, `${label}.servers`) }),\n ...(mcp.proxy === undefined ? {} : { proxy: parseStringArray(mcp.proxy, `${label}.proxy`) }),\n };\n}\n\nfunction parseDomain(value: unknown, label: string): DomainDefinition {\n const domain = requireRecord(value, label);\n assertOnlyKeys(domain, ['description', 'plugins', 'mcp', 'sharedSkills'], label);\n const description = optionalString(domain.description, `${label}.description`);\n if (domain.plugins !== undefined && !Array.isArray(domain.plugins)) {\n throw new Error(`${label}.plugins must be an array`);\n }\n const sharedSkills = parseOptionalBoolean(domain.sharedSkills, `${label}.sharedSkills`);\n return {\n ...(description ? { description } : {}),\n ...(Array.isArray(domain.plugins)\n ? { plugins: domain.plugins.map((plugin, index) => parseDomainPlugin(plugin, `${label}.plugins[${index}]`)) }\n : {}),\n ...(domain.mcp === undefined ? {} : { mcp: parseMcpAllowlist(domain.mcp, `${label}.mcp`) }),\n ...(sharedSkills === undefined ? {} : { sharedSkills }),\n };\n}\n\nfunction parseAliases(value: unknown, label: string): Record<string, string[]> {\n if (value === undefined) return {};\n const aliases = requireRecord(value, label);\n return Object.fromEntries(\n Object.entries(aliases).map(([name, domains]) => [name, parseStringArray(domains, `${label}.${name}`)]),\n );\n}\n\n/**\n * Reads domains and plugin catalogs from global and repository configs.\n *\n * Named domains and explicit plugin entries are replaced by later repository\n * definitions. Configured roots accumulate, with exact marketplace manifests\n * deduplicated in discovery order. Explicit entries override discovered IDs.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<unknown>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n const domains: Record<string, ResolvedDomain> = {};\n let defaultDomains: string[] | undefined;\n\n for (const source of sources) {\n const document = requireRecord(source.document, source.filePath);\n assertOnlyKeys(document, ['plugins', 'domains', 'aliases', 'defaultDomains'], source.filePath);\n Object.assign(aliases, parseAliases(document.aliases, `aliases in ${source.filePath}`));\n if (document.domains !== undefined) {\n const sourceDomains = requireRecord(document.domains, `domains in ${source.filePath}`);\n for (const [name, definition] of Object.entries(sourceDomains)) {\n domains[name] = {\n ...parseDomain(definition, `domains.${name} in ${source.filePath}`),\n baseDirectory: source.baseDirectory,\n };\n }\n }\n if (Object.hasOwn(document, 'defaultDomains')) defaultDomains = parseDefaultDomains(document.defaultDomains);\n }\n\n const plugins = loadPluginCatalog(\n sources.map((source) => ({\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n value: requireRecord(source.document, source.filePath).plugins,\n })),\n repoRoot,\n homeDirectory,\n );\n\n if (defaultDomains) {\n for (const name of expandDomainNames({ plugins, domains, aliases }, defaultDomains)) {\n if (!Object.hasOwn(domains, name)) {\n throw new Error(`Unknown default domain \"${name}\" in ${DEFAULT_DOMAINS_PATH}`);\n }\n }\n }\n return { plugins, domains, aliases, ...(defaultDomains ? { defaultDomains } : {}) };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/**\n * Whether to include .claude/skills as shared fallbacks.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves named domain plugins while preserving each subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory: string = os.homedir(),\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n const homeDoomDirectory = globalDoomConfigDirectory(homeDirectory);\n\n for (const domainName of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[domainName];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${domainName}`);\n for (const selection of domain.plugins ?? []) {\n const isSubset = typeof selection !== 'string';\n const pluginName = isSubset ? selection.name : selection;\n const plugin = manifest.plugins.entries[pluginName];\n if (!plugin) throw new Error(`${UNKNOWN_PLUGIN_ERROR} \"${pluginName}\" referenced by domain \"${domainName}\"`);\n const directory = pluginDirectoryForSource(plugin.source, homeDoomDirectory);\n if (plugin.source.type === 'local' && (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory())) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: pluginName,\n directory,\n source: plugin.source,\n ...(plugin.manifest ? { manifest: plugin.manifest } : {}),\n ...(plugin.manifest?.agentPluginSchema === SUPPORTED_AGENT_PLUGIN_SCHEMA\n ? { skillDiscovery: 'direct-children' as const }\n : {}),\n ...(isSubset && selection.skills ? { skills: selection.skills } : {}),\n ...(isSubset && selection.agents ? { agents: selection.agents } : {}),\n ...(isSubset && selection.hooks !== undefined ? { hooks: selection.hooks } : {}),\n ...(isSubset && selection.mcp !== undefined ? { mcp: selection.mcp } : {}),\n });\n }\n }\n\n for (const configuredDirectory of explicitDirectories) {\n const directory = path.resolve(configuredDirectory);\n if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: path.basename(directory),\n directory,\n source: { type: 'local', path: directory },\n });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n\nexport const DOOMPI_DOMAINS_ENV = 'DOOMPI_DOMAINS';\nexport const DEFAULT_DOMAIN = 'default';\nconst MARKETING_MAJOR_MODE = 'marketing';\n\nfunction parseDomainList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n}\n\n/**\n * Domains selected when the caller names none.\n *\n * Configuration keeps this axis independent of the major mode. The\n * major-mode-derived choice is retained only as the compatibility fallback for\n * domains files that declare no defaultDomains.\n */\nexport function defaultDomainsForMajorMode(\n majorMode: string,\n environment: NodeJS.ProcessEnv,\n defaultDomains?: readonly string[],\n): string[] {\n const inherited = environment[DOOMPI_DOMAINS_ENV];\n // An explicitly empty variable means no domains, so this tests for the key\n // rather than for a truthy value.\n if (inherited !== undefined) return parseDomainList(inherited);\n if (defaultDomains !== undefined) return [...defaultDomains];\n return parseDomainList(majorMode === MARKETING_MAJOR_MODE ? MARKETING_MAJOR_MODE : DEFAULT_DOMAIN);\n}\n"],"mappings":"sTAkBA,MAGM,EAAiC,kCACjC,EAAuB,qBAG7B,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,SAAS,EAAc,EAAgB,EAAwC,CAC7E,GAAI,CAAC,EAAS,CAAK,EAAG,MAAU,MAAM,GAAG,EAAM,mBAAmB,EAClE,OAAO,CACT,CAEA,SAAS,EAAe,EAAiC,EAA4B,EAAqB,CACxG,IAAM,EAAa,OAAO,KAAK,CAAM,CAAC,CAAC,OAAQ,GAAQ,CAAC,EAAQ,SAAS,CAAG,CAAC,EAC7E,GAAI,EAAW,OAAS,EAAG,MAAU,MAAM,GAAG,EAAM,+BAA+B,EAAW,GAAG,EAAE,CACrG,CAEA,SAAS,EAAc,EAAgB,EAAuB,CAC5D,GAAI,OAAO,GAAU,UAAY,CAAC,EAAM,KAAK,EAAG,MAAU,MAAM,GAAG,EAAM,4BAA4B,EACrG,OAAO,EAAM,KAAK,CACpB,CAEA,SAAS,EAAe,EAAgB,EAAmC,CACrE,OAAU,IAAA,GACd,OAAO,EAAc,EAAO,CAAK,CACnC,CAEA,SAAS,EAAiB,EAAgB,EAAyB,CACjE,GAAI,CAAC,MAAM,QAAQ,CAAK,EAAG,MAAU,MAAM,GAAG,EAAM,uCAAuC,EAC3F,MAAO,CAAC,GAAG,IAAI,IAAI,EAAM,KAAK,EAAO,IAAU,EAAc,EAAO,GAAG,EAAM,GAAG,EAAM,EAAE,CAAC,CAAC,CAAC,CAC7F,CAEA,SAAS,EAAqB,EAAgB,EAAoC,CAC5E,OAAU,IAAA,GACd,IAAI,OAAO,GAAU,UAAW,MAAU,MAAM,GAAG,EAAM,mBAAmB,EAC5E,OAAO,CADqE,CAE9E,CAEA,SAAS,EAAoB,EAA0B,CACrD,OAAO,EAAiB,EAAO,qBAAqB,GAAsB,CAC5E,CAEA,SAAS,EAAkB,EAAgB,EAA6B,CACtE,GAAI,OAAO,GAAU,SAAU,OAAO,EAAc,EAAO,CAAK,EAChE,IAAM,EAAS,EAAc,EAAO,CAAK,EACzC,EAAe,EAAQ,CAAC,OAAQ,SAAU,SAAU,QAAS,KAAK,EAAG,CAAK,EAC1E,IAAM,EAAS,EAAO,SAAW,IAAA,GAAY,IAAA,GAAY,EAAiB,EAAO,OAAQ,GAAG,EAAM,QAAQ,EACpG,EAAS,EAAO,SAAW,IAAA,GAAY,IAAA,GAAY,EAAiB,EAAO,OAAQ,GAAG,EAAM,QAAQ,EACpG,EAAQ,EAAqB,EAAO,MAAO,GAAG,EAAM,OAAO,EAC3D,EAAM,EAAqB,EAAO,IAAK,GAAG,EAAM,KAAK,EAC3D,MAAO,CACL,KAAM,EAAc,EAAO,KAAM,GAAG,EAAM,MAAM,EAChD,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,EAC3B,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,EAC3B,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,OAAM,EACvC,GAAI,IAAQ,IAAA,GAAY,CAAC,EAAI,CAAE,KAAI,CACrC,CACF,CAEA,SAAS,EAAkB,EAAgB,EAAmC,CAC5E,IAAM,EAAM,EAAc,EAAO,CAAK,EAEtC,OADA,EAAe,EAAK,CAAC,UAAW,OAAO,EAAG,CAAK,EACxC,CACL,GAAI,EAAI,UAAY,IAAA,GAAY,CAAC,EAAI,CAAE,QAAS,EAAiB,EAAI,QAAS,GAAG,EAAM,SAAS,CAAE,EAClG,GAAI,EAAI,QAAU,IAAA,GAAY,CAAC,EAAI,CAAE,MAAO,EAAiB,EAAI,MAAO,GAAG,EAAM,OAAO,CAAE,CAC5F,CACF,CAEA,SAAS,EAAY,EAAgB,EAAiC,CACpE,IAAM,EAAS,EAAc,EAAO,CAAK,EACzC,EAAe,EAAQ,CAAC,cAAe,UAAW,MAAO,cAAc,EAAG,CAAK,EAC/E,IAAM,EAAc,EAAe,EAAO,YAAa,GAAG,EAAM,aAAa,EAC7E,GAAI,EAAO,UAAY,IAAA,IAAa,CAAC,MAAM,QAAQ,EAAO,OAAO,EAC/D,MAAU,MAAM,GAAG,EAAM,0BAA0B,EAErD,IAAM,EAAe,EAAqB,EAAO,aAAc,GAAG,EAAM,cAAc,EACtF,MAAO,CACL,GAAI,EAAc,CAAE,aAAY,EAAI,CAAC,EACrC,GAAI,MAAM,QAAQ,EAAO,OAAO,EAC5B,CAAE,QAAS,EAAO,QAAQ,KAAK,EAAQ,IAAU,EAAkB,EAAQ,GAAG,EAAM,WAAW,EAAM,EAAE,CAAC,CAAE,EAC1G,CAAC,EACL,GAAI,EAAO,MAAQ,IAAA,GAAY,CAAC,EAAI,CAAE,IAAK,EAAkB,EAAO,IAAK,GAAG,EAAM,KAAK,CAAE,EACzF,GAAI,IAAiB,IAAA,GAAY,CAAC,EAAI,CAAE,cAAa,CACvD,CACF,CAEA,SAAS,EAAa,EAAgB,EAAyC,CAC7E,GAAI,IAAU,IAAA,GAAW,MAAO,CAAC,EACjC,IAAM,EAAU,EAAc,EAAO,CAAK,EAC1C,OAAO,OAAO,YACZ,OAAO,QAAQ,CAAO,CAAC,CAAC,KAAK,CAAC,EAAM,KAAa,CAAC,EAAM,EAAiB,EAAS,GAAG,EAAM,GAAG,GAAM,CAAC,CAAC,CACxG,CACF,CASA,SAAgB,EAAY,EAAkB,EAAwBA,EAAAA,QAAG,QAAQ,EAAmB,CAClG,IAAM,EAAUC,EAAAA,sBAA+B,eAAc,EAAU,CAAa,EAC9E,EAAoC,CAAC,EACrC,EAA0C,CAAC,EAC7C,EAEJ,IAAK,IAAM,KAAU,EAAS,CAC5B,IAAM,EAAW,EAAc,EAAO,SAAU,EAAO,QAAQ,EAG/D,GAFA,EAAe,EAAU,CAAC,UAAW,UAAW,UAAW,gBAAgB,EAAG,EAAO,QAAQ,EAC7F,OAAO,OAAO,EAAS,EAAa,EAAS,QAAS,cAAc,EAAO,UAAU,CAAC,EAClF,EAAS,UAAY,IAAA,GAAW,CAClC,IAAM,EAAgB,EAAc,EAAS,QAAS,cAAc,EAAO,UAAU,EACrF,IAAK,GAAM,CAAC,EAAM,KAAe,OAAO,QAAQ,CAAa,EAC3D,EAAQ,GAAQ,CACd,GAAG,EAAY,EAAY,WAAW,EAAK,MAAM,EAAO,UAAU,EAClE,cAAe,EAAO,aACxB,CAEJ,CACI,OAAO,OAAO,EAAU,gBAAgB,IAAG,EAAiB,EAAoB,EAAS,cAAc,EAC7G,CAEA,IAAM,EAAUC,EAAAA,kBACd,EAAQ,IAAK,IAAY,CACvB,SAAU,EAAO,SACjB,cAAe,EAAO,cACtB,MAAO,EAAc,EAAO,SAAU,EAAO,QAAQ,CAAC,CAAC,OACzD,EAAE,EACF,EACA,CACF,EAEA,GAAI,EACG,KAAA,IAAM,KAAQC,EAAAA,kBAAkB,CAAE,UAAS,UAAS,SAAQ,EAAG,CAAc,EAChF,GAAI,CAAC,OAAO,OAAO,EAAS,CAAI,EAC9B,MAAU,MAAM,2BAA2B,EAAK,OAAO,GAAsB,CAAA,CAInF,MAAO,CAAE,UAAS,UAAS,UAAS,GAAI,EAAiB,CAAE,gBAAe,EAAI,CAAC,CAAG,CACpF,CAEA,SAAgB,EAAgB,EAAkB,EAAkC,CAClF,IAAM,EAAW,EAAY,EAAU,CAAa,EACpD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAS,OAAO,EAAG,GAAG,OAAO,KAAK,EAAS,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CACjG,CAQA,SAAgB,EAAoB,EAAkB,EAAuB,EAAiC,CAC5G,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAWA,EAAAA,kBAAkB,EAAU,CAAW,EAExD,OADI,EAAS,SAAW,GACjB,EAAS,KAAM,GAAS,EAAS,QAAQ,EAAK,EAAE,eAAiB,EAAK,CAC/E,CAGA,SAAgB,EACd,EACA,EACA,EACA,EAAwBH,EAAAA,QAAG,QAAQ,EACpB,CACf,IAAM,EAAW,EAAY,EAAU,CAAa,EAC9C,EAAyB,CAAC,EAC1B,EAAO,IAAI,IACX,EAAoBI,EAAAA,0BAA0B,CAAa,EAEjE,IAAK,IAAM,KAAcD,EAAAA,kBAAkB,EAAU,CAAW,EAAG,CACjE,IAAM,EAAS,EAAS,QAAQ,GAChC,GAAI,CAAC,EAAQ,MAAU,MAAM,mBAA4B,GAAY,EACrE,IAAK,IAAM,KAAa,EAAO,SAAW,CAAC,EAAG,CAC5C,IAAM,EAAW,OAAO,GAAc,SAChC,EAAa,EAAW,EAAU,KAAO,EACzC,EAAS,EAAS,QAAQ,QAAQ,GACxC,GAAI,CAAC,EAAQ,MAAU,MAAM,mBAA4B,EAAW,0BAA0B,EAAW,EAAE,EAC3G,IAAM,EAAYE,EAAAA,yBAAyB,EAAO,OAAQ,CAAiB,EAC3E,GAAI,EAAO,OAAO,OAAS,UAAY,CAACC,EAAAA,QAAG,WAAW,CAAS,GAAK,CAACA,EAAAA,QAAG,SAAS,CAAS,CAAC,CAAC,YAAY,GACtG,MAAU,MAAM,GAAG,EAA+B,IAAI,GAAW,EAE/D,EAAK,IAAI,CAAS,IACtB,EAAK,IAAI,CAAS,EAClB,EAAQ,KAAK,CACX,KAAM,EACN,YACA,OAAQ,EAAO,OACf,GAAI,EAAO,SAAW,CAAE,SAAU,EAAO,QAAS,EAAI,CAAC,EACvD,GAAI,EAAO,UAAU,oBAAsB,6DACvC,CAAE,eAAgB,iBAA2B,EAC7C,CAAC,EACL,GAAI,GAAY,EAAU,OAAS,CAAE,OAAQ,EAAU,MAAO,EAAI,CAAC,EACnE,GAAI,GAAY,EAAU,OAAS,CAAE,OAAQ,EAAU,MAAO,EAAI,CAAC,EACnE,GAAI,GAAY,EAAU,QAAU,IAAA,GAAY,CAAE,MAAO,EAAU,KAAM,EAAI,CAAC,EAC9E,GAAI,GAAY,EAAU,MAAQ,IAAA,GAAY,CAAE,IAAK,EAAU,GAAI,EAAI,CAAC,CAC1E,CAAC,EACH,CACF,CAEA,IAAK,IAAM,KAAuB,EAAqB,CACrD,IAAM,EAAYC,EAAAA,QAAK,QAAQ,CAAmB,EAClD,GAAI,CAACD,EAAAA,QAAG,WAAW,CAAS,GAAK,CAACA,EAAAA,QAAG,SAAS,CAAS,CAAC,CAAC,YAAY,EACnE,MAAU,MAAM,GAAG,EAA+B,IAAI,GAAW,EAE/D,EAAK,IAAI,CAAS,IACtB,EAAK,IAAI,CAAS,EAClB,EAAQ,KAAK,CACX,KAAMC,EAAAA,QAAK,SAAS,CAAS,EAC7B,YACA,OAAQ,CAAE,KAAM,QAAS,KAAM,CAAU,CAC3C,CAAC,EACH,CACA,OAAO,CACT,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACU,CACV,OAAO,EAAqB,EAAU,EAAa,EAAqB,CAAa,CAAC,CAAC,IACpF,GAAU,EAAM,SACnB,CACF,CAEA,MAAa,EAAqB,iBACrB,EAAiB,UACxB,EAAuB,YAE7B,SAAS,EAAgB,EAAyB,CAChD,OAAO,EACJ,MAAM,GAAG,CAAC,CACV,IAAK,GAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,CACnB,CASA,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAM,EAAY,EAAY,GAK9B,OAFI,IAAc,IAAA,GACd,IAAmB,IAAA,GAChB,EAAgB,IAAc,EAAuB,EAAuB,CAAc,EADxD,CAAC,GAAG,CAAc,EADvB,EAAgB,CAAS,CAG/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"domains.d.cts","names":[],"sources":["../../src/adapters/domains.ts"],"mappings":";;;;;;;;;;iBA2HgB,YAAY,kBAAkB,yBAAuC;iBA0CrE,gBAAgB,kBAAkB;;;;;;;iBAWlC,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAmDa,yBACd,kBACA,uBACA,+BACA;cAOW;cACA;;;;;;;;iBAiBG,2BACd,mBACA,aAAa,OAAO,YACpB"}
1
+ {"version":3,"file":"domains.d.cts","names":[],"sources":["../../src/adapters/domains.ts"],"mappings":";;;;;;;;;;iBA2HgB,YAAY,kBAAkB,yBAAuC;iBA0CrE,gBAAgB,kBAAkB;;;;;;;iBAWlC,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAoDa,yBACd,kBACA,uBACA,+BACA;cAOW;cACA;;;;;;;;iBAiBG,2BACd,mBACA,aAAa,OAAO,YACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"domains.d.mts","names":[],"sources":["../../src/adapters/domains.ts"],"mappings":";;;;;;;;;;iBA2HgB,YAAY,kBAAkB,yBAAuC;iBA0CrE,gBAAgB,kBAAkB;;;;;;;iBAWlC,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAmDa,yBACd,kBACA,uBACA,+BACA;cAOW;cACA;;;;;;;;iBAiBG,2BACd,mBACA,aAAa,OAAO,YACpB"}
1
+ {"version":3,"file":"domains.d.mts","names":[],"sources":["../../src/adapters/domains.ts"],"mappings":";;;;;;;;;;iBA2HgB,YAAY,kBAAkB,yBAAuC;iBA0CrE,gBAAgB,kBAAkB;;;;;;;iBAWlC,oBAAoB,kBAAkB,uBAAuB;;iBAQ7D,qBACd,kBACA,uBACA,+BACA,yBACC;iBAoDa,yBACd,kBACA,uBACA,+BACA;cAOW;cACA;;;;;;;;iBAiBG,2BACd,mBACA,aAAa,OAAO,YACpB"}
@@ -1,2 +1,2 @@
1
- import{globalDoomConfigDirectory as e}from"./config.mjs";import{expandDomainNames as t}from"../services/domains.mjs";import{DOOM_DIR as n,readDoomConfigSources as r}from"./layeredConfig.mjs";import{loadPluginCatalog as i,pluginDirectoryForSource as a}from"./pluginCatalog.mjs";import o from"node:fs";import s from"node:path";import c from"node:os";const l=`Plugin directory does not exist`,u=`.doom/domains.yaml`;function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e,t){if(!d(e))throw Error(`${t} must be an object`);return e}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(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}function h(e,t){if(e!==void 0)return m(e,t)}function g(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array of non-empty strings`);return[...new Set(e.map((e,n)=>m(e,`${t}[${n}]`)))]}function _(e,t){if(e!==void 0){if(typeof e!=`boolean`)throw Error(`${t} must be a boolean`);return e}}function v(e){return g(e,`defaultDomains in ${u}`)}function y(e,t){if(typeof e==`string`)return m(e,t);let n=f(e,t);p(n,[`name`,`skills`,`agents`,`hooks`,`mcp`],t);let r=n.skills===void 0?void 0:g(n.skills,`${t}.skills`),i=n.agents===void 0?void 0:g(n.agents,`${t}.agents`),a=_(n.hooks,`${t}.hooks`),o=_(n.mcp,`${t}.mcp`);return{name:m(n.name,`${t}.name`),...r?{skills:r}:{},...i?{agents:i}:{},...a===void 0?{}:{hooks:a},...o===void 0?{}:{mcp:o}}}function b(e,t){let n=f(e,t);return p(n,[`servers`,`proxy`],t),{...n.servers===void 0?{}:{servers:g(n.servers,`${t}.servers`)},...n.proxy===void 0?{}:{proxy:g(n.proxy,`${t}.proxy`)}}}function x(e,t){let n=f(e,t);p(n,[`description`,`plugins`,`mcp`,`sharedSkills`],t);let r=h(n.description,`${t}.description`);if(n.plugins!==void 0&&!Array.isArray(n.plugins))throw Error(`${t}.plugins must be an array`);let i=_(n.sharedSkills,`${t}.sharedSkills`);return{...r?{description:r}:{},...Array.isArray(n.plugins)?{plugins:n.plugins.map((e,n)=>y(e,`${t}.plugins[${n}]`))}:{},...n.mcp===void 0?{}:{mcp:b(n.mcp,`${t}.mcp`)},...i===void 0?{}:{sharedSkills:i}}}function S(e,t){if(e===void 0)return{};let n=f(e,t);return Object.fromEntries(Object.entries(n).map(([e,n])=>[e,g(n,`${t}.${e}`)]))}function C(e,n=c.homedir()){let a=r(`domains.yaml`,e,n),o={},s={},l;for(let e of a){let t=f(e.document,e.filePath);if(p(t,[`plugins`,`domains`,`aliases`,`defaultDomains`],e.filePath),Object.assign(o,S(t.aliases,`aliases in ${e.filePath}`)),t.domains!==void 0){let n=f(t.domains,`domains in ${e.filePath}`);for(let[t,r]of Object.entries(n))s[t]={...x(r,`domains.${t} in ${e.filePath}`),baseDirectory:e.baseDirectory}}Object.hasOwn(t,`defaultDomains`)&&(l=v(t.defaultDomains))}let d=i(a.map(e=>({filePath:e.filePath,baseDirectory:e.baseDirectory,value:f(e.document,e.filePath).plugins})),e,n);if(l){for(let e of t({plugins:d,domains:s,aliases:o},l))if(!Object.hasOwn(s,e))throw Error(`Unknown default domain "${e}" in ${u}`)}return{plugins:d,domains:s,aliases:o,...l?{defaultDomains:l}:{}}}function w(e,t){let n=C(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function T(e,n,r){let i=C(e,r),a=t(i,n);return a.length===0||a.some(e=>i.domains[e]?.sharedSkills!==!1)}function E(n,r,i,u=c.homedir()){let d=C(n,u),f=[],p=new Set,m=e(u);for(let e of t(d,r)){let t=d.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let n of t.plugins??[]){let t=typeof n!=`string`,r=t?n.name:n,i=d.plugins.entries[r];if(!i)throw Error(`Unknown plugin "${r}" referenced by domain "${e}"`);let s=a(i.source,m);if(i.source.type===`local`&&(!o.existsSync(s)||!o.statSync(s).isDirectory()))throw Error(`${l}: ${s}`);p.has(s)||(p.add(s),f.push({name:r,directory:s,source:i.source,...i.manifest?.agentPluginSchema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?{skillDiscovery:`direct-children`}:{},...t&&n.skills?{skills:n.skills}:{},...t&&n.agents?{agents:n.agents}:{},...t&&n.hooks!==void 0?{hooks:n.hooks}:{},...t&&n.mcp!==void 0?{mcp:n.mcp}:{}}))}}for(let e of i){let t=s.resolve(e);if(!o.existsSync(t)||!o.statSync(t).isDirectory())throw Error(`${l}: ${t}`);p.has(t)||(p.add(t),f.push({name:s.basename(t),directory:t,source:{type:`local`,path:t}}))}return f}function D(e,t,n,r){return E(e,t,n,r).map(e=>e.directory)}const O=`DOOMPI_DOMAINS`,k=`default`,A=`marketing`;function j(e){return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function M(e,t,n){let r=t[O];return r===void 0?n===void 0?j(e===A?A:k):[...n]:j(r)}export{k as DEFAULT_DOMAIN,O as DOOMPI_DOMAINS_ENV,n as DOOM_DIR,M as defaultDomainsForMajorMode,w as listDomainNames,C as loadDomains,D as resolvePluginDirectories,E as resolvePluginEntries,T as resolveSharedSkills};
1
+ import{globalDoomConfigDirectory as e}from"./config.mjs";import{expandDomainNames as t}from"../services/domains.mjs";import{DOOM_DIR as n,readDoomConfigSources as r}from"./layeredConfig.mjs";import{loadPluginCatalog as i,pluginDirectoryForSource as a}from"./pluginCatalog.mjs";import o from"node:fs";import s from"node:path";import c from"node:os";const l=`Plugin directory does not exist`,u=`.doom/domains.yaml`;function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e,t){if(!d(e))throw Error(`${t} must be an object`);return e}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(typeof e!=`string`||!e.trim())throw Error(`${t} must be a non-empty string`);return e.trim()}function h(e,t){if(e!==void 0)return m(e,t)}function g(e,t){if(!Array.isArray(e))throw Error(`${t} must be an array of non-empty strings`);return[...new Set(e.map((e,n)=>m(e,`${t}[${n}]`)))]}function _(e,t){if(e!==void 0){if(typeof e!=`boolean`)throw Error(`${t} must be a boolean`);return e}}function v(e){return g(e,`defaultDomains in ${u}`)}function y(e,t){if(typeof e==`string`)return m(e,t);let n=f(e,t);p(n,[`name`,`skills`,`agents`,`hooks`,`mcp`],t);let r=n.skills===void 0?void 0:g(n.skills,`${t}.skills`),i=n.agents===void 0?void 0:g(n.agents,`${t}.agents`),a=_(n.hooks,`${t}.hooks`),o=_(n.mcp,`${t}.mcp`);return{name:m(n.name,`${t}.name`),...r?{skills:r}:{},...i?{agents:i}:{},...a===void 0?{}:{hooks:a},...o===void 0?{}:{mcp:o}}}function b(e,t){let n=f(e,t);return p(n,[`servers`,`proxy`],t),{...n.servers===void 0?{}:{servers:g(n.servers,`${t}.servers`)},...n.proxy===void 0?{}:{proxy:g(n.proxy,`${t}.proxy`)}}}function x(e,t){let n=f(e,t);p(n,[`description`,`plugins`,`mcp`,`sharedSkills`],t);let r=h(n.description,`${t}.description`);if(n.plugins!==void 0&&!Array.isArray(n.plugins))throw Error(`${t}.plugins must be an array`);let i=_(n.sharedSkills,`${t}.sharedSkills`);return{...r?{description:r}:{},...Array.isArray(n.plugins)?{plugins:n.plugins.map((e,n)=>y(e,`${t}.plugins[${n}]`))}:{},...n.mcp===void 0?{}:{mcp:b(n.mcp,`${t}.mcp`)},...i===void 0?{}:{sharedSkills:i}}}function S(e,t){if(e===void 0)return{};let n=f(e,t);return Object.fromEntries(Object.entries(n).map(([e,n])=>[e,g(n,`${t}.${e}`)]))}function C(e,n=c.homedir()){let a=r(`domains.yaml`,e,n),o={},s={},l;for(let e of a){let t=f(e.document,e.filePath);if(p(t,[`plugins`,`domains`,`aliases`,`defaultDomains`],e.filePath),Object.assign(o,S(t.aliases,`aliases in ${e.filePath}`)),t.domains!==void 0){let n=f(t.domains,`domains in ${e.filePath}`);for(let[t,r]of Object.entries(n))s[t]={...x(r,`domains.${t} in ${e.filePath}`),baseDirectory:e.baseDirectory}}Object.hasOwn(t,`defaultDomains`)&&(l=v(t.defaultDomains))}let d=i(a.map(e=>({filePath:e.filePath,baseDirectory:e.baseDirectory,value:f(e.document,e.filePath).plugins})),e,n);if(l){for(let e of t({plugins:d,domains:s,aliases:o},l))if(!Object.hasOwn(s,e))throw Error(`Unknown default domain "${e}" in ${u}`)}return{plugins:d,domains:s,aliases:o,...l?{defaultDomains:l}:{}}}function w(e,t){let n=C(e,t);return[...new Set([...Object.keys(n.domains),...Object.keys(n.aliases)])].sort()}function T(e,n,r){let i=C(e,r),a=t(i,n);return a.length===0||a.some(e=>i.domains[e]?.sharedSkills!==!1)}function E(n,r,i,u=c.homedir()){let d=C(n,u),f=[],p=new Set,m=e(u);for(let e of t(d,r)){let t=d.domains[e];if(!t)throw Error(`Unknown domain: ${e}`);for(let n of t.plugins??[]){let t=typeof n!=`string`,r=t?n.name:n,i=d.plugins.entries[r];if(!i)throw Error(`Unknown plugin "${r}" referenced by domain "${e}"`);let s=a(i.source,m);if(i.source.type===`local`&&(!o.existsSync(s)||!o.statSync(s).isDirectory()))throw Error(`${l}: ${s}`);p.has(s)||(p.add(s),f.push({name:r,directory:s,source:i.source,...i.manifest?{manifest:i.manifest}:{},...i.manifest?.agentPluginSchema===`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`?{skillDiscovery:`direct-children`}:{},...t&&n.skills?{skills:n.skills}:{},...t&&n.agents?{agents:n.agents}:{},...t&&n.hooks!==void 0?{hooks:n.hooks}:{},...t&&n.mcp!==void 0?{mcp:n.mcp}:{}}))}}for(let e of i){let t=s.resolve(e);if(!o.existsSync(t)||!o.statSync(t).isDirectory())throw Error(`${l}: ${t}`);p.has(t)||(p.add(t),f.push({name:s.basename(t),directory:t,source:{type:`local`,path:t}}))}return f}function D(e,t,n,r){return E(e,t,n,r).map(e=>e.directory)}const O=`DOOMPI_DOMAINS`,k=`default`,A=`marketing`;function j(e){return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function M(e,t,n){let r=t[O];return r===void 0?n===void 0?j(e===A?A:k):[...n]:j(r)}export{k as DEFAULT_DOMAIN,O as DOOMPI_DOMAINS_ENV,n as DOOM_DIR,M as defaultDomainsForMajorMode,w as listDomainNames,C as loadDomains,D as resolvePluginDirectories,E as resolvePluginEntries,T as resolveSharedSkills};
2
2
  //# sourceMappingURL=domains.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"domains.mjs","names":[],"sources":["../../src/adapters/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { expandDomainNames } from '../services/domains.ts';\nimport type {\n DomainDefinition,\n DomainManifest,\n DomainMcpAllowlist,\n DomainPlugin,\n PluginEntry,\n ResolvedDomain,\n} from '../types/domains.ts';\nimport { globalDoomConfigDirectory } from './config.ts';\nimport { readDoomConfigSources } from './layeredConfig.ts';\nimport { loadPluginCatalog, pluginDirectoryForSource } from './pluginCatalog.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst UNKNOWN_PLUGIN_ERROR = 'Unknown plugin';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst DEFAULT_DOMAINS_PATH = '.doom/domains.yaml';\nconst SUPPORTED_AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\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 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 requireString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, label);\n}\n\nfunction parseStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value)) throw new Error(`${label} must be an array of non-empty strings`);\n return [...new Set(value.map((entry, index) => requireString(entry, `${label}[${index}]`)))];\n}\n\nfunction parseOptionalBoolean(value: unknown, label: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') throw new Error(`${label} must be a boolean`);\n return value;\n}\n\nfunction parseDefaultDomains(value: unknown): string[] {\n return parseStringArray(value, `defaultDomains in ${DEFAULT_DOMAINS_PATH}`);\n}\n\nfunction parseDomainPlugin(value: unknown, label: string): DomainPlugin {\n if (typeof value === 'string') return requireString(value, label);\n const plugin = requireRecord(value, label);\n assertOnlyKeys(plugin, ['name', 'skills', 'agents', 'hooks', 'mcp'], label);\n const skills = plugin.skills === undefined ? undefined : parseStringArray(plugin.skills, `${label}.skills`);\n const agents = plugin.agents === undefined ? undefined : parseStringArray(plugin.agents, `${label}.agents`);\n const hooks = parseOptionalBoolean(plugin.hooks, `${label}.hooks`);\n const mcp = parseOptionalBoolean(plugin.mcp, `${label}.mcp`);\n return {\n name: requireString(plugin.name, `${label}.name`),\n ...(skills ? { skills } : {}),\n ...(agents ? { agents } : {}),\n ...(hooks === undefined ? {} : { hooks }),\n ...(mcp === undefined ? {} : { mcp }),\n };\n}\n\nfunction parseMcpAllowlist(value: unknown, label: string): DomainMcpAllowlist {\n const mcp = requireRecord(value, label);\n assertOnlyKeys(mcp, ['servers', 'proxy'], label);\n return {\n ...(mcp.servers === undefined ? {} : { servers: parseStringArray(mcp.servers, `${label}.servers`) }),\n ...(mcp.proxy === undefined ? {} : { proxy: parseStringArray(mcp.proxy, `${label}.proxy`) }),\n };\n}\n\nfunction parseDomain(value: unknown, label: string): DomainDefinition {\n const domain = requireRecord(value, label);\n assertOnlyKeys(domain, ['description', 'plugins', 'mcp', 'sharedSkills'], label);\n const description = optionalString(domain.description, `${label}.description`);\n if (domain.plugins !== undefined && !Array.isArray(domain.plugins)) {\n throw new Error(`${label}.plugins must be an array`);\n }\n const sharedSkills = parseOptionalBoolean(domain.sharedSkills, `${label}.sharedSkills`);\n return {\n ...(description ? { description } : {}),\n ...(Array.isArray(domain.plugins)\n ? { plugins: domain.plugins.map((plugin, index) => parseDomainPlugin(plugin, `${label}.plugins[${index}]`)) }\n : {}),\n ...(domain.mcp === undefined ? {} : { mcp: parseMcpAllowlist(domain.mcp, `${label}.mcp`) }),\n ...(sharedSkills === undefined ? {} : { sharedSkills }),\n };\n}\n\nfunction parseAliases(value: unknown, label: string): Record<string, string[]> {\n if (value === undefined) return {};\n const aliases = requireRecord(value, label);\n return Object.fromEntries(\n Object.entries(aliases).map(([name, domains]) => [name, parseStringArray(domains, `${label}.${name}`)]),\n );\n}\n\n/**\n * Reads domains and plugin catalogs from global and repository configs.\n *\n * Named domains and explicit plugin entries are replaced by later repository\n * definitions. Configured roots accumulate, with exact marketplace manifests\n * deduplicated in discovery order. Explicit entries override discovered IDs.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<unknown>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n const domains: Record<string, ResolvedDomain> = {};\n let defaultDomains: string[] | undefined;\n\n for (const source of sources) {\n const document = requireRecord(source.document, source.filePath);\n assertOnlyKeys(document, ['plugins', 'domains', 'aliases', 'defaultDomains'], source.filePath);\n Object.assign(aliases, parseAliases(document.aliases, `aliases in ${source.filePath}`));\n if (document.domains !== undefined) {\n const sourceDomains = requireRecord(document.domains, `domains in ${source.filePath}`);\n for (const [name, definition] of Object.entries(sourceDomains)) {\n domains[name] = {\n ...parseDomain(definition, `domains.${name} in ${source.filePath}`),\n baseDirectory: source.baseDirectory,\n };\n }\n }\n if (Object.hasOwn(document, 'defaultDomains')) defaultDomains = parseDefaultDomains(document.defaultDomains);\n }\n\n const plugins = loadPluginCatalog(\n sources.map((source) => ({\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n value: requireRecord(source.document, source.filePath).plugins,\n })),\n repoRoot,\n homeDirectory,\n );\n\n if (defaultDomains) {\n for (const name of expandDomainNames({ plugins, domains, aliases }, defaultDomains)) {\n if (!Object.hasOwn(domains, name)) {\n throw new Error(`Unknown default domain \"${name}\" in ${DEFAULT_DOMAINS_PATH}`);\n }\n }\n }\n return { plugins, domains, aliases, ...(defaultDomains ? { defaultDomains } : {}) };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/**\n * Whether to include .claude/skills as shared fallbacks.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves named domain plugins while preserving each subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory: string = os.homedir(),\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n const homeDoomDirectory = globalDoomConfigDirectory(homeDirectory);\n\n for (const domainName of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[domainName];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${domainName}`);\n for (const selection of domain.plugins ?? []) {\n const isSubset = typeof selection !== 'string';\n const pluginName = isSubset ? selection.name : selection;\n const plugin = manifest.plugins.entries[pluginName];\n if (!plugin) throw new Error(`${UNKNOWN_PLUGIN_ERROR} \"${pluginName}\" referenced by domain \"${domainName}\"`);\n const directory = pluginDirectoryForSource(plugin.source, homeDoomDirectory);\n if (plugin.source.type === 'local' && (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory())) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: pluginName,\n directory,\n source: plugin.source,\n ...(plugin.manifest?.agentPluginSchema === SUPPORTED_AGENT_PLUGIN_SCHEMA\n ? { skillDiscovery: 'direct-children' as const }\n : {}),\n ...(isSubset && selection.skills ? { skills: selection.skills } : {}),\n ...(isSubset && selection.agents ? { agents: selection.agents } : {}),\n ...(isSubset && selection.hooks !== undefined ? { hooks: selection.hooks } : {}),\n ...(isSubset && selection.mcp !== undefined ? { mcp: selection.mcp } : {}),\n });\n }\n }\n\n for (const configuredDirectory of explicitDirectories) {\n const directory = path.resolve(configuredDirectory);\n if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: path.basename(directory),\n directory,\n source: { type: 'local', path: directory },\n });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n\nexport const DOOMPI_DOMAINS_ENV = 'DOOMPI_DOMAINS';\nexport const DEFAULT_DOMAIN = 'default';\nconst MARKETING_MAJOR_MODE = 'marketing';\n\nfunction parseDomainList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n}\n\n/**\n * Domains selected when the caller names none.\n *\n * Configuration keeps this axis independent of the major mode. The\n * major-mode-derived choice is retained only as the compatibility fallback for\n * domains files that declare no defaultDomains.\n */\nexport function defaultDomainsForMajorMode(\n majorMode: string,\n environment: NodeJS.ProcessEnv,\n defaultDomains?: readonly string[],\n): string[] {\n const inherited = environment[DOOMPI_DOMAINS_ENV];\n // An explicitly empty variable means no domains, so this tests for the key\n // rather than for a truthy value.\n if (inherited !== undefined) return parseDomainList(inherited);\n if (defaultDomains !== undefined) return [...defaultDomains];\n return parseDomainList(majorMode === MARKETING_MAJOR_MODE ? MARKETING_MAJOR_MODE : DEFAULT_DOMAIN);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"domains.mjs","names":[],"sources":["../../src/adapters/domains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { expandDomainNames } from '../services/domains.ts';\nimport type {\n DomainDefinition,\n DomainManifest,\n DomainMcpAllowlist,\n DomainPlugin,\n PluginEntry,\n ResolvedDomain,\n} from '../types/domains.ts';\nimport { globalDoomConfigDirectory } from './config.ts';\nimport { readDoomConfigSources } from './layeredConfig.ts';\nimport { loadPluginCatalog, pluginDirectoryForSource } from './pluginCatalog.ts';\n\nexport { DOOM_DIR } from './layeredConfig.ts';\n\nconst DOMAINS_FILE = 'domains.yaml';\nconst UNKNOWN_DOMAIN_ERROR = 'Unknown domain';\nconst UNKNOWN_PLUGIN_ERROR = 'Unknown plugin';\nconst MISSING_PLUGIN_DIRECTORY_ERROR = 'Plugin directory does not exist';\nconst DEFAULT_DOMAINS_PATH = '.doom/domains.yaml';\nconst SUPPORTED_AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\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 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 requireString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, label);\n}\n\nfunction parseStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value)) throw new Error(`${label} must be an array of non-empty strings`);\n return [...new Set(value.map((entry, index) => requireString(entry, `${label}[${index}]`)))];\n}\n\nfunction parseOptionalBoolean(value: unknown, label: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') throw new Error(`${label} must be a boolean`);\n return value;\n}\n\nfunction parseDefaultDomains(value: unknown): string[] {\n return parseStringArray(value, `defaultDomains in ${DEFAULT_DOMAINS_PATH}`);\n}\n\nfunction parseDomainPlugin(value: unknown, label: string): DomainPlugin {\n if (typeof value === 'string') return requireString(value, label);\n const plugin = requireRecord(value, label);\n assertOnlyKeys(plugin, ['name', 'skills', 'agents', 'hooks', 'mcp'], label);\n const skills = plugin.skills === undefined ? undefined : parseStringArray(plugin.skills, `${label}.skills`);\n const agents = plugin.agents === undefined ? undefined : parseStringArray(plugin.agents, `${label}.agents`);\n const hooks = parseOptionalBoolean(plugin.hooks, `${label}.hooks`);\n const mcp = parseOptionalBoolean(plugin.mcp, `${label}.mcp`);\n return {\n name: requireString(plugin.name, `${label}.name`),\n ...(skills ? { skills } : {}),\n ...(agents ? { agents } : {}),\n ...(hooks === undefined ? {} : { hooks }),\n ...(mcp === undefined ? {} : { mcp }),\n };\n}\n\nfunction parseMcpAllowlist(value: unknown, label: string): DomainMcpAllowlist {\n const mcp = requireRecord(value, label);\n assertOnlyKeys(mcp, ['servers', 'proxy'], label);\n return {\n ...(mcp.servers === undefined ? {} : { servers: parseStringArray(mcp.servers, `${label}.servers`) }),\n ...(mcp.proxy === undefined ? {} : { proxy: parseStringArray(mcp.proxy, `${label}.proxy`) }),\n };\n}\n\nfunction parseDomain(value: unknown, label: string): DomainDefinition {\n const domain = requireRecord(value, label);\n assertOnlyKeys(domain, ['description', 'plugins', 'mcp', 'sharedSkills'], label);\n const description = optionalString(domain.description, `${label}.description`);\n if (domain.plugins !== undefined && !Array.isArray(domain.plugins)) {\n throw new Error(`${label}.plugins must be an array`);\n }\n const sharedSkills = parseOptionalBoolean(domain.sharedSkills, `${label}.sharedSkills`);\n return {\n ...(description ? { description } : {}),\n ...(Array.isArray(domain.plugins)\n ? { plugins: domain.plugins.map((plugin, index) => parseDomainPlugin(plugin, `${label}.plugins[${index}]`)) }\n : {}),\n ...(domain.mcp === undefined ? {} : { mcp: parseMcpAllowlist(domain.mcp, `${label}.mcp`) }),\n ...(sharedSkills === undefined ? {} : { sharedSkills }),\n };\n}\n\nfunction parseAliases(value: unknown, label: string): Record<string, string[]> {\n if (value === undefined) return {};\n const aliases = requireRecord(value, label);\n return Object.fromEntries(\n Object.entries(aliases).map(([name, domains]) => [name, parseStringArray(domains, `${label}.${name}`)]),\n );\n}\n\n/**\n * Reads domains and plugin catalogs from global and repository configs.\n *\n * Named domains and explicit plugin entries are replaced by later repository\n * definitions. Configured roots accumulate, with exact marketplace manifests\n * deduplicated in discovery order. Explicit entries override discovered IDs.\n */\nexport function loadDomains(repoRoot: string, homeDirectory: string = os.homedir()): DomainManifest {\n const sources = readDoomConfigSources<unknown>(DOMAINS_FILE, repoRoot, homeDirectory);\n const aliases: Record<string, string[]> = {};\n const domains: Record<string, ResolvedDomain> = {};\n let defaultDomains: string[] | undefined;\n\n for (const source of sources) {\n const document = requireRecord(source.document, source.filePath);\n assertOnlyKeys(document, ['plugins', 'domains', 'aliases', 'defaultDomains'], source.filePath);\n Object.assign(aliases, parseAliases(document.aliases, `aliases in ${source.filePath}`));\n if (document.domains !== undefined) {\n const sourceDomains = requireRecord(document.domains, `domains in ${source.filePath}`);\n for (const [name, definition] of Object.entries(sourceDomains)) {\n domains[name] = {\n ...parseDomain(definition, `domains.${name} in ${source.filePath}`),\n baseDirectory: source.baseDirectory,\n };\n }\n }\n if (Object.hasOwn(document, 'defaultDomains')) defaultDomains = parseDefaultDomains(document.defaultDomains);\n }\n\n const plugins = loadPluginCatalog(\n sources.map((source) => ({\n filePath: source.filePath,\n baseDirectory: source.baseDirectory,\n value: requireRecord(source.document, source.filePath).plugins,\n })),\n repoRoot,\n homeDirectory,\n );\n\n if (defaultDomains) {\n for (const name of expandDomainNames({ plugins, domains, aliases }, defaultDomains)) {\n if (!Object.hasOwn(domains, name)) {\n throw new Error(`Unknown default domain \"${name}\" in ${DEFAULT_DOMAINS_PATH}`);\n }\n }\n }\n return { plugins, domains, aliases, ...(defaultDomains ? { defaultDomains } : {}) };\n}\n\nexport function listDomainNames(repoRoot: string, homeDirectory?: string): string[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n return [...new Set([...Object.keys(manifest.domains), ...Object.keys(manifest.aliases)])].sort();\n}\n\n/**\n * Whether to include .claude/skills as shared fallbacks.\n *\n * Shared skills are included unless every selected domain opts out, so mixing a\n * trimmed domain with an untrimmed one cannot strip the untrimmed one's skills.\n */\nexport function resolveSharedSkills(repoRoot: string, domainNames: string[], homeDirectory?: string): boolean {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const expanded = expandDomainNames(manifest, domainNames);\n if (expanded.length === 0) return true;\n return expanded.some((name) => manifest.domains[name]?.sharedSkills !== false);\n}\n\n/** Resolves named domain plugins while preserving each subset filter. */\nexport function resolvePluginEntries(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory: string = os.homedir(),\n): PluginEntry[] {\n const manifest = loadDomains(repoRoot, homeDirectory);\n const entries: PluginEntry[] = [];\n const seen = new Set<string>();\n const homeDoomDirectory = globalDoomConfigDirectory(homeDirectory);\n\n for (const domainName of expandDomainNames(manifest, domainNames)) {\n const domain = manifest.domains[domainName];\n if (!domain) throw new Error(`${UNKNOWN_DOMAIN_ERROR}: ${domainName}`);\n for (const selection of domain.plugins ?? []) {\n const isSubset = typeof selection !== 'string';\n const pluginName = isSubset ? selection.name : selection;\n const plugin = manifest.plugins.entries[pluginName];\n if (!plugin) throw new Error(`${UNKNOWN_PLUGIN_ERROR} \"${pluginName}\" referenced by domain \"${domainName}\"`);\n const directory = pluginDirectoryForSource(plugin.source, homeDoomDirectory);\n if (plugin.source.type === 'local' && (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory())) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: pluginName,\n directory,\n source: plugin.source,\n ...(plugin.manifest ? { manifest: plugin.manifest } : {}),\n ...(plugin.manifest?.agentPluginSchema === SUPPORTED_AGENT_PLUGIN_SCHEMA\n ? { skillDiscovery: 'direct-children' as const }\n : {}),\n ...(isSubset && selection.skills ? { skills: selection.skills } : {}),\n ...(isSubset && selection.agents ? { agents: selection.agents } : {}),\n ...(isSubset && selection.hooks !== undefined ? { hooks: selection.hooks } : {}),\n ...(isSubset && selection.mcp !== undefined ? { mcp: selection.mcp } : {}),\n });\n }\n }\n\n for (const configuredDirectory of explicitDirectories) {\n const directory = path.resolve(configuredDirectory);\n if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {\n throw new Error(`${MISSING_PLUGIN_DIRECTORY_ERROR}: ${directory}`);\n }\n if (seen.has(directory)) continue;\n seen.add(directory);\n entries.push({\n name: path.basename(directory),\n directory,\n source: { type: 'local', path: directory },\n });\n }\n return entries;\n}\n\nexport function resolvePluginDirectories(\n repoRoot: string,\n domainNames: string[],\n explicitDirectories: string[],\n homeDirectory?: string,\n): string[] {\n return resolvePluginEntries(repoRoot, domainNames, explicitDirectories, homeDirectory).map(\n (entry) => entry.directory,\n );\n}\n\nexport const DOOMPI_DOMAINS_ENV = 'DOOMPI_DOMAINS';\nexport const DEFAULT_DOMAIN = 'default';\nconst MARKETING_MAJOR_MODE = 'marketing';\n\nfunction parseDomainList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n}\n\n/**\n * Domains selected when the caller names none.\n *\n * Configuration keeps this axis independent of the major mode. The\n * major-mode-derived choice is retained only as the compatibility fallback for\n * domains files that declare no defaultDomains.\n */\nexport function defaultDomainsForMajorMode(\n majorMode: string,\n environment: NodeJS.ProcessEnv,\n defaultDomains?: readonly string[],\n): string[] {\n const inherited = environment[DOOMPI_DOMAINS_ENV];\n // An explicitly empty variable means no domains, so this tests for the key\n // rather than for a truthy value.\n if (inherited !== undefined) return parseDomainList(inherited);\n if (defaultDomains !== undefined) return [...defaultDomains];\n return parseDomainList(majorMode === MARKETING_MAJOR_MODE ? MARKETING_MAJOR_MODE : DEFAULT_DOMAIN);\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);const n=new Set([`profileEnvironment`,`pluginHooks`]),r={root:`DOOMPI_ROOT`,majorMode:`DOOMPI_MAJOR_MODE`,temporaryDirectory:`DOOMPI_TEMP_DIR`,domains:`DOOMPI_DOMAINS`,layers:`DOOMPI_LAYERS`,compositionFingerprint:`DOOMPI_COMPOSITION_FINGERPRINT`,profile:`DOOMPI_PROFILE`,profileEnvironment:`DOOMPI_PROFILE_ENV`,hookGroups:`DOOMPI_HOOK_GROUPS`,skillDirectories:`DOOMPI_SKILL_DIRS`,agentDirectories:`DOOMPI_AGENT_DIRS`,additionalDirectories:`DOOMPI_ADDITIONAL_DIRS`,childExtensions:`DOOMPI_CHILD_EXTENSIONS`,pluginDirectories:`DOOMPI_PLUGIN_DIRS`,pluginHooks:`DOOMPI_PLUGIN_HOOKS`,mcpConfigPath:`DOOMPI_MCP_CONFIG`,personaFile:`DOOMPI_PERSONA_FILE`,hooks:`DOOMPI_HOOKS_ENABLED`,agents:`DOOMPI_AGENTS_ENABLED`,mcp:`DOOMPI_MCP_ENABLED`,allowProtectedWrites:`DOOMPI_ALLOW_PROTECTED_WRITES`};function i(e){return e?.split(`,`).map(e=>e.trim()).filter(Boolean)??[]}function a(e){return e?.split(t.default.delimiter).map(e=>e.trim()).filter(Boolean)??[]}function o(e){return e!==`0`}function s(e,t,n){if(!e)return{};try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]==`string`))}catch(e){return n?.(t,e),{}}}function c(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}catch(e){return n?.(t,e),[]}}function l(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.pluginRoot==`string`&&typeof e.configPath==`string`):[]}catch(e){return n?.(t,e),[]}}function u(e=process.env,t){let n=r,u=e[n.hookGroups];return{root:e[n.root]||void 0,majorMode:e[n.majorMode]||`copilot`,temporaryDirectory:e[n.temporaryDirectory]||void 0,domains:i(e[n.domains]),layers:i(e[n.layers]),compositionFingerprint:e[n.compositionFingerprint]||void 0,profile:e[n.profile]||void 0,profileEnvironment:s(e[n.profileEnvironment],n.profileEnvironment,t),hookGroups:u===void 0?void 0:i(u),skillDirectories:a(e[n.skillDirectories]),agentDirectories:a(e[n.agentDirectories]),additionalDirectories:a(e[n.additionalDirectories]),childExtensions:c(e[n.childExtensions],n.childExtensions,t),pluginDirectories:a(e[n.pluginDirectories]),pluginHooks:l(e[n.pluginHooks],n.pluginHooks,t),mcpConfigPath:e[n.mcpConfigPath]||void 0,personaFile:e[n.personaFile]||void 0,hooks:o(e[n.hooks]),agents:o(e[n.agents]),mcp:o(e[n.mcp]),allowProtectedWrites:o(e[n.allowProtectedWrites])}}function d(e,n=process.env){let i=(e,t)=>{t===void 0?delete n[e]:n[e]=t},a=(e,t)=>i(e,t?`1`:`0`),o=r;return`root`in e&&i(o.root,e.root),`majorMode`in e&&i(o.majorMode,e.majorMode),`temporaryDirectory`in e&&i(o.temporaryDirectory,e.temporaryDirectory),`domains`in e&&i(o.domains,e.domains?.join(`,`)),`layers`in e&&i(o.layers,e.layers?.join(`,`)),`compositionFingerprint`in e&&i(o.compositionFingerprint,e.compositionFingerprint),`profile`in e&&i(o.profile,e.profile),`hookGroups`in e&&i(o.hookGroups,e.hookGroups?.join(`,`)),`skillDirectories`in e&&i(o.skillDirectories,e.skillDirectories?.join(t.default.delimiter)),`agentDirectories`in e&&i(o.agentDirectories,e.agentDirectories?.join(t.default.delimiter)),`additionalDirectories`in e&&i(o.additionalDirectories,e.additionalDirectories?.join(t.default.delimiter)),`childExtensions`in e&&i(o.childExtensions,JSON.stringify(e.childExtensions??[])),`pluginDirectories`in e&&i(o.pluginDirectories,e.pluginDirectories?.join(t.default.delimiter)),`mcpConfigPath`in e&&i(o.mcpConfigPath,e.mcpConfigPath),`personaFile`in e&&i(o.personaFile,e.personaFile),e.hooks!==void 0&&a(o.hooks,e.hooks),e.agents!==void 0&&a(o.agents,e.agents),e.mcp!==void 0&&a(o.mcp,e.mcp),e.allowProtectedWrites!==void 0&&a(o.allowProtectedWrites,e.allowProtectedWrites),n}exports.FILE_ONLY_STATE_FIELDS=n,exports.HARNESS_STATE_KEYS=r,exports.projectHarnessEnvironment=d,exports.readHarnessState=u;
1
+ const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);const n=new Set([`profileEnvironment`,`pluginHooks`,`mcpProjection`]),r={root:`DOOMPI_ROOT`,majorMode:`DOOMPI_MAJOR_MODE`,temporaryDirectory:`DOOMPI_TEMP_DIR`,domains:`DOOMPI_DOMAINS`,layers:`DOOMPI_LAYERS`,compositionFingerprint:`DOOMPI_COMPOSITION_FINGERPRINT`,profile:`DOOMPI_PROFILE`,profileEnvironment:`DOOMPI_PROFILE_ENV`,hookGroups:`DOOMPI_HOOK_GROUPS`,skillDirectories:`DOOMPI_SKILL_DIRS`,agentDirectories:`DOOMPI_AGENT_DIRS`,additionalDirectories:`DOOMPI_ADDITIONAL_DIRS`,childExtensions:`DOOMPI_CHILD_EXTENSIONS`,pluginDirectories:`DOOMPI_PLUGIN_DIRS`,pluginHooks:`DOOMPI_PLUGIN_HOOKS`,mcpConfigPath:`DOOMPI_MCP_CONFIG`,personaFile:`DOOMPI_PERSONA_FILE`,hooks:`DOOMPI_HOOKS_ENABLED`,agents:`DOOMPI_AGENTS_ENABLED`,mcp:`DOOMPI_MCP_ENABLED`,allowProtectedWrites:`DOOMPI_ALLOW_PROTECTED_WRITES`};function i(e){return e?.split(`,`).map(e=>e.trim()).filter(Boolean)??[]}function a(e){return e?.split(t.default.delimiter).map(e=>e.trim()).filter(Boolean)??[]}function o(e){return e!==`0`}function s(e,t,n){if(!e)return{};try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]==`string`))}catch(e){return n?.(t,e),{}}}function c(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}catch(e){return n?.(t,e),[]}}function l(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.pluginRoot==`string`&&typeof e.configPath==`string`):[]}catch(e){return n?.(t,e),[]}}function u(e=process.env,t){let n=r,u=e[n.hookGroups];return{root:e[n.root]||void 0,majorMode:e[n.majorMode]||`copilot`,temporaryDirectory:e[n.temporaryDirectory]||void 0,domains:i(e[n.domains]),layers:i(e[n.layers]),compositionFingerprint:e[n.compositionFingerprint]||void 0,profile:e[n.profile]||void 0,profileEnvironment:s(e[n.profileEnvironment],n.profileEnvironment,t),hookGroups:u===void 0?void 0:i(u),skillDirectories:a(e[n.skillDirectories]),agentDirectories:a(e[n.agentDirectories]),additionalDirectories:a(e[n.additionalDirectories]),childExtensions:c(e[n.childExtensions],n.childExtensions,t),pluginDirectories:a(e[n.pluginDirectories]),pluginHooks:l(e[n.pluginHooks],n.pluginHooks,t),mcpConfigPath:e[n.mcpConfigPath]||void 0,personaFile:e[n.personaFile]||void 0,hooks:o(e[n.hooks]),agents:o(e[n.agents]),mcp:o(e[n.mcp]),allowProtectedWrites:o(e[n.allowProtectedWrites])}}function d(e,n=process.env){let i=(e,t)=>{t===void 0?delete n[e]:n[e]=t},a=(e,t)=>i(e,t?`1`:`0`),o=r;return`root`in e&&i(o.root,e.root),`majorMode`in e&&i(o.majorMode,e.majorMode),`temporaryDirectory`in e&&i(o.temporaryDirectory,e.temporaryDirectory),`domains`in e&&i(o.domains,e.domains?.join(`,`)),`layers`in e&&i(o.layers,e.layers?.join(`,`)),`compositionFingerprint`in e&&i(o.compositionFingerprint,e.compositionFingerprint),`profile`in e&&i(o.profile,e.profile),`hookGroups`in e&&i(o.hookGroups,e.hookGroups?.join(`,`)),`skillDirectories`in e&&i(o.skillDirectories,e.skillDirectories?.join(t.default.delimiter)),`agentDirectories`in e&&i(o.agentDirectories,e.agentDirectories?.join(t.default.delimiter)),`additionalDirectories`in e&&i(o.additionalDirectories,e.additionalDirectories?.join(t.default.delimiter)),`childExtensions`in e&&i(o.childExtensions,JSON.stringify(e.childExtensions??[])),`pluginDirectories`in e&&i(o.pluginDirectories,e.pluginDirectories?.join(t.default.delimiter)),`mcpConfigPath`in e&&i(o.mcpConfigPath,e.mcpConfigPath),`personaFile`in e&&i(o.personaFile,e.personaFile),e.hooks!==void 0&&a(o.hooks,e.hooks),e.agents!==void 0&&a(o.agents,e.agents),e.mcp!==void 0&&a(o.mcp,e.mcp),e.allowProtectedWrites!==void 0&&a(o.allowProtectedWrites,e.allowProtectedWrites),n}exports.FILE_ONLY_STATE_FIELDS=n,exports.HARNESS_STATE_KEYS=r,exports.projectHarnessEnvironment=d,exports.readHarnessState=u;
2
2
  //# sourceMappingURL=harnessState.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"harnessState.cjs","names":["path"],"sources":["../../src/adapters/harnessState.ts"],"sourcesContent":["import path from 'node:path';\nimport type { HarnessState, PluginHookSource } from '../types/config.ts';\n\n/**\n * The codec between harness state and the environment.\n *\n * Decoding exists for processes that were started without a state file: a\n * nested run, a third-party spawn, or anything older than the store. Encoding\n * exists because bash hooks, the shell launchers, and packages that do not\n * depend on this one can only read an environment. Ownership, persistence and\n * mutation belong to harnessStore.ts; nothing here touches disk or holds state.\n */\n\nconst DEFAULT_MAJOR_MODE = 'copilot';\nconst DISABLED_FLAG = '0';\n\n/**\n * State that lives in the file only.\n *\n * Both are JSON documents that every spawned process and every hook would\n * otherwise copy in its environment, and neither has a reader outside this\n * package: the plugin hook list is consumed by the Pi hooks extension and the\n * profile environment by the profile switcher, both of which read the store.\n */\nexport const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState> = new Set(['profileEnvironment', 'pluginHooks']);\n\nexport type HarnessStateParseReporter = (key: string, error: unknown) => void;\n\nexport const HARNESS_STATE_KEYS = {\n root: 'DOOMPI_ROOT',\n majorMode: 'DOOMPI_MAJOR_MODE',\n temporaryDirectory: 'DOOMPI_TEMP_DIR',\n domains: 'DOOMPI_DOMAINS',\n layers: 'DOOMPI_LAYERS',\n compositionFingerprint: 'DOOMPI_COMPOSITION_FINGERPRINT',\n profile: 'DOOMPI_PROFILE',\n profileEnvironment: 'DOOMPI_PROFILE_ENV',\n hookGroups: 'DOOMPI_HOOK_GROUPS',\n skillDirectories: 'DOOMPI_SKILL_DIRS',\n agentDirectories: 'DOOMPI_AGENT_DIRS',\n additionalDirectories: 'DOOMPI_ADDITIONAL_DIRS',\n childExtensions: 'DOOMPI_CHILD_EXTENSIONS',\n pluginDirectories: 'DOOMPI_PLUGIN_DIRS',\n pluginHooks: 'DOOMPI_PLUGIN_HOOKS',\n mcpConfigPath: 'DOOMPI_MCP_CONFIG',\n personaFile: 'DOOMPI_PERSONA_FILE',\n hooks: 'DOOMPI_HOOKS_ENABLED',\n agents: 'DOOMPI_AGENTS_ENABLED',\n mcp: 'DOOMPI_MCP_ENABLED',\n allowProtectedWrites: 'DOOMPI_ALLOW_PROTECTED_WRITES',\n} as const;\n\nfunction splitCsv(value: string | undefined): string[] {\n return (\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction splitPaths(value: string | undefined): string[] {\n return (\n value\n ?.split(path.delimiter)\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction parseFlag(value: string | undefined): boolean {\n return value !== DISABLED_FLAG;\n}\n\nfunction parseStringRecord(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): Record<string, string> {\n if (!value) return {};\n try {\n const parsed = JSON.parse(value) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n return Object.fromEntries(\n Object.entries(parsed).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n } catch (error) {\n report?.(key, error);\n return {};\n }\n}\n\nfunction parseStringList(value: string | undefined, key: string, report?: HarnessStateParseReporter): string[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nfunction parsePluginHooks(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): PluginHookSource[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is PluginHookSource =>\n typeof item === 'object' &&\n item !== null &&\n typeof (item as PluginHookSource).pluginRoot === 'string' &&\n typeof (item as PluginHookSource).configPath === 'string',\n );\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nexport function readHarnessState(\n environment: NodeJS.ProcessEnv = process.env,\n report?: HarnessStateParseReporter,\n): HarnessState {\n const keys = HARNESS_STATE_KEYS;\n const hookGroups = environment[keys.hookGroups];\n return {\n root: environment[keys.root] || undefined,\n majorMode: environment[keys.majorMode] || DEFAULT_MAJOR_MODE,\n temporaryDirectory: environment[keys.temporaryDirectory] || undefined,\n domains: splitCsv(environment[keys.domains]),\n layers: splitCsv(environment[keys.layers]),\n compositionFingerprint: environment[keys.compositionFingerprint] || undefined,\n profile: environment[keys.profile] || undefined,\n profileEnvironment: parseStringRecord(environment[keys.profileEnvironment], keys.profileEnvironment, report),\n hookGroups: hookGroups === undefined ? undefined : splitCsv(hookGroups),\n skillDirectories: splitPaths(environment[keys.skillDirectories]),\n agentDirectories: splitPaths(environment[keys.agentDirectories]),\n additionalDirectories: splitPaths(environment[keys.additionalDirectories]),\n childExtensions: parseStringList(environment[keys.childExtensions], keys.childExtensions, report),\n pluginDirectories: splitPaths(environment[keys.pluginDirectories]),\n pluginHooks: parsePluginHooks(environment[keys.pluginHooks], keys.pluginHooks, report),\n mcpConfigPath: environment[keys.mcpConfigPath] || undefined,\n personaFile: environment[keys.personaFile] || undefined,\n hooks: parseFlag(environment[keys.hooks]),\n agents: parseFlag(environment[keys.agents]),\n mcp: parseFlag(environment[keys.mcp]),\n allowProtectedWrites: parseFlag(environment[keys.allowProtectedWrites]),\n };\n}\n\n/**\n * Publishes a state patch into an environment.\n *\n * Takes the environment rather than assuming `process.env`, because the\n * launcher builds a child environment and Doom Team builds a spawn snapshot;\n * neither should mutate its own process to describe another one.\n *\n * Fields in FILE_ONLY_FIELDS are skipped: the file carries them, and a reader\n * that needs them reads the store.\n */\nexport function projectHarnessEnvironment(\n patch: Partial<HarnessState>,\n environment: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const assign = (key: string, value: string | undefined): void => {\n if (value === undefined) delete environment[key];\n else environment[key] = value;\n };\n const assignFlag = (key: string, value: boolean): void => assign(key, value ? '1' : DISABLED_FLAG);\n const keys = HARNESS_STATE_KEYS;\n\n if ('root' in patch) assign(keys.root, patch.root);\n if ('majorMode' in patch) assign(keys.majorMode, patch.majorMode);\n if ('temporaryDirectory' in patch) assign(keys.temporaryDirectory, patch.temporaryDirectory);\n if ('domains' in patch) assign(keys.domains, patch.domains?.join(','));\n if ('layers' in patch) assign(keys.layers, patch.layers?.join(','));\n if ('compositionFingerprint' in patch) assign(keys.compositionFingerprint, patch.compositionFingerprint);\n if ('profile' in patch) assign(keys.profile, patch.profile);\n if ('hookGroups' in patch) assign(keys.hookGroups, patch.hookGroups?.join(','));\n if ('skillDirectories' in patch) assign(keys.skillDirectories, patch.skillDirectories?.join(path.delimiter));\n if ('agentDirectories' in patch) assign(keys.agentDirectories, patch.agentDirectories?.join(path.delimiter));\n if ('additionalDirectories' in patch) {\n assign(keys.additionalDirectories, patch.additionalDirectories?.join(path.delimiter));\n }\n if ('childExtensions' in patch) assign(keys.childExtensions, JSON.stringify(patch.childExtensions ?? []));\n if ('pluginDirectories' in patch) assign(keys.pluginDirectories, patch.pluginDirectories?.join(path.delimiter));\n if ('mcpConfigPath' in patch) assign(keys.mcpConfigPath, patch.mcpConfigPath);\n if ('personaFile' in patch) assign(keys.personaFile, patch.personaFile);\n if (patch.hooks !== undefined) assignFlag(keys.hooks, patch.hooks);\n if (patch.agents !== undefined) assignFlag(keys.agents, patch.agents);\n if (patch.mcp !== undefined) assignFlag(keys.mcp, patch.mcp);\n if (patch.allowProtectedWrites !== undefined) assignFlag(keys.allowProtectedWrites, patch.allowProtectedWrites);\n return environment;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"harnessState.cjs","names":["path"],"sources":["../../src/adapters/harnessState.ts"],"sourcesContent":["import path from 'node:path';\nimport type { HarnessState, PluginHookSource } from '../types/config.ts';\n\n/**\n * The codec between harness state and the environment.\n *\n * Decoding exists for processes that were started without a state file: a\n * nested run, a third-party spawn, or anything older than the store. Encoding\n * exists because bash hooks, the shell launchers, and packages that do not\n * depend on this one can only read an environment. Ownership, persistence and\n * mutation belong to harnessStore.ts; nothing here touches disk or holds state.\n */\n\nconst DEFAULT_MAJOR_MODE = 'copilot';\nconst DISABLED_FLAG = '0';\n\n/**\n * State that lives in the file only.\n *\n * These are JSON documents that every spawned process and every hook would\n * otherwise copy in its environment. The plugin hook list and profile defaults\n * are read from the store, while Config publishes the MCP projection through\n * the session-scoped Cordis registry.\n */\nexport const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState> = new Set([\n 'profileEnvironment',\n 'pluginHooks',\n 'mcpProjection',\n]);\n\nexport type HarnessStateParseReporter = (key: string, error: unknown) => void;\n\nexport const HARNESS_STATE_KEYS = {\n root: 'DOOMPI_ROOT',\n majorMode: 'DOOMPI_MAJOR_MODE',\n temporaryDirectory: 'DOOMPI_TEMP_DIR',\n domains: 'DOOMPI_DOMAINS',\n layers: 'DOOMPI_LAYERS',\n compositionFingerprint: 'DOOMPI_COMPOSITION_FINGERPRINT',\n profile: 'DOOMPI_PROFILE',\n profileEnvironment: 'DOOMPI_PROFILE_ENV',\n hookGroups: 'DOOMPI_HOOK_GROUPS',\n skillDirectories: 'DOOMPI_SKILL_DIRS',\n agentDirectories: 'DOOMPI_AGENT_DIRS',\n additionalDirectories: 'DOOMPI_ADDITIONAL_DIRS',\n childExtensions: 'DOOMPI_CHILD_EXTENSIONS',\n pluginDirectories: 'DOOMPI_PLUGIN_DIRS',\n pluginHooks: 'DOOMPI_PLUGIN_HOOKS',\n mcpConfigPath: 'DOOMPI_MCP_CONFIG',\n personaFile: 'DOOMPI_PERSONA_FILE',\n hooks: 'DOOMPI_HOOKS_ENABLED',\n agents: 'DOOMPI_AGENTS_ENABLED',\n mcp: 'DOOMPI_MCP_ENABLED',\n allowProtectedWrites: 'DOOMPI_ALLOW_PROTECTED_WRITES',\n} as const;\n\nfunction splitCsv(value: string | undefined): string[] {\n return (\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction splitPaths(value: string | undefined): string[] {\n return (\n value\n ?.split(path.delimiter)\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction parseFlag(value: string | undefined): boolean {\n return value !== DISABLED_FLAG;\n}\n\nfunction parseStringRecord(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): Record<string, string> {\n if (!value) return {};\n try {\n const parsed = JSON.parse(value) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n return Object.fromEntries(\n Object.entries(parsed).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n } catch (error) {\n report?.(key, error);\n return {};\n }\n}\n\nfunction parseStringList(value: string | undefined, key: string, report?: HarnessStateParseReporter): string[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nfunction parsePluginHooks(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): PluginHookSource[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is PluginHookSource =>\n typeof item === 'object' &&\n item !== null &&\n typeof (item as PluginHookSource).pluginRoot === 'string' &&\n typeof (item as PluginHookSource).configPath === 'string',\n );\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nexport function readHarnessState(\n environment: NodeJS.ProcessEnv = process.env,\n report?: HarnessStateParseReporter,\n): HarnessState {\n const keys = HARNESS_STATE_KEYS;\n const hookGroups = environment[keys.hookGroups];\n return {\n root: environment[keys.root] || undefined,\n majorMode: environment[keys.majorMode] || DEFAULT_MAJOR_MODE,\n temporaryDirectory: environment[keys.temporaryDirectory] || undefined,\n domains: splitCsv(environment[keys.domains]),\n layers: splitCsv(environment[keys.layers]),\n compositionFingerprint: environment[keys.compositionFingerprint] || undefined,\n profile: environment[keys.profile] || undefined,\n profileEnvironment: parseStringRecord(environment[keys.profileEnvironment], keys.profileEnvironment, report),\n hookGroups: hookGroups === undefined ? undefined : splitCsv(hookGroups),\n skillDirectories: splitPaths(environment[keys.skillDirectories]),\n agentDirectories: splitPaths(environment[keys.agentDirectories]),\n additionalDirectories: splitPaths(environment[keys.additionalDirectories]),\n childExtensions: parseStringList(environment[keys.childExtensions], keys.childExtensions, report),\n pluginDirectories: splitPaths(environment[keys.pluginDirectories]),\n pluginHooks: parsePluginHooks(environment[keys.pluginHooks], keys.pluginHooks, report),\n mcpConfigPath: environment[keys.mcpConfigPath] || undefined,\n personaFile: environment[keys.personaFile] || undefined,\n hooks: parseFlag(environment[keys.hooks]),\n agents: parseFlag(environment[keys.agents]),\n mcp: parseFlag(environment[keys.mcp]),\n allowProtectedWrites: parseFlag(environment[keys.allowProtectedWrites]),\n };\n}\n\n/**\n * Publishes a state patch into an environment.\n *\n * Takes the environment rather than assuming `process.env`, because the\n * launcher builds a child environment and Doom Team builds a spawn snapshot;\n * neither should mutate its own process to describe another one.\n *\n * Fields in FILE_ONLY_FIELDS are skipped: the file carries them, and a reader\n * that needs them reads the store.\n */\nexport function projectHarnessEnvironment(\n patch: Partial<HarnessState>,\n environment: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const assign = (key: string, value: string | undefined): void => {\n if (value === undefined) delete environment[key];\n else environment[key] = value;\n };\n const assignFlag = (key: string, value: boolean): void => assign(key, value ? '1' : DISABLED_FLAG);\n const keys = HARNESS_STATE_KEYS;\n\n if ('root' in patch) assign(keys.root, patch.root);\n if ('majorMode' in patch) assign(keys.majorMode, patch.majorMode);\n if ('temporaryDirectory' in patch) assign(keys.temporaryDirectory, patch.temporaryDirectory);\n if ('domains' in patch) assign(keys.domains, patch.domains?.join(','));\n if ('layers' in patch) assign(keys.layers, patch.layers?.join(','));\n if ('compositionFingerprint' in patch) assign(keys.compositionFingerprint, patch.compositionFingerprint);\n if ('profile' in patch) assign(keys.profile, patch.profile);\n if ('hookGroups' in patch) assign(keys.hookGroups, patch.hookGroups?.join(','));\n if ('skillDirectories' in patch) assign(keys.skillDirectories, patch.skillDirectories?.join(path.delimiter));\n if ('agentDirectories' in patch) assign(keys.agentDirectories, patch.agentDirectories?.join(path.delimiter));\n if ('additionalDirectories' in patch) {\n assign(keys.additionalDirectories, patch.additionalDirectories?.join(path.delimiter));\n }\n if ('childExtensions' in patch) assign(keys.childExtensions, JSON.stringify(patch.childExtensions ?? []));\n if ('pluginDirectories' in patch) assign(keys.pluginDirectories, patch.pluginDirectories?.join(path.delimiter));\n if ('mcpConfigPath' in patch) assign(keys.mcpConfigPath, patch.mcpConfigPath);\n if ('personaFile' in patch) assign(keys.personaFile, patch.personaFile);\n if (patch.hooks !== undefined) assignFlag(keys.hooks, patch.hooks);\n if (patch.agents !== undefined) assignFlag(keys.agents, patch.agents);\n if (patch.mcp !== undefined) assignFlag(keys.mcp, patch.mcp);\n if (patch.allowProtectedWrites !== undefined) assignFlag(keys.allowProtectedWrites, patch.allowProtectedWrites);\n return environment;\n}\n"],"mappings":"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"}
@@ -3,10 +3,10 @@ import { HarnessState } from "../types/config.cjs";
3
3
  /**
4
4
  * State that lives in the file only.
5
5
  *
6
- * Both are JSON documents that every spawned process and every hook would
7
- * otherwise copy in its environment, and neither has a reader outside this
8
- * package: the plugin hook list is consumed by the Pi hooks extension and the
9
- * profile environment by the profile switcher, both of which read the store.
6
+ * These are JSON documents that every spawned process and every hook would
7
+ * otherwise copy in its environment. The plugin hook list and profile defaults
8
+ * are read from the store, while Config publishes the MCP projection through
9
+ * the session-scoped Cordis registry.
10
10
  */
11
11
  declare const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState>;
12
12
  type HarnessStateParseReporter = (key: string, error: unknown) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"harnessState.d.cts","names":[],"sources":["../../src/adapters/harnessState.ts"],"mappings":";;;;;;;;;;cAwBa,wBAAwB,kBAAkB;KAE3C,6BAA6B,aAAa;cAEzC;;;;;;;;;;;;;;;;;;;;;;;iBAiGG,iBACd,cAAa,OAAO,YACpB,SAAS,4BACR;;;;;;;;;;;iBAsCa,0BACd,OAAO,QAAQ,eACf,cAAa,OAAO,aACnB,OAAO"}
1
+ {"version":3,"file":"harnessState.d.cts","names":[],"sources":["../../src/adapters/harnessState.ts"],"mappings":";;;;;;;;;;cAwBa,wBAAwB,kBAAkB;KAM3C,6BAA6B,aAAa;cAEzC;;;;;;;;;;;;;;;;;;;;;;;iBAiGG,iBACd,cAAa,OAAO,YACpB,SAAS,4BACR;;;;;;;;;;;iBAsCa,0BACd,OAAO,QAAQ,eACf,cAAa,OAAO,aACnB,OAAO"}
@@ -3,10 +3,10 @@ import { HarnessState } from "../types/config.mjs";
3
3
  /**
4
4
  * State that lives in the file only.
5
5
  *
6
- * Both are JSON documents that every spawned process and every hook would
7
- * otherwise copy in its environment, and neither has a reader outside this
8
- * package: the plugin hook list is consumed by the Pi hooks extension and the
9
- * profile environment by the profile switcher, both of which read the store.
6
+ * These are JSON documents that every spawned process and every hook would
7
+ * otherwise copy in its environment. The plugin hook list and profile defaults
8
+ * are read from the store, while Config publishes the MCP projection through
9
+ * the session-scoped Cordis registry.
10
10
  */
11
11
  declare const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState>;
12
12
  type HarnessStateParseReporter = (key: string, error: unknown) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"harnessState.d.mts","names":[],"sources":["../../src/adapters/harnessState.ts"],"mappings":";;;;;;;;;;cAwBa,wBAAwB,kBAAkB;KAE3C,6BAA6B,aAAa;cAEzC;;;;;;;;;;;;;;;;;;;;;;;iBAiGG,iBACd,cAAa,OAAO,YACpB,SAAS,4BACR;;;;;;;;;;;iBAsCa,0BACd,OAAO,QAAQ,eACf,cAAa,OAAO,aACnB,OAAO"}
1
+ {"version":3,"file":"harnessState.d.mts","names":[],"sources":["../../src/adapters/harnessState.ts"],"mappings":";;;;;;;;;;cAwBa,wBAAwB,kBAAkB;KAM3C,6BAA6B,aAAa;cAEzC;;;;;;;;;;;;;;;;;;;;;;;iBAiGG,iBACd,cAAa,OAAO,YACpB,SAAS,4BACR;;;;;;;;;;;iBAsCa,0BACd,OAAO,QAAQ,eACf,cAAa,OAAO,aACnB,OAAO"}
@@ -1,2 +1,2 @@
1
- import e from"node:path";const t=new Set([`profileEnvironment`,`pluginHooks`]),n={root:`DOOMPI_ROOT`,majorMode:`DOOMPI_MAJOR_MODE`,temporaryDirectory:`DOOMPI_TEMP_DIR`,domains:`DOOMPI_DOMAINS`,layers:`DOOMPI_LAYERS`,compositionFingerprint:`DOOMPI_COMPOSITION_FINGERPRINT`,profile:`DOOMPI_PROFILE`,profileEnvironment:`DOOMPI_PROFILE_ENV`,hookGroups:`DOOMPI_HOOK_GROUPS`,skillDirectories:`DOOMPI_SKILL_DIRS`,agentDirectories:`DOOMPI_AGENT_DIRS`,additionalDirectories:`DOOMPI_ADDITIONAL_DIRS`,childExtensions:`DOOMPI_CHILD_EXTENSIONS`,pluginDirectories:`DOOMPI_PLUGIN_DIRS`,pluginHooks:`DOOMPI_PLUGIN_HOOKS`,mcpConfigPath:`DOOMPI_MCP_CONFIG`,personaFile:`DOOMPI_PERSONA_FILE`,hooks:`DOOMPI_HOOKS_ENABLED`,agents:`DOOMPI_AGENTS_ENABLED`,mcp:`DOOMPI_MCP_ENABLED`,allowProtectedWrites:`DOOMPI_ALLOW_PROTECTED_WRITES`};function r(e){return e?.split(`,`).map(e=>e.trim()).filter(Boolean)??[]}function i(t){return t?.split(e.delimiter).map(e=>e.trim()).filter(Boolean)??[]}function a(e){return e!==`0`}function o(e,t,n){if(!e)return{};try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]==`string`))}catch(e){return n?.(t,e),{}}}function s(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}catch(e){return n?.(t,e),[]}}function c(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.pluginRoot==`string`&&typeof e.configPath==`string`):[]}catch(e){return n?.(t,e),[]}}function l(e=process.env,t){let l=n,u=e[l.hookGroups];return{root:e[l.root]||void 0,majorMode:e[l.majorMode]||`copilot`,temporaryDirectory:e[l.temporaryDirectory]||void 0,domains:r(e[l.domains]),layers:r(e[l.layers]),compositionFingerprint:e[l.compositionFingerprint]||void 0,profile:e[l.profile]||void 0,profileEnvironment:o(e[l.profileEnvironment],l.profileEnvironment,t),hookGroups:u===void 0?void 0:r(u),skillDirectories:i(e[l.skillDirectories]),agentDirectories:i(e[l.agentDirectories]),additionalDirectories:i(e[l.additionalDirectories]),childExtensions:s(e[l.childExtensions],l.childExtensions,t),pluginDirectories:i(e[l.pluginDirectories]),pluginHooks:c(e[l.pluginHooks],l.pluginHooks,t),mcpConfigPath:e[l.mcpConfigPath]||void 0,personaFile:e[l.personaFile]||void 0,hooks:a(e[l.hooks]),agents:a(e[l.agents]),mcp:a(e[l.mcp]),allowProtectedWrites:a(e[l.allowProtectedWrites])}}function u(t,r=process.env){let i=(e,t)=>{t===void 0?delete r[e]:r[e]=t},a=(e,t)=>i(e,t?`1`:`0`),o=n;return`root`in t&&i(o.root,t.root),`majorMode`in t&&i(o.majorMode,t.majorMode),`temporaryDirectory`in t&&i(o.temporaryDirectory,t.temporaryDirectory),`domains`in t&&i(o.domains,t.domains?.join(`,`)),`layers`in t&&i(o.layers,t.layers?.join(`,`)),`compositionFingerprint`in t&&i(o.compositionFingerprint,t.compositionFingerprint),`profile`in t&&i(o.profile,t.profile),`hookGroups`in t&&i(o.hookGroups,t.hookGroups?.join(`,`)),`skillDirectories`in t&&i(o.skillDirectories,t.skillDirectories?.join(e.delimiter)),`agentDirectories`in t&&i(o.agentDirectories,t.agentDirectories?.join(e.delimiter)),`additionalDirectories`in t&&i(o.additionalDirectories,t.additionalDirectories?.join(e.delimiter)),`childExtensions`in t&&i(o.childExtensions,JSON.stringify(t.childExtensions??[])),`pluginDirectories`in t&&i(o.pluginDirectories,t.pluginDirectories?.join(e.delimiter)),`mcpConfigPath`in t&&i(o.mcpConfigPath,t.mcpConfigPath),`personaFile`in t&&i(o.personaFile,t.personaFile),t.hooks!==void 0&&a(o.hooks,t.hooks),t.agents!==void 0&&a(o.agents,t.agents),t.mcp!==void 0&&a(o.mcp,t.mcp),t.allowProtectedWrites!==void 0&&a(o.allowProtectedWrites,t.allowProtectedWrites),r}export{t as FILE_ONLY_STATE_FIELDS,n as HARNESS_STATE_KEYS,u as projectHarnessEnvironment,l as readHarnessState};
1
+ import e from"node:path";const t=new Set([`profileEnvironment`,`pluginHooks`,`mcpProjection`]),n={root:`DOOMPI_ROOT`,majorMode:`DOOMPI_MAJOR_MODE`,temporaryDirectory:`DOOMPI_TEMP_DIR`,domains:`DOOMPI_DOMAINS`,layers:`DOOMPI_LAYERS`,compositionFingerprint:`DOOMPI_COMPOSITION_FINGERPRINT`,profile:`DOOMPI_PROFILE`,profileEnvironment:`DOOMPI_PROFILE_ENV`,hookGroups:`DOOMPI_HOOK_GROUPS`,skillDirectories:`DOOMPI_SKILL_DIRS`,agentDirectories:`DOOMPI_AGENT_DIRS`,additionalDirectories:`DOOMPI_ADDITIONAL_DIRS`,childExtensions:`DOOMPI_CHILD_EXTENSIONS`,pluginDirectories:`DOOMPI_PLUGIN_DIRS`,pluginHooks:`DOOMPI_PLUGIN_HOOKS`,mcpConfigPath:`DOOMPI_MCP_CONFIG`,personaFile:`DOOMPI_PERSONA_FILE`,hooks:`DOOMPI_HOOKS_ENABLED`,agents:`DOOMPI_AGENTS_ENABLED`,mcp:`DOOMPI_MCP_ENABLED`,allowProtectedWrites:`DOOMPI_ALLOW_PROTECTED_WRITES`};function r(e){return e?.split(`,`).map(e=>e.trim()).filter(Boolean)??[]}function i(t){return t?.split(e.delimiter).map(e=>e.trim()).filter(Boolean)??[]}function a(e){return e!==`0`}function o(e,t,n){if(!e)return{};try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]==`string`))}catch(e){return n?.(t,e),{}}}function s(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}catch(e){return n?.(t,e),[]}}function c(e,t,n){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.pluginRoot==`string`&&typeof e.configPath==`string`):[]}catch(e){return n?.(t,e),[]}}function l(e=process.env,t){let l=n,u=e[l.hookGroups];return{root:e[l.root]||void 0,majorMode:e[l.majorMode]||`copilot`,temporaryDirectory:e[l.temporaryDirectory]||void 0,domains:r(e[l.domains]),layers:r(e[l.layers]),compositionFingerprint:e[l.compositionFingerprint]||void 0,profile:e[l.profile]||void 0,profileEnvironment:o(e[l.profileEnvironment],l.profileEnvironment,t),hookGroups:u===void 0?void 0:r(u),skillDirectories:i(e[l.skillDirectories]),agentDirectories:i(e[l.agentDirectories]),additionalDirectories:i(e[l.additionalDirectories]),childExtensions:s(e[l.childExtensions],l.childExtensions,t),pluginDirectories:i(e[l.pluginDirectories]),pluginHooks:c(e[l.pluginHooks],l.pluginHooks,t),mcpConfigPath:e[l.mcpConfigPath]||void 0,personaFile:e[l.personaFile]||void 0,hooks:a(e[l.hooks]),agents:a(e[l.agents]),mcp:a(e[l.mcp]),allowProtectedWrites:a(e[l.allowProtectedWrites])}}function u(t,r=process.env){let i=(e,t)=>{t===void 0?delete r[e]:r[e]=t},a=(e,t)=>i(e,t?`1`:`0`),o=n;return`root`in t&&i(o.root,t.root),`majorMode`in t&&i(o.majorMode,t.majorMode),`temporaryDirectory`in t&&i(o.temporaryDirectory,t.temporaryDirectory),`domains`in t&&i(o.domains,t.domains?.join(`,`)),`layers`in t&&i(o.layers,t.layers?.join(`,`)),`compositionFingerprint`in t&&i(o.compositionFingerprint,t.compositionFingerprint),`profile`in t&&i(o.profile,t.profile),`hookGroups`in t&&i(o.hookGroups,t.hookGroups?.join(`,`)),`skillDirectories`in t&&i(o.skillDirectories,t.skillDirectories?.join(e.delimiter)),`agentDirectories`in t&&i(o.agentDirectories,t.agentDirectories?.join(e.delimiter)),`additionalDirectories`in t&&i(o.additionalDirectories,t.additionalDirectories?.join(e.delimiter)),`childExtensions`in t&&i(o.childExtensions,JSON.stringify(t.childExtensions??[])),`pluginDirectories`in t&&i(o.pluginDirectories,t.pluginDirectories?.join(e.delimiter)),`mcpConfigPath`in t&&i(o.mcpConfigPath,t.mcpConfigPath),`personaFile`in t&&i(o.personaFile,t.personaFile),t.hooks!==void 0&&a(o.hooks,t.hooks),t.agents!==void 0&&a(o.agents,t.agents),t.mcp!==void 0&&a(o.mcp,t.mcp),t.allowProtectedWrites!==void 0&&a(o.allowProtectedWrites,t.allowProtectedWrites),r}export{t as FILE_ONLY_STATE_FIELDS,n as HARNESS_STATE_KEYS,u as projectHarnessEnvironment,l as readHarnessState};
2
2
  //# sourceMappingURL=harnessState.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"harnessState.mjs","names":[],"sources":["../../src/adapters/harnessState.ts"],"sourcesContent":["import path from 'node:path';\nimport type { HarnessState, PluginHookSource } from '../types/config.ts';\n\n/**\n * The codec between harness state and the environment.\n *\n * Decoding exists for processes that were started without a state file: a\n * nested run, a third-party spawn, or anything older than the store. Encoding\n * exists because bash hooks, the shell launchers, and packages that do not\n * depend on this one can only read an environment. Ownership, persistence and\n * mutation belong to harnessStore.ts; nothing here touches disk or holds state.\n */\n\nconst DEFAULT_MAJOR_MODE = 'copilot';\nconst DISABLED_FLAG = '0';\n\n/**\n * State that lives in the file only.\n *\n * Both are JSON documents that every spawned process and every hook would\n * otherwise copy in its environment, and neither has a reader outside this\n * package: the plugin hook list is consumed by the Pi hooks extension and the\n * profile environment by the profile switcher, both of which read the store.\n */\nexport const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState> = new Set(['profileEnvironment', 'pluginHooks']);\n\nexport type HarnessStateParseReporter = (key: string, error: unknown) => void;\n\nexport const HARNESS_STATE_KEYS = {\n root: 'DOOMPI_ROOT',\n majorMode: 'DOOMPI_MAJOR_MODE',\n temporaryDirectory: 'DOOMPI_TEMP_DIR',\n domains: 'DOOMPI_DOMAINS',\n layers: 'DOOMPI_LAYERS',\n compositionFingerprint: 'DOOMPI_COMPOSITION_FINGERPRINT',\n profile: 'DOOMPI_PROFILE',\n profileEnvironment: 'DOOMPI_PROFILE_ENV',\n hookGroups: 'DOOMPI_HOOK_GROUPS',\n skillDirectories: 'DOOMPI_SKILL_DIRS',\n agentDirectories: 'DOOMPI_AGENT_DIRS',\n additionalDirectories: 'DOOMPI_ADDITIONAL_DIRS',\n childExtensions: 'DOOMPI_CHILD_EXTENSIONS',\n pluginDirectories: 'DOOMPI_PLUGIN_DIRS',\n pluginHooks: 'DOOMPI_PLUGIN_HOOKS',\n mcpConfigPath: 'DOOMPI_MCP_CONFIG',\n personaFile: 'DOOMPI_PERSONA_FILE',\n hooks: 'DOOMPI_HOOKS_ENABLED',\n agents: 'DOOMPI_AGENTS_ENABLED',\n mcp: 'DOOMPI_MCP_ENABLED',\n allowProtectedWrites: 'DOOMPI_ALLOW_PROTECTED_WRITES',\n} as const;\n\nfunction splitCsv(value: string | undefined): string[] {\n return (\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction splitPaths(value: string | undefined): string[] {\n return (\n value\n ?.split(path.delimiter)\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction parseFlag(value: string | undefined): boolean {\n return value !== DISABLED_FLAG;\n}\n\nfunction parseStringRecord(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): Record<string, string> {\n if (!value) return {};\n try {\n const parsed = JSON.parse(value) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n return Object.fromEntries(\n Object.entries(parsed).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n } catch (error) {\n report?.(key, error);\n return {};\n }\n}\n\nfunction parseStringList(value: string | undefined, key: string, report?: HarnessStateParseReporter): string[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nfunction parsePluginHooks(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): PluginHookSource[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is PluginHookSource =>\n typeof item === 'object' &&\n item !== null &&\n typeof (item as PluginHookSource).pluginRoot === 'string' &&\n typeof (item as PluginHookSource).configPath === 'string',\n );\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nexport function readHarnessState(\n environment: NodeJS.ProcessEnv = process.env,\n report?: HarnessStateParseReporter,\n): HarnessState {\n const keys = HARNESS_STATE_KEYS;\n const hookGroups = environment[keys.hookGroups];\n return {\n root: environment[keys.root] || undefined,\n majorMode: environment[keys.majorMode] || DEFAULT_MAJOR_MODE,\n temporaryDirectory: environment[keys.temporaryDirectory] || undefined,\n domains: splitCsv(environment[keys.domains]),\n layers: splitCsv(environment[keys.layers]),\n compositionFingerprint: environment[keys.compositionFingerprint] || undefined,\n profile: environment[keys.profile] || undefined,\n profileEnvironment: parseStringRecord(environment[keys.profileEnvironment], keys.profileEnvironment, report),\n hookGroups: hookGroups === undefined ? undefined : splitCsv(hookGroups),\n skillDirectories: splitPaths(environment[keys.skillDirectories]),\n agentDirectories: splitPaths(environment[keys.agentDirectories]),\n additionalDirectories: splitPaths(environment[keys.additionalDirectories]),\n childExtensions: parseStringList(environment[keys.childExtensions], keys.childExtensions, report),\n pluginDirectories: splitPaths(environment[keys.pluginDirectories]),\n pluginHooks: parsePluginHooks(environment[keys.pluginHooks], keys.pluginHooks, report),\n mcpConfigPath: environment[keys.mcpConfigPath] || undefined,\n personaFile: environment[keys.personaFile] || undefined,\n hooks: parseFlag(environment[keys.hooks]),\n agents: parseFlag(environment[keys.agents]),\n mcp: parseFlag(environment[keys.mcp]),\n allowProtectedWrites: parseFlag(environment[keys.allowProtectedWrites]),\n };\n}\n\n/**\n * Publishes a state patch into an environment.\n *\n * Takes the environment rather than assuming `process.env`, because the\n * launcher builds a child environment and Doom Team builds a spawn snapshot;\n * neither should mutate its own process to describe another one.\n *\n * Fields in FILE_ONLY_FIELDS are skipped: the file carries them, and a reader\n * that needs them reads the store.\n */\nexport function projectHarnessEnvironment(\n patch: Partial<HarnessState>,\n environment: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const assign = (key: string, value: string | undefined): void => {\n if (value === undefined) delete environment[key];\n else environment[key] = value;\n };\n const assignFlag = (key: string, value: boolean): void => assign(key, value ? '1' : DISABLED_FLAG);\n const keys = HARNESS_STATE_KEYS;\n\n if ('root' in patch) assign(keys.root, patch.root);\n if ('majorMode' in patch) assign(keys.majorMode, patch.majorMode);\n if ('temporaryDirectory' in patch) assign(keys.temporaryDirectory, patch.temporaryDirectory);\n if ('domains' in patch) assign(keys.domains, patch.domains?.join(','));\n if ('layers' in patch) assign(keys.layers, patch.layers?.join(','));\n if ('compositionFingerprint' in patch) assign(keys.compositionFingerprint, patch.compositionFingerprint);\n if ('profile' in patch) assign(keys.profile, patch.profile);\n if ('hookGroups' in patch) assign(keys.hookGroups, patch.hookGroups?.join(','));\n if ('skillDirectories' in patch) assign(keys.skillDirectories, patch.skillDirectories?.join(path.delimiter));\n if ('agentDirectories' in patch) assign(keys.agentDirectories, patch.agentDirectories?.join(path.delimiter));\n if ('additionalDirectories' in patch) {\n assign(keys.additionalDirectories, patch.additionalDirectories?.join(path.delimiter));\n }\n if ('childExtensions' in patch) assign(keys.childExtensions, JSON.stringify(patch.childExtensions ?? []));\n if ('pluginDirectories' in patch) assign(keys.pluginDirectories, patch.pluginDirectories?.join(path.delimiter));\n if ('mcpConfigPath' in patch) assign(keys.mcpConfigPath, patch.mcpConfigPath);\n if ('personaFile' in patch) assign(keys.personaFile, patch.personaFile);\n if (patch.hooks !== undefined) assignFlag(keys.hooks, patch.hooks);\n if (patch.agents !== undefined) assignFlag(keys.agents, patch.agents);\n if (patch.mcp !== undefined) assignFlag(keys.mcp, patch.mcp);\n if (patch.allowProtectedWrites !== undefined) assignFlag(keys.allowProtectedWrites, patch.allowProtectedWrites);\n return environment;\n}\n"],"mappings":"yBAaA,MAWa,EAA0D,IAAI,IAAI,CAAC,qBAAsB,aAAa,CAAC,EAIvG,EAAqB,CAChC,KAAM,cACN,UAAW,oBACX,mBAAoB,kBACpB,QAAS,iBACT,OAAQ,gBACR,uBAAwB,iCACxB,QAAS,iBACT,mBAAoB,qBACpB,WAAY,qBACZ,iBAAkB,oBAClB,iBAAkB,oBAClB,sBAAuB,yBACvB,gBAAiB,0BACjB,kBAAmB,qBACnB,YAAa,sBACb,cAAe,oBACf,YAAa,sBACb,MAAO,uBACP,OAAQ,wBACR,IAAK,qBACL,qBAAsB,+BACxB,EAEA,SAAS,EAAS,EAAqC,CACrD,OACE,GACI,MAAM,GAAG,CAAC,CACX,IAAK,GAAS,EAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,GAAK,CAAC,CAE3B,CAEA,SAAS,EAAW,EAAqC,CACvD,OACE,GACI,MAAM,EAAK,SAAS,CAAC,CACtB,IAAK,GAAS,EAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,GAAK,CAAC,CAE3B,CAEA,SAAS,EAAU,EAAoC,CACrD,OAAO,IAAU,GACnB,CAEA,SAAS,EACP,EACA,EACA,EACwB,CACxB,GAAI,CAAC,EAAO,MAAO,CAAC,EACpB,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,CAAK,EAE/B,OADI,OAAO,GAAW,WAAY,GAAmB,MAAM,QAAQ,CAAM,EAAU,CAAC,EAC7E,OAAO,YACZ,OAAO,QAAQ,CAAM,CAAC,CAAC,OAAQ,GAAqC,OAAO,EAAM,IAAO,QAAQ,CAClG,CACF,OAAS,EAAO,CAEd,OADA,IAAS,EAAK,CAAK,EACZ,CAAC,CACV,CACF,CAEA,SAAS,EAAgB,EAA2B,EAAa,EAA8C,CAC7G,GAAI,CAAC,EAAO,MAAO,CAAC,EACpB,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,CAAK,EAC/B,OAAO,MAAM,QAAQ,CAAM,EAAI,EAAO,OAAQ,GAAyB,OAAO,GAAS,QAAQ,EAAI,CAAC,CACtG,OAAS,EAAO,CAEd,OADA,IAAS,EAAK,CAAK,EACZ,CAAC,CACV,CACF,CAEA,SAAS,EACP,EACA,EACA,EACoB,CACpB,GAAI,CAAC,EAAO,MAAO,CAAC,EACpB,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,CAAK,EAE/B,OADK,MAAM,QAAQ,CAAM,EAClB,EAAO,OACX,GACC,OAAO,GAAS,YAChB,GACA,OAAQ,EAA0B,YAAe,UACjD,OAAQ,EAA0B,YAAe,QACrD,EAPmC,CAAC,CAQtC,OAAS,EAAO,CAEd,OADA,IAAS,EAAK,CAAK,EACZ,CAAC,CACV,CACF,CAEA,SAAgB,EACd,EAAiC,QAAQ,IACzC,EACc,CACd,IAAM,EAAO,EACP,EAAa,EAAY,EAAK,YACpC,MAAO,CACL,KAAM,EAAY,EAAK,OAAS,IAAA,GAChC,UAAW,EAAY,EAAK,YAAc,UAC1C,mBAAoB,EAAY,EAAK,qBAAuB,IAAA,GAC5D,QAAS,EAAS,EAAY,EAAK,QAAQ,EAC3C,OAAQ,EAAS,EAAY,EAAK,OAAO,EACzC,uBAAwB,EAAY,EAAK,yBAA2B,IAAA,GACpE,QAAS,EAAY,EAAK,UAAY,IAAA,GACtC,mBAAoB,EAAkB,EAAY,EAAK,oBAAqB,EAAK,mBAAoB,CAAM,EAC3G,WAAY,IAAe,IAAA,GAAY,IAAA,GAAY,EAAS,CAAU,EACtE,iBAAkB,EAAW,EAAY,EAAK,iBAAiB,EAC/D,iBAAkB,EAAW,EAAY,EAAK,iBAAiB,EAC/D,sBAAuB,EAAW,EAAY,EAAK,sBAAsB,EACzE,gBAAiB,EAAgB,EAAY,EAAK,iBAAkB,EAAK,gBAAiB,CAAM,EAChG,kBAAmB,EAAW,EAAY,EAAK,kBAAkB,EACjE,YAAa,EAAiB,EAAY,EAAK,aAAc,EAAK,YAAa,CAAM,EACrF,cAAe,EAAY,EAAK,gBAAkB,IAAA,GAClD,YAAa,EAAY,EAAK,cAAgB,IAAA,GAC9C,MAAO,EAAU,EAAY,EAAK,MAAM,EACxC,OAAQ,EAAU,EAAY,EAAK,OAAO,EAC1C,IAAK,EAAU,EAAY,EAAK,IAAI,EACpC,qBAAsB,EAAU,EAAY,EAAK,qBAAqB,CACxE,CACF,CAYA,SAAgB,EACd,EACA,EAAiC,QAAQ,IACtB,CACnB,IAAM,GAAU,EAAa,IAAoC,CAC3D,IAAU,IAAA,GAAW,OAAO,EAAY,GACvC,EAAY,GAAO,CAC1B,EACM,GAAc,EAAa,IAAyB,EAAO,EAAK,EAAQ,IAAM,GAAa,EAC3F,EAAO,EAuBb,MArBI,SAAU,GAAO,EAAO,EAAK,KAAM,EAAM,IAAI,EAC7C,cAAe,GAAO,EAAO,EAAK,UAAW,EAAM,SAAS,EAC5D,uBAAwB,GAAO,EAAO,EAAK,mBAAoB,EAAM,kBAAkB,EACvF,YAAa,GAAO,EAAO,EAAK,QAAS,EAAM,SAAS,KAAK,GAAG,CAAC,EACjE,WAAY,GAAO,EAAO,EAAK,OAAQ,EAAM,QAAQ,KAAK,GAAG,CAAC,EAC9D,2BAA4B,GAAO,EAAO,EAAK,uBAAwB,EAAM,sBAAsB,EACnG,YAAa,GAAO,EAAO,EAAK,QAAS,EAAM,OAAO,EACtD,eAAgB,GAAO,EAAO,EAAK,WAAY,EAAM,YAAY,KAAK,GAAG,CAAC,EAC1E,qBAAsB,GAAO,EAAO,EAAK,iBAAkB,EAAM,kBAAkB,KAAK,EAAK,SAAS,CAAC,EACvG,qBAAsB,GAAO,EAAO,EAAK,iBAAkB,EAAM,kBAAkB,KAAK,EAAK,SAAS,CAAC,EACvG,0BAA2B,GAC7B,EAAO,EAAK,sBAAuB,EAAM,uBAAuB,KAAK,EAAK,SAAS,CAAC,EAElF,oBAAqB,GAAO,EAAO,EAAK,gBAAiB,KAAK,UAAU,EAAM,iBAAmB,CAAC,CAAC,CAAC,EACpG,sBAAuB,GAAO,EAAO,EAAK,kBAAmB,EAAM,mBAAmB,KAAK,EAAK,SAAS,CAAC,EAC1G,kBAAmB,GAAO,EAAO,EAAK,cAAe,EAAM,aAAa,EACxE,gBAAiB,GAAO,EAAO,EAAK,YAAa,EAAM,WAAW,EAClE,EAAM,QAAU,IAAA,IAAW,EAAW,EAAK,MAAO,EAAM,KAAK,EAC7D,EAAM,SAAW,IAAA,IAAW,EAAW,EAAK,OAAQ,EAAM,MAAM,EAChE,EAAM,MAAQ,IAAA,IAAW,EAAW,EAAK,IAAK,EAAM,GAAG,EACvD,EAAM,uBAAyB,IAAA,IAAW,EAAW,EAAK,qBAAsB,EAAM,oBAAoB,EACvG,CACT"}
1
+ {"version":3,"file":"harnessState.mjs","names":[],"sources":["../../src/adapters/harnessState.ts"],"sourcesContent":["import path from 'node:path';\nimport type { HarnessState, PluginHookSource } from '../types/config.ts';\n\n/**\n * The codec between harness state and the environment.\n *\n * Decoding exists for processes that were started without a state file: a\n * nested run, a third-party spawn, or anything older than the store. Encoding\n * exists because bash hooks, the shell launchers, and packages that do not\n * depend on this one can only read an environment. Ownership, persistence and\n * mutation belong to harnessStore.ts; nothing here touches disk or holds state.\n */\n\nconst DEFAULT_MAJOR_MODE = 'copilot';\nconst DISABLED_FLAG = '0';\n\n/**\n * State that lives in the file only.\n *\n * These are JSON documents that every spawned process and every hook would\n * otherwise copy in its environment. The plugin hook list and profile defaults\n * are read from the store, while Config publishes the MCP projection through\n * the session-scoped Cordis registry.\n */\nexport const FILE_ONLY_STATE_FIELDS: ReadonlySet<keyof HarnessState> = new Set([\n 'profileEnvironment',\n 'pluginHooks',\n 'mcpProjection',\n]);\n\nexport type HarnessStateParseReporter = (key: string, error: unknown) => void;\n\nexport const HARNESS_STATE_KEYS = {\n root: 'DOOMPI_ROOT',\n majorMode: 'DOOMPI_MAJOR_MODE',\n temporaryDirectory: 'DOOMPI_TEMP_DIR',\n domains: 'DOOMPI_DOMAINS',\n layers: 'DOOMPI_LAYERS',\n compositionFingerprint: 'DOOMPI_COMPOSITION_FINGERPRINT',\n profile: 'DOOMPI_PROFILE',\n profileEnvironment: 'DOOMPI_PROFILE_ENV',\n hookGroups: 'DOOMPI_HOOK_GROUPS',\n skillDirectories: 'DOOMPI_SKILL_DIRS',\n agentDirectories: 'DOOMPI_AGENT_DIRS',\n additionalDirectories: 'DOOMPI_ADDITIONAL_DIRS',\n childExtensions: 'DOOMPI_CHILD_EXTENSIONS',\n pluginDirectories: 'DOOMPI_PLUGIN_DIRS',\n pluginHooks: 'DOOMPI_PLUGIN_HOOKS',\n mcpConfigPath: 'DOOMPI_MCP_CONFIG',\n personaFile: 'DOOMPI_PERSONA_FILE',\n hooks: 'DOOMPI_HOOKS_ENABLED',\n agents: 'DOOMPI_AGENTS_ENABLED',\n mcp: 'DOOMPI_MCP_ENABLED',\n allowProtectedWrites: 'DOOMPI_ALLOW_PROTECTED_WRITES',\n} as const;\n\nfunction splitCsv(value: string | undefined): string[] {\n return (\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction splitPaths(value: string | undefined): string[] {\n return (\n value\n ?.split(path.delimiter)\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n );\n}\n\nfunction parseFlag(value: string | undefined): boolean {\n return value !== DISABLED_FLAG;\n}\n\nfunction parseStringRecord(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): Record<string, string> {\n if (!value) return {};\n try {\n const parsed = JSON.parse(value) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n return Object.fromEntries(\n Object.entries(parsed).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n } catch (error) {\n report?.(key, error);\n return {};\n }\n}\n\nfunction parseStringList(value: string | undefined, key: string, report?: HarnessStateParseReporter): string[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nfunction parsePluginHooks(\n value: string | undefined,\n key: string,\n report?: HarnessStateParseReporter,\n): PluginHookSource[] {\n if (!value) return [];\n try {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is PluginHookSource =>\n typeof item === 'object' &&\n item !== null &&\n typeof (item as PluginHookSource).pluginRoot === 'string' &&\n typeof (item as PluginHookSource).configPath === 'string',\n );\n } catch (error) {\n report?.(key, error);\n return [];\n }\n}\n\nexport function readHarnessState(\n environment: NodeJS.ProcessEnv = process.env,\n report?: HarnessStateParseReporter,\n): HarnessState {\n const keys = HARNESS_STATE_KEYS;\n const hookGroups = environment[keys.hookGroups];\n return {\n root: environment[keys.root] || undefined,\n majorMode: environment[keys.majorMode] || DEFAULT_MAJOR_MODE,\n temporaryDirectory: environment[keys.temporaryDirectory] || undefined,\n domains: splitCsv(environment[keys.domains]),\n layers: splitCsv(environment[keys.layers]),\n compositionFingerprint: environment[keys.compositionFingerprint] || undefined,\n profile: environment[keys.profile] || undefined,\n profileEnvironment: parseStringRecord(environment[keys.profileEnvironment], keys.profileEnvironment, report),\n hookGroups: hookGroups === undefined ? undefined : splitCsv(hookGroups),\n skillDirectories: splitPaths(environment[keys.skillDirectories]),\n agentDirectories: splitPaths(environment[keys.agentDirectories]),\n additionalDirectories: splitPaths(environment[keys.additionalDirectories]),\n childExtensions: parseStringList(environment[keys.childExtensions], keys.childExtensions, report),\n pluginDirectories: splitPaths(environment[keys.pluginDirectories]),\n pluginHooks: parsePluginHooks(environment[keys.pluginHooks], keys.pluginHooks, report),\n mcpConfigPath: environment[keys.mcpConfigPath] || undefined,\n personaFile: environment[keys.personaFile] || undefined,\n hooks: parseFlag(environment[keys.hooks]),\n agents: parseFlag(environment[keys.agents]),\n mcp: parseFlag(environment[keys.mcp]),\n allowProtectedWrites: parseFlag(environment[keys.allowProtectedWrites]),\n };\n}\n\n/**\n * Publishes a state patch into an environment.\n *\n * Takes the environment rather than assuming `process.env`, because the\n * launcher builds a child environment and Doom Team builds a spawn snapshot;\n * neither should mutate its own process to describe another one.\n *\n * Fields in FILE_ONLY_FIELDS are skipped: the file carries them, and a reader\n * that needs them reads the store.\n */\nexport function projectHarnessEnvironment(\n patch: Partial<HarnessState>,\n environment: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const assign = (key: string, value: string | undefined): void => {\n if (value === undefined) delete environment[key];\n else environment[key] = value;\n };\n const assignFlag = (key: string, value: boolean): void => assign(key, value ? '1' : DISABLED_FLAG);\n const keys = HARNESS_STATE_KEYS;\n\n if ('root' in patch) assign(keys.root, patch.root);\n if ('majorMode' in patch) assign(keys.majorMode, patch.majorMode);\n if ('temporaryDirectory' in patch) assign(keys.temporaryDirectory, patch.temporaryDirectory);\n if ('domains' in patch) assign(keys.domains, patch.domains?.join(','));\n if ('layers' in patch) assign(keys.layers, patch.layers?.join(','));\n if ('compositionFingerprint' in patch) assign(keys.compositionFingerprint, patch.compositionFingerprint);\n if ('profile' in patch) assign(keys.profile, patch.profile);\n if ('hookGroups' in patch) assign(keys.hookGroups, patch.hookGroups?.join(','));\n if ('skillDirectories' in patch) assign(keys.skillDirectories, patch.skillDirectories?.join(path.delimiter));\n if ('agentDirectories' in patch) assign(keys.agentDirectories, patch.agentDirectories?.join(path.delimiter));\n if ('additionalDirectories' in patch) {\n assign(keys.additionalDirectories, patch.additionalDirectories?.join(path.delimiter));\n }\n if ('childExtensions' in patch) assign(keys.childExtensions, JSON.stringify(patch.childExtensions ?? []));\n if ('pluginDirectories' in patch) assign(keys.pluginDirectories, patch.pluginDirectories?.join(path.delimiter));\n if ('mcpConfigPath' in patch) assign(keys.mcpConfigPath, patch.mcpConfigPath);\n if ('personaFile' in patch) assign(keys.personaFile, patch.personaFile);\n if (patch.hooks !== undefined) assignFlag(keys.hooks, patch.hooks);\n if (patch.agents !== undefined) assignFlag(keys.agents, patch.agents);\n if (patch.mcp !== undefined) assignFlag(keys.mcp, patch.mcp);\n if (patch.allowProtectedWrites !== undefined) assignFlag(keys.allowProtectedWrites, patch.allowProtectedWrites);\n return environment;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../config.cjs"),t=require("../harnessStore.cjs"),n=require("./piContext.cjs");require("../../types/config.cjs");const r=require("../../providers/doomConfigService.cjs"),i=require("./helpContribution.cjs");let a=require("@deepseek-ai/cordis"),o=require("@agimon-ai/doompi-extension-contracts/session-context"),s=require("@agimon-ai/doompi-telemetry");const c=`@agimon-ai/doompi-config`;async function l(l){let u=new a.Context,d,f=()=>(d??=u.fiber.dispose(),d);try{u.effect(function*(){let u=i.registerDoomConfigHelp(l);yield()=>u.dispose();let d=!0,f=0,p,m,h;yield async()=>{d=!1,f+=1,await m?.dispose(),m=void 0,p=void 0;try{await h?.shutdown()}finally{h=void 0}},l.on(`session_start`,async(i,u)=>{let g=++f;p?.(),p=void 0,n.acknowledgeDoomConfigTransition(l,u,t.getHarnessState());let _=await n.createDoomConfigContextAsync(u);!d||g!==f||(p=n.provideDoomConfigContext(u,_),m??=(0,o.openDoomSessionContext)(u,()=>new a.Context),m.root.reflect.get(`doomConfig`)||new r.DoomConfigService(m.root,e.loadDoomConfig),h??=(0,s.createDoomTelemetry)({serviceName:`doom-config`,packageName:c,cwd:u.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),h.recordEvent(`doom_config.context_bound`,{"config.major_mode":_.harness.majorMode,"config.domain_count":_.harness.domains.length,"config.has_profile":_.harness.profile!==void 0,"config.requires_relaunch":_.requiresRelaunch}))})},c)}catch(e){throw await f(),e}l.on(`session_shutdown`,f)}exports.default=l,exports.registerConfigExtension=l;
1
+ const e=require("../harnessStore.cjs"),t=require("./piContext.cjs"),n=require("./helpContribution.cjs");let r=require("@agimon-ai/doompi-extension-contracts/mcp-projection"),i=require("@agimon-ai/doompi-extension-contracts/cordis-host"),a=require("@agimon-ai/doompi-extension-contracts/readiness"),o=require("@agimon-ai/doompi-extension-contracts/help"),s=require("@agimon-ai/doompi-telemetry");const c=`@agimon-ai/doompi-config`;async function l(e){let t=await(0,i.connectDoomCordisHost)(e,c),n=t.root.plugin(u,{pi:e});try{await n}catch(e){throw await n.dispose(),await t.dispose(),e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function u(l,{pi:u}){l.inject([o.DOOM_HELP_SERVICE],e=>{let t=n.registerDoomConfigHelp((0,o.requireDoomHelpService)(e));return()=>t.dispose()});let d,f=l.inject([i.DOOM_CORDIS_SESSION_SERVICE],n=>{let o=n.get(i.DOOM_CORDIS_SESSION_SERVICE),l=o.context,f=Symbol(o.generation),p=!0,m=Promise.resolve(),h,g=(0,a.createDoomReadinessCoordinator)({notify(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`,r=`${e.packageId} initialization ${e.state}: ${n}`;l.hasUI?l.ui.notify(r,`warning`):process.emitWarning(r)}});n.effect(()=>async()=>{p=!1,d?.token===f&&(d=void 0),await Promise.allSettled([g.dispose(),m]),await h?.shutdown()},`${c}/session`),n.provide(a.DOOM_READINESS_SERVICE,g);let _=(0,s.createDoomTelemetry)({serviceName:`doom-config`,packageName:c,cwd:l.cwd,env:process.env,enableLogs:!0,enableTraces:!0});h=_;let v=g.start(c,o.generation,async i=>{t.acknowledgeDoomConfigTransition(u,l,e.getHarnessState());let a=await t.createDoomConfigContextAsync(l);if(i.aborted)throw i.reason;if(!p||d?.token!==f)throw Error(`Doom Config initialization was superseded: ${o.generation}.`);t.provideDoomConfigContext(n,a,`${o.generation}:config`);let s=a.harness.root??l.cwd,c=a.harness.temporaryDirectory??l.cwd,m=a.harness.mcp&&(0,r.isDoomMcpProjection)(a.harness.mcpProjection)&&a.harness.mcpProjection.repoRoot===s?a.harness.mcpProjection:(0,r.createDisabledDoomMcpProjection)({repoRoot:s,stagingDirectory:c});return n.provide(r.DOOM_MCP_PROJECTION_SERVICE,(0,r.createDoomMcpProjectionService)({sessionId:o.sessionId,generation:`${o.generation}:mcp-projection`,projection:m})),Promise.allSettled([_.recordEvent(`doom_config.context_bound`,{"config.major_mode":a.harness.majorMode,"config.domain_count":a.harness.domains.length,"config.has_profile":a.harness.profile!==void 0,"config.requires_relaunch":a.requiresRelaunch})]),{value:void 0}});d={token:f,sessionManager:l.sessionManager,handle:v},m=v.wait(),Promise.allSettled([m])});u.on(`session_start`,async(e,t)=>{await f.await();let n=d;if(!n||n.sessionManager!==t.sessionManager)throw Error(`Doom Config initialization is unavailable for the active session.`);if(await n.handle.wait(),d?.token!==n.token)throw Error(`Doom Config initialization was superseded before the session barrier completed.`)})}exports.default=l,exports.registerConfigExtension=l;
2
2
  //# sourceMappingURL=configExtension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"configExtension.cjs","names":["Context","registerDoomConfigHelp","getHarnessState","createDoomConfigContextAsync","provideDoomConfigContext","openDoomSessionContext","DoomConfigService","loadDoomConfig","createDoomTelemetry"],"sources":["../../../src/adapters/pi/configExtension.ts"],"sourcesContent":["import {\n type DoomSessionContextHandle,\n openDoomSessionContext,\n} from '@agimon-ai/doompi-extension-contracts/session-context';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { Context } from '@deepseek-ai/cordis';\nimport { DOOM_CONFIG_SERVICE } from '../../types/config.ts';\nimport { loadDoomConfig } from '../config.ts';\nimport { DoomConfigService } from '../../providers/doomConfigService.ts';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { getHarnessState } from '../harnessStore.ts';\nimport {\n acknowledgeDoomConfigTransition,\n createDoomConfigContextAsync,\n provideDoomConfigContext,\n} from './piContext.ts';\nimport { registerDoomConfigHelp } from './helpContribution.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-config';\n\n/** The fixed Config core's single standard Pi factory. */\nexport async function registerConfigExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n cordis.effect(function* () {\n const help = registerDoomConfigHelp(pi);\n yield () => help.dispose();\n\n let active = true;\n let generation = 0;\n let bindingDisposer: (() => void) | undefined;\n let session: DoomSessionContextHandle | undefined;\n let telemetry: DoomTelemetry | undefined;\n yield async () => {\n active = false;\n generation += 1;\n await session?.dispose();\n session = undefined;\n // Config remains available to extensions that shut down after the\n // fixed core. The WeakMap key disappears with Pi's session manager,\n // and a reload overwrites the binding before consumers run.\n bindingDisposer = undefined;\n try {\n await telemetry?.shutdown();\n } finally {\n telemetry = undefined;\n }\n };\n\n pi.on('session_start', async (_event, context) => {\n const ownGeneration = ++generation;\n bindingDisposer?.();\n bindingDisposer = undefined;\n acknowledgeDoomConfigTransition(pi, context, getHarnessState());\n const config = await createDoomConfigContextAsync(context);\n if (!active || ownGeneration !== generation) return;\n\n bindingDisposer = provideDoomConfigContext(context, config);\n // Config is the one package present in every activation, parent and\n // detached child alike, so it is a safe place to open the session's\n // cordis registry. Publishing the service here is what lets any other\n // extension resolve `doomConfig` by name instead of importing us.\n session ??= openDoomSessionContext(context, () => new Context());\n if (!session.root.reflect.get(DOOM_CONFIG_SERVICE)) {\n new DoomConfigService(session.root, loadDoomConfig);\n }\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-config',\n packageName: PACKAGE_SOURCE,\n cwd: context.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n void telemetry.recordEvent('doom_config.context_bound', {\n 'config.major_mode': config.harness.majorMode,\n 'config.domain_count': config.harness.domains.length,\n 'config.has_profile': config.harness.profile !== undefined,\n 'config.requires_relaunch': config.requiresRelaunch,\n });\n });\n }, PACKAGE_SOURCE);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on('session_shutdown', dispose);\n}\n\nexport default registerConfigExtension;\n"],"mappings":"+WAkBA,MAAM,EAAiB,2BAGvB,eAAsB,EAAwB,EAAiC,CAC7E,IAAM,EAAS,IAAIA,EAAAA,QACf,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAO,OAAO,WAAa,CACzB,IAAM,EAAOC,EAAAA,uBAAuB,CAAE,EACtC,SAAY,EAAK,QAAQ,EAEzB,IAAI,EAAS,GACT,EAAa,EACb,EACA,EACA,EACJ,MAAM,SAAY,CAChB,EAAS,GACT,GAAc,EACd,MAAM,GAAS,QAAQ,EACvB,EAAU,IAAA,GAIV,EAAkB,IAAA,GAClB,GAAI,CACF,MAAM,GAAW,SAAS,CAC5B,QAAU,CACR,EAAY,IAAA,EACd,CACF,EAEA,EAAG,GAAG,gBAAiB,MAAO,EAAQ,IAAY,CAChD,IAAM,EAAgB,EAAE,EACxB,IAAkB,EAClB,EAAkB,IAAA,GAClB,EAAA,gCAAgC,EAAI,EAASC,EAAAA,gBAAgB,CAAC,EAC9D,IAAM,EAAS,MAAMC,EAAAA,6BAA6B,CAAO,EACrD,CAAC,GAAU,IAAkB,IAEjC,EAAkBC,EAAAA,yBAAyB,EAAS,CAAM,EAK1D,KAAA,EAAYC,EAAAA,uBAAAA,CAAuB,MAAe,IAAIL,EAAAA,OAAS,EAC1D,EAAQ,KAAK,QAAQ,IAAA,YAAuB,GAC/C,IAAIM,EAAAA,kBAAkB,EAAQ,KAAMC,EAAAA,cAAc,EAEpD,KAAA,EAAcC,EAAAA,oBAAAA,CAAoB,CAChC,YAAa,cACb,YAAa,EACb,IAAK,EAAQ,IACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,EAAe,YAAY,4BAA6B,CACtD,oBAAqB,EAAO,QAAQ,UACpC,sBAAuB,EAAO,QAAQ,QAAQ,OAC9C,qBAAsB,EAAO,QAAQ,UAAY,IAAA,GACjD,2BAA4B,EAAO,gBACrC,CAAC,EACH,CAAC,CACH,EAAG,CAAc,CACnB,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAoB,CAAO,CACnC"}
1
+ {"version":3,"file":"configExtension.cjs","names":["connectDoomCordisHost","DOOM_HELP_SERVICE","registerDoomConfigHelp","requireDoomHelpService","DOOM_CORDIS_SESSION_SERVICE","createDoomReadinessCoordinator","DOOM_READINESS_SERVICE","createDoomTelemetry","getHarnessState","createDoomConfigContextAsync","isDoomMcpProjection","createDisabledDoomMcpProjection","DOOM_MCP_PROJECTION_SERVICE","createDoomMcpProjectionService"],"sources":["../../../src/adapters/pi/configExtension.ts"],"sourcesContent":["import {\n createDisabledDoomMcpProjection,\n createDoomMcpProjectionService,\n DOOM_MCP_PROJECTION_SERVICE,\n isDoomMcpProjection,\n} from '@agimon-ai/doompi-extension-contracts/mcp-projection';\nimport {\n connectDoomCordisHost,\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n createDoomReadinessCoordinator,\n DOOM_READINESS_SERVICE,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { getHarnessState } from '../harnessStore.ts';\nimport {\n acknowledgeDoomConfigTransition,\n createDoomConfigContextAsync,\n provideDoomConfigContext,\n} from './piContext.ts';\nimport { registerDoomConfigHelp } from './helpContribution.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-config';\n\n/** The fixed Config core's single standard Pi factory. */\nexport async function registerConfigExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(configPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface ConfigPluginOptions {\n readonly pi: ExtensionAPI;\n}\n\ninterface ConfigInitialization {\n readonly token: symbol;\n readonly sessionManager: ExtensionContext['sessionManager'];\n readonly handle: DoomReadinessHandle<void>;\n}\n\nfunction configPlugin(cordis: Context, { pi }: ConfigPluginOptions): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const help = registerDoomConfigHelp(requireDoomHelpService(helpContext));\n return () => help.dispose();\n });\n\n let initialization: ConfigInitialization | undefined;\n const sessionInjection = cordis.inject([DOOM_CORDIS_SESSION_SERVICE], (sessionContext) => {\n const session = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = session.context;\n const token = Symbol(session.generation);\n let active = true;\n let initializationTask: Promise<void> = Promise.resolve();\n let telemetry: DoomTelemetry | undefined;\n const readiness = createDoomReadinessCoordinator({\n notify(notification: DoomReadinessNotification) {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n const message = `${notification.packageId} initialization ${notification.state}: ${detail}`;\n if (context.hasUI) context.ui.notify(message, 'warning');\n else process.emitWarning(message);\n },\n });\n sessionContext.effect(\n () => async () => {\n active = false;\n if (initialization?.token === token) initialization = undefined;\n await Promise.allSettled([readiness.dispose(), initializationTask]);\n await telemetry?.shutdown();\n },\n `${PACKAGE_SOURCE}/session`,\n );\n\n // Consumers can resolve and register their own work as soon as the host's\n // session fiber activates. Config file I/O continues behind the barrier\n // below so Cordis activation itself stays synchronous.\n sessionContext.provide(DOOM_READINESS_SERVICE, readiness);\n const sessionTelemetry = createDoomTelemetry({\n serviceName: 'doom-config',\n packageName: PACKAGE_SOURCE,\n cwd: context.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n telemetry = sessionTelemetry;\n const handle = readiness.start<void>(PACKAGE_SOURCE, session.generation, async (signal) => {\n acknowledgeDoomConfigTransition(pi, context, getHarnessState());\n const config = await createDoomConfigContextAsync(context);\n if (signal.aborted) throw signal.reason;\n if (!active || initialization?.token !== token) {\n throw new Error(`Doom Config initialization was superseded: ${session.generation}.`);\n }\n\n provideDoomConfigContext(sessionContext, config, `${session.generation}:config`);\n const repoRoot = config.harness.root ?? context.cwd;\n const stagingDirectory = config.harness.temporaryDirectory ?? context.cwd;\n const projection =\n config.harness.mcp &&\n isDoomMcpProjection(config.harness.mcpProjection) &&\n config.harness.mcpProjection.repoRoot === repoRoot\n ? config.harness.mcpProjection\n : createDisabledDoomMcpProjection({ repoRoot, stagingDirectory });\n sessionContext.provide(\n DOOM_MCP_PROJECTION_SERVICE,\n createDoomMcpProjectionService({\n sessionId: session.sessionId,\n generation: `${session.generation}:mcp-projection`,\n projection,\n }),\n );\n void Promise.allSettled([\n sessionTelemetry.recordEvent('doom_config.context_bound', {\n 'config.major_mode': config.harness.majorMode,\n 'config.domain_count': config.harness.domains.length,\n 'config.has_profile': config.harness.profile !== undefined,\n 'config.requires_relaunch': config.requiresRelaunch,\n }),\n ]);\n return { value: undefined };\n });\n initialization = { token, sessionManager: context.sessionManager, handle };\n initializationTask = handle.wait();\n // The Pi barrier observes this same promise. Attaching a rejection handler\n // now also covers hosts that dispose before Pi reaches that handler.\n void Promise.allSettled([initializationTask]);\n });\n\n // Pi invokes session_start handlers in registration order. The Cordis host\n // runs first and commits readiness; this Config-owned barrier then preserves\n // the historical guarantee that later package handlers see bound config.\n pi.on('session_start', async (_event, context) => {\n await sessionInjection.await();\n const current = initialization;\n if (!current || current.sessionManager !== context.sessionManager) {\n throw new Error('Doom Config initialization is unavailable for the active session.');\n }\n await current.handle.wait();\n if (initialization?.token !== current.token) {\n throw new Error('Doom Config initialization was superseded before the session barrier completed.');\n }\n });\n}\n\nexport default registerConfigExtension;\n"],"mappings":"2YA6BA,MAAM,EAAiB,2BAGvB,eAAsB,EAAwB,EAAiC,CAC7E,IAAM,EAAa,MAAA,EAAMA,EAAAA,sBAAAA,CAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAc,CAAE,IAAG,CAAC,EACzD,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CAGd,MAFA,MAAM,EAAM,QAAQ,EACpB,MAAM,EAAW,QAAQ,EACnB,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAYA,SAAS,EAAa,EAAiB,CAAE,MAAiC,CACxE,EAAO,OAAO,CAACC,EAAAA,iBAAiB,EAAI,GAAgB,CAClD,IAAM,EAAOC,EAAAA,wBAAAA,EAAuBC,EAAAA,uBAAAA,CAAuB,CAAW,CAAC,EACvE,UAAa,EAAK,QAAQ,CAC5B,CAAC,EAED,IAAI,EACE,EAAmB,EAAO,OAAO,CAACC,EAAAA,2BAA2B,EAAI,GAAmB,CACxF,IAAM,EAAU,EAAe,IAAIA,EAAAA,2BAA2B,EACxD,EAAU,EAAQ,QAClB,EAAQ,OAAO,EAAQ,UAAU,EACnC,EAAS,GACT,EAAoC,QAAQ,QAAQ,EACpD,EACE,GAAA,EAAYC,EAAAA,+BAAAA,CAA+B,CAC/C,OAAO,EAAyC,CAC9C,IAAM,EAAc,EAAa,YAAY,KAAK,IAAI,EAChD,GAAU,EAAa,OAAO,SAAW,IAAgB,mCACzD,EAAU,GAAG,EAAa,UAAU,kBAAkB,EAAa,MAAM,IAAI,IAC/E,EAAQ,MAAO,EAAQ,GAAG,OAAO,EAAS,SAAS,EAClD,QAAQ,YAAY,CAAO,CAClC,CACF,CAAC,EACD,EAAe,WACP,SAAY,CAChB,EAAS,GACL,GAAgB,QAAU,IAAO,EAAiB,IAAA,IACtD,MAAM,QAAQ,WAAW,CAAC,EAAU,QAAQ,EAAG,CAAkB,CAAC,EAClE,MAAM,GAAW,SAAS,CAC5B,EACA,GAAG,EAAe,SACpB,EAKA,EAAe,QAAQC,EAAAA,uBAAwB,CAAS,EACxD,IAAM,GAAA,EAAmBC,EAAAA,oBAAAA,CAAoB,CAC3C,YAAa,cACb,YAAa,EACb,IAAK,EAAQ,IACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,EAAY,EACZ,IAAM,EAAS,EAAU,MAAY,EAAgB,EAAQ,WAAY,KAAO,IAAW,CACzF,EAAA,gCAAgC,EAAI,EAASC,EAAAA,gBAAgB,CAAC,EAC9D,IAAM,EAAS,MAAMC,EAAAA,6BAA6B,CAAO,EACzD,GAAI,EAAO,QAAS,MAAM,EAAO,OACjC,GAAI,CAAC,GAAU,GAAgB,QAAU,EACvC,MAAU,MAAM,8CAA8C,EAAQ,WAAW,EAAE,EAGrF,EAAA,yBAAyB,EAAgB,EAAQ,GAAG,EAAQ,WAAW,QAAQ,EAC/E,IAAM,EAAW,EAAO,QAAQ,MAAQ,EAAQ,IAC1C,EAAmB,EAAO,QAAQ,oBAAsB,EAAQ,IAChE,EACJ,EAAO,QAAQ,MAAA,EACfC,EAAAA,oBAAAA,CAAoB,EAAO,QAAQ,aAAa,GAChD,EAAO,QAAQ,cAAc,WAAa,EACtC,EAAO,QAAQ,eAAA,EACfC,EAAAA,gCAAAA,CAAgC,CAAE,WAAU,kBAAiB,CAAC,EAiBpE,OAhBA,EAAe,QACbC,EAAAA,6BAAAA,EACAC,EAAAA,+BAAAA,CAA+B,CAC7B,UAAW,EAAQ,UACnB,WAAY,GAAG,EAAQ,WAAW,iBAClC,YACF,CAAC,CACH,EACA,QAAa,WAAW,CACtB,EAAiB,YAAY,4BAA6B,CACxD,oBAAqB,EAAO,QAAQ,UACpC,sBAAuB,EAAO,QAAQ,QAAQ,OAC9C,qBAAsB,EAAO,QAAQ,UAAY,IAAA,GACjD,2BAA4B,EAAO,gBACrC,CAAC,CACH,CAAC,EACM,CAAE,MAAO,IAAA,EAAU,CAC5B,CAAC,EACD,EAAiB,CAAE,QAAO,eAAgB,EAAQ,eAAgB,QAAO,EACzE,EAAqB,EAAO,KAAK,EAGjC,QAAa,WAAW,CAAC,CAAkB,CAAC,CAC9C,CAAC,EAKD,EAAG,GAAG,gBAAiB,MAAO,EAAQ,IAAY,CAChD,MAAM,EAAiB,MAAM,EAC7B,IAAM,EAAU,EAChB,GAAI,CAAC,GAAW,EAAQ,iBAAmB,EAAQ,eACjD,MAAU,MAAM,mEAAmE,EAGrF,GADA,MAAM,EAAQ,OAAO,KAAK,EACtB,GAAgB,QAAU,EAAQ,MACpC,MAAU,MAAM,iFAAiF,CAErG,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"configExtension.d.cts","names":[],"sources":["../../../src/adapters/pi/configExtension.ts"],"mappings":";;;iBAqBsB,wBAAwB,IAAI,eAAe"}
1
+ {"version":3,"file":"configExtension.d.cts","names":[],"sources":["../../../src/adapters/pi/configExtension.ts"],"mappings":";;;iBAgCsB,wBAAwB,IAAI,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"configExtension.d.mts","names":[],"sources":["../../../src/adapters/pi/configExtension.ts"],"mappings":";;;iBAqBsB,wBAAwB,IAAI,eAAe"}
1
+ {"version":3,"file":"configExtension.d.mts","names":[],"sources":["../../../src/adapters/pi/configExtension.ts"],"mappings":";;;iBAgCsB,wBAAwB,IAAI,eAAe"}
@@ -1,2 +1,2 @@
1
- import{loadDoomConfig as e}from"../config.mjs";import{getHarnessState as t}from"../harnessStore.mjs";import{acknowledgeDoomConfigTransition as n,createDoomConfigContextAsync as r,provideDoomConfigContext as i}from"./piContext.mjs";import"../../types/config.mjs";import{DoomConfigService as a}from"../../providers/doomConfigService.mjs";import{registerDoomConfigHelp as o}from"./helpContribution.mjs";import{Context as s}from"@deepseek-ai/cordis";import{openDoomSessionContext as c}from"@agimon-ai/doompi-extension-contracts/session-context";import{createDoomTelemetry as l}from"@agimon-ai/doompi-telemetry";const u=`@agimon-ai/doompi-config`;async function d(d){let f=new s,p,m=()=>(p??=f.fiber.dispose(),p);try{f.effect(function*(){let f=o(d);yield()=>f.dispose();let p=!0,m=0,h,g,_;yield async()=>{p=!1,m+=1,await g?.dispose(),g=void 0,h=void 0;try{await _?.shutdown()}finally{_=void 0}},d.on(`session_start`,async(o,f)=>{let v=++m;h?.(),h=void 0,n(d,f,t());let y=await r(f);!p||v!==m||(h=i(f,y),g??=c(f,()=>new s),g.root.reflect.get(`doomConfig`)||new a(g.root,e),_??=l({serviceName:`doom-config`,packageName:u,cwd:f.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),_.recordEvent(`doom_config.context_bound`,{"config.major_mode":y.harness.majorMode,"config.domain_count":y.harness.domains.length,"config.has_profile":y.harness.profile!==void 0,"config.requires_relaunch":y.requiresRelaunch}))})},u)}catch(e){throw await m(),e}d.on(`session_shutdown`,m)}export{d as default,d as registerConfigExtension};
1
+ import{getHarnessState as e}from"../harnessStore.mjs";import{acknowledgeDoomConfigTransition as t,createDoomConfigContextAsync as n,provideDoomConfigContext as r}from"./piContext.mjs";import{registerDoomConfigHelp as i}from"./helpContribution.mjs";import{DOOM_MCP_PROJECTION_SERVICE as a,createDisabledDoomMcpProjection as o,createDoomMcpProjectionService as s,isDoomMcpProjection as c}from"@agimon-ai/doompi-extension-contracts/mcp-projection";import{DOOM_CORDIS_SESSION_SERVICE as l,connectDoomCordisHost as u}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_READINESS_SERVICE as d,createDoomReadinessCoordinator as f}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_HELP_SERVICE as p,requireDoomHelpService as m}from"@agimon-ai/doompi-extension-contracts/help";import{createDoomTelemetry as h}from"@agimon-ai/doompi-telemetry";const g=`@agimon-ai/doompi-config`;async function _(e){let t=await u(e,g),n=t.root.plugin(v,{pi:e});try{await n}catch(e){throw await n.dispose(),await t.dispose(),e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function v(u,{pi:_}){u.inject([p],e=>{let t=i(m(e));return()=>t.dispose()});let v,y=u.inject([l],i=>{let u=i.get(l),p=u.context,m=Symbol(u.generation),y=!0,b=Promise.resolve(),x,S=f({notify(e){let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`,r=`${e.packageId} initialization ${e.state}: ${n}`;p.hasUI?p.ui.notify(r,`warning`):process.emitWarning(r)}});i.effect(()=>async()=>{y=!1,v?.token===m&&(v=void 0),await Promise.allSettled([S.dispose(),b]),await x?.shutdown()},`${g}/session`),i.provide(d,S);let C=h({serviceName:`doom-config`,packageName:g,cwd:p.cwd,env:process.env,enableLogs:!0,enableTraces:!0});x=C;let w=S.start(g,u.generation,async l=>{t(_,p,e());let d=await n(p);if(l.aborted)throw l.reason;if(!y||v?.token!==m)throw Error(`Doom Config initialization was superseded: ${u.generation}.`);r(i,d,`${u.generation}:config`);let f=d.harness.root??p.cwd,h=d.harness.temporaryDirectory??p.cwd,g=d.harness.mcp&&c(d.harness.mcpProjection)&&d.harness.mcpProjection.repoRoot===f?d.harness.mcpProjection:o({repoRoot:f,stagingDirectory:h});return i.provide(a,s({sessionId:u.sessionId,generation:`${u.generation}:mcp-projection`,projection:g})),Promise.allSettled([C.recordEvent(`doom_config.context_bound`,{"config.major_mode":d.harness.majorMode,"config.domain_count":d.harness.domains.length,"config.has_profile":d.harness.profile!==void 0,"config.requires_relaunch":d.requiresRelaunch})]),{value:void 0}});v={token:m,sessionManager:p.sessionManager,handle:w},b=w.wait(),Promise.allSettled([b])});_.on(`session_start`,async(e,t)=>{await y.await();let n=v;if(!n||n.sessionManager!==t.sessionManager)throw Error(`Doom Config initialization is unavailable for the active session.`);if(await n.handle.wait(),v?.token!==n.token)throw Error(`Doom Config initialization was superseded before the session barrier completed.`)})}export{_ as default,_ as registerConfigExtension};
2
2
  //# sourceMappingURL=configExtension.mjs.map