@agimon-ai/doompi 0.0.1-alpha.19 → 0.0.1-alpha.20
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.
- package/README.md +25 -1
- package/dist/adapters/bootstrapClaim.cjs.map +1 -1
- package/dist/adapters/bootstrapClaim.mjs.map +1 -1
- package/dist/adapters/bootstrapLocator.cjs +1 -1
- package/dist/adapters/bootstrapLocator.cjs.map +1 -1
- package/dist/adapters/bootstrapLocator.d.cts +1 -1
- package/dist/adapters/bootstrapLocator.d.cts.map +1 -1
- package/dist/adapters/bootstrapLocator.d.mts +1 -1
- package/dist/adapters/bootstrapLocator.d.mts.map +1 -1
- package/dist/adapters/bootstrapLocator.mjs +1 -1
- package/dist/adapters/bootstrapLocator.mjs.map +1 -1
- package/dist/adapters/compatibility/process.cjs +1 -1
- package/dist/adapters/compatibility/process.mjs +1 -1
- package/dist/adapters/composer.cjs +1 -1
- package/dist/adapters/composer.cjs.map +1 -1
- package/dist/adapters/composer.d.cts +1 -1
- package/dist/adapters/composer.d.cts.map +1 -1
- package/dist/adapters/composer.d.mts +1 -1
- package/dist/adapters/composer.d.mts.map +1 -1
- package/dist/adapters/composer.mjs +1 -1
- package/dist/adapters/composer.mjs.map +1 -1
- package/dist/adapters/extensionCompiler.cjs +2 -2
- package/dist/adapters/extensionCompiler.cjs.map +1 -1
- package/dist/adapters/extensionCompiler.mjs +2 -2
- package/dist/adapters/extensionCompiler.mjs.map +1 -1
- package/dist/adapters/harnessContext.cjs +1 -1
- package/dist/adapters/harnessContext.cjs.map +1 -1
- package/dist/adapters/harnessContext.d.cts.map +1 -1
- package/dist/adapters/harnessContext.d.mts.map +1 -1
- package/dist/adapters/harnessContext.mjs +1 -1
- package/dist/adapters/harnessContext.mjs.map +1 -1
- package/dist/adapters/matrixSwitcher.cjs +1 -1
- package/dist/adapters/matrixSwitcher.d.mts +1 -1
- package/dist/adapters/matrixSwitcher.mjs +1 -1
- package/dist/adapters/projectPiSettings.cjs.map +1 -1
- package/dist/adapters/projectPiSettings.mjs.map +1 -1
- package/dist/adapters/resourceCollector.cjs +2 -2
- package/dist/adapters/resourceCollector.cjs.map +1 -1
- package/dist/adapters/resourceCollector.d.cts +2 -2
- package/dist/adapters/resourceCollector.d.cts.map +1 -1
- package/dist/adapters/resourceCollector.d.mts +2 -2
- package/dist/adapters/resourceCollector.d.mts.map +1 -1
- package/dist/adapters/resourceCollector.mjs +2 -2
- package/dist/adapters/resourceCollector.mjs.map +1 -1
- package/dist/adapters/runtimeBundle.cjs +1 -1
- package/dist/adapters/runtimeBundle.cjs.map +1 -1
- package/dist/adapters/runtimeBundle.d.cts +3 -1
- package/dist/adapters/runtimeBundle.d.cts.map +1 -1
- package/dist/adapters/runtimeBundle.d.mts +3 -1
- package/dist/adapters/runtimeBundle.d.mts.map +1 -1
- package/dist/adapters/runtimeBundle.mjs +1 -1
- package/dist/adapters/runtimeBundle.mjs.map +1 -1
- package/dist/adapters/sharedBuildCache.cjs +2 -0
- package/dist/adapters/sharedBuildCache.cjs.map +1 -0
- package/dist/adapters/sharedBuildCache.mjs +2 -0
- package/dist/adapters/sharedBuildCache.mjs.map +1 -0
- package/dist/adapters/startupPrecompiler.cjs +1 -1
- package/dist/adapters/startupPrecompiler.cjs.map +1 -1
- package/dist/adapters/startupPrecompiler.d.cts +1 -1
- package/dist/adapters/startupPrecompiler.d.cts.map +1 -1
- package/dist/adapters/startupPrecompiler.d.mts +1 -1
- package/dist/adapters/startupPrecompiler.d.mts.map +1 -1
- package/dist/adapters/startupPrecompiler.mjs +1 -1
- package/dist/adapters/startupPrecompiler.mjs.map +1 -1
- package/dist/adapters/syncLocation.cjs +2 -0
- package/dist/adapters/syncLocation.cjs.map +1 -0
- package/dist/adapters/syncLocation.d.cts +19 -0
- package/dist/adapters/syncLocation.d.cts.map +1 -0
- package/dist/adapters/syncLocation.d.mts +19 -0
- package/dist/adapters/syncLocation.d.mts.map +1 -0
- package/dist/adapters/syncLocation.mjs +2 -0
- package/dist/adapters/syncLocation.mjs.map +1 -0
- package/dist/adapters/syncState.cjs +1 -1
- package/dist/adapters/syncState.cjs.map +1 -1
- package/dist/adapters/syncState.d.cts +18 -6
- package/dist/adapters/syncState.d.cts.map +1 -1
- package/dist/adapters/syncState.d.mts +18 -6
- package/dist/adapters/syncState.d.mts.map +1 -1
- package/dist/adapters/syncState.mjs +1 -1
- package/dist/adapters/syncState.mjs.map +1 -1
- package/dist/adapters/syncStateContract.cjs +1 -1
- package/dist/adapters/syncStateContract.cjs.map +1 -1
- package/dist/adapters/syncStateContract.d.cts +5 -5
- package/dist/adapters/syncStateContract.d.mts +5 -5
- package/dist/adapters/syncStateContract.mjs +1 -1
- package/dist/adapters/syncStateContract.mjs.map +1 -1
- package/dist/adapters/syncedRuntimeBuilder.cjs +1 -1
- package/dist/adapters/syncedRuntimeBuilder.cjs.map +1 -1
- package/dist/adapters/syncedRuntimeBuilder.d.cts +1 -1
- package/dist/adapters/syncedRuntimeBuilder.d.cts.map +1 -1
- package/dist/adapters/syncedRuntimeBuilder.d.mts +1 -1
- package/dist/adapters/syncedRuntimeBuilder.d.mts.map +1 -1
- package/dist/adapters/syncedRuntimeBuilder.mjs +1 -1
- package/dist/adapters/syncedRuntimeBuilder.mjs.map +1 -1
- package/dist/commands/buildCommand.cjs +2 -2
- package/dist/commands/buildCommand.cjs.map +1 -1
- package/dist/commands/buildCommand.mjs +2 -2
- package/dist/commands/buildCommand.mjs.map +1 -1
- package/dist/commands/cli/help.cjs +7 -0
- package/dist/commands/cli/help.cjs.map +1 -1
- package/dist/commands/cli/help.mjs +7 -0
- package/dist/commands/cli/help.mjs.map +1 -1
- package/dist/commands/compatibilityCommand.cjs +1 -1
- package/dist/commands/compatibilityCommand.cjs.map +1 -1
- package/dist/commands/compatibilityCommand.mjs +1 -1
- package/dist/commands/launchCommand.cjs +1 -1
- package/dist/commands/launchCommand.mjs +1 -1
- package/dist/commands/syncCommand.cjs +5 -5
- package/dist/commands/syncCommand.cjs.map +1 -1
- package/dist/commands/syncCommand.d.cts +4 -1
- package/dist/commands/syncCommand.d.cts.map +1 -1
- package/dist/commands/syncCommand.d.mts +4 -1
- package/dist/commands/syncCommand.d.mts.map +1 -1
- package/dist/commands/syncCommand.mjs +5 -5
- package/dist/commands/syncCommand.mjs.map +1 -1
- package/dist/extensions/entries/repositoryHooks.cjs +5 -5
- package/dist/extensions/entries/repositoryHooks.mjs +5 -5
- package/dist/extensions/entries/styleSystem.cjs +2 -2
- package/dist/extensions/entries/styleSystem.cjs.map +1 -1
- package/dist/extensions/entries/styleSystem.mjs +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/services/config/index.cjs +1 -1
- package/dist/services/config/index.d.mts +1 -1
- package/dist/services/config/index.mjs +1 -1
- package/dist/services/index.cjs +1 -1
- package/dist/services/index.mjs +1 -1
- package/dist/services/syncState.cjs +1 -1
- package/dist/services/syncState.d.cts +2 -2
- package/dist/services/syncState.d.mts +2 -2
- package/dist/services/syncState.mjs +1 -1
- package/dist/types/interfaces/harness.d.cts +4 -0
- package/dist/types/interfaces/harness.d.cts.map +1 -1
- package/dist/types/interfaces/harness.d.mts +4 -0
- package/dist/types/interfaces/harness.d.mts.map +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Doompi is a configuration framework for [Pi](https://github.com/earendil-works/p
|
|
|
10
10
|
tailored for people whose agent has one MCP server too many. It turns extensions, skills,
|
|
11
11
|
MCP servers, and system prompts into config instead of background noise.
|
|
12
12
|
|
|
13
|
-

|
|
13
|
+

|
|
14
14
|
|
|
15
15
|
Plugin systems scope what an agent knows. Nothing scopes what it can reach. Claude Code's
|
|
16
16
|
`enableAllProjectMcpServers` and static denylist are repository-wide. Doompi draws that
|
|
@@ -49,6 +49,30 @@ pi # run your existing Pi setup for comp
|
|
|
49
49
|
`dpi sync` writes DoomPi's generated state, package alias, and theme resource, but it does
|
|
50
50
|
not register DoomPi in either normal Pi settings file.
|
|
51
51
|
|
|
52
|
+
### Sync storage and worktrees
|
|
53
|
+
|
|
54
|
+
Generated sync artifacts are kept out of the repository at:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
~/.pi/.doom/sync/<repo-label>--<repo-id-32hex>/
|
|
58
|
+
shared-cache/objects/<full-build-sha256>/
|
|
59
|
+
worktrees/<worktree-label>--<worktree-id-32hex>/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The repository identity comes from Git's canonical common directory, while each
|
|
63
|
+
worktree gets its own identity. Linked worktrees therefore share immutable,
|
|
64
|
+
content-addressed build objects but never share state, `dist`, manifests, staged
|
|
65
|
+
resources, or per-process `run` files. Runtime loading uses only verified artifacts
|
|
66
|
+
materialized in the current worktree directory; it never loads directly from the
|
|
67
|
+
shared cache. The global `~/.pi/.doom/*.yaml` configuration and persistent
|
|
68
|
+
`~/.pi/.doom/plugin-cache` behavior are unchanged.
|
|
69
|
+
|
|
70
|
+
Older releases may have written state under `<repository>/.pi/doom`. That location
|
|
71
|
+
is a read-only fallback only when the corresponding home-scoped state is absent.
|
|
72
|
+
`doompi sync --check` reports that migration is required, and `doompi sync` rebuilds
|
|
73
|
+
into the home-scoped worktree namespace rather than copying the legacy files. DoomPi
|
|
74
|
+
does not automatically delete legacy, orphaned, or unused generated directories.
|
|
75
|
+
|
|
52
76
|
For a fair comparison, `dpi` lets Pi merge the same ordinary settings from
|
|
53
77
|
`~/.pi/agent/settings.json` and `<repo>/.pi/settings.json`. It then overlays only these
|
|
54
78
|
DoomPi-owned values in memory:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapClaim.cjs","names":["path"],"sources":["../../src/adapters/bootstrapClaim.ts"],"sourcesContent":["import path from 'node:path';\n\n/**\n * Process-wide ownership of one repository's DoomPi load cycle.\n *\n * Pi unions the extension lists of its user and project settings scopes and\n * dedupes only by the resolved file's real path, so registering DoomPi in both\n * scopes loads two separate installs of the same package. Each one would\n * otherwise read, recompile, and rewrite the same
|
|
1
|
+
{"version":3,"file":"bootstrapClaim.cjs","names":["path"],"sources":["../../src/adapters/bootstrapClaim.ts"],"sourcesContent":["import path from 'node:path';\n\n/**\n * Process-wide ownership of one repository's DoomPi load cycle.\n *\n * Pi unions the extension lists of its user and project settings scopes and\n * dedupes only by the resolved file's real path, so registering DoomPi in both\n * scopes loads two separate installs of the same package. Each one would\n * otherwise read, recompile, and rewrite the same home-scoped worktree state\n * for the same repository, and two installs at different versions disagree about the state\n * contract. A process-global symbol survives the distinct module URLs those\n * installs have, so the first factory owns the cycle and the rest stand down.\n * Pi resolves project resources before user ones, which makes the owner the\n * repository-local install whenever both scopes register the package.\n */\n\nconst BOOTSTRAP_CLAIM_KEY = Symbol.for('@agimon-ai/doompi:bootstrap-claim');\n\nexport type ReleaseBootstrapClaim = () => void;\n\n/**\n * The registry shared by every DoomPi install in this process.\n *\n * The symbol description is part of the cross-install contract and must stay\n * exactly as written: two installs only meet here when they compute the same\n * key. A value of another shape belongs to an install that spelled the\n * registry differently, so this one starts its own rather than corrupting it.\n */\nfunction claimRegistry(): Map<string, symbol> {\n const existing = Reflect.get(globalThis, BOOTSTRAP_CLAIM_KEY);\n if (existing instanceof Map) return existing as Map<string, symbol>;\n const created = new Map<string, symbol>();\n Reflect.set(globalThis, BOOTSTRAP_CLAIM_KEY, created);\n return created;\n}\n\n/**\n * Claims the load cycle for one repository, or reports that it is already owned.\n *\n * Callers must acquire before their first `await`, because releasing happens on\n * `session_start` and an interleaved second factory would otherwise slip in.\n */\nexport function acquireBootstrapClaim(repoRoot: string): ReleaseBootstrapClaim | undefined {\n const registry = claimRegistry();\n const key = path.resolve(repoRoot);\n if (registry.has(key)) return undefined;\n\n const claim = Symbol('doompi-bootstrap');\n registry.set(key, claim);\n return () => {\n if (registry.get(key) === claim) registry.delete(key);\n };\n}\n"],"mappings":"iGAgBA,MAAM,EAAsB,OAAO,IAAI,oCAAoC,CAY3E,SAAS,GAAqC,CAC5C,IAAM,EAAW,QAAQ,IAAI,WAAY,EAAoB,CAC7D,GAAI,aAAoB,IAAK,OAAO,EACpC,IAAM,EAAU,IAAI,IAEpB,OADA,QAAQ,IAAI,WAAY,EAAqB,EAAQ,CAC9C,EAST,SAAgB,EAAsB,EAAqD,CACzF,IAAM,EAAW,GAAe,CAC1B,EAAMA,EAAAA,QAAK,QAAQ,EAAS,CAClC,GAAI,EAAS,IAAI,EAAI,CAAE,OAEvB,IAAM,EAAQ,OAAO,mBAAmB,CAExC,OADA,EAAS,IAAI,EAAK,EAAM,KACX,CACP,EAAS,IAAI,EAAI,GAAK,GAAO,EAAS,OAAO,EAAI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapClaim.mjs","names":[],"sources":["../../src/adapters/bootstrapClaim.ts"],"sourcesContent":["import path from 'node:path';\n\n/**\n * Process-wide ownership of one repository's DoomPi load cycle.\n *\n * Pi unions the extension lists of its user and project settings scopes and\n * dedupes only by the resolved file's real path, so registering DoomPi in both\n * scopes loads two separate installs of the same package. Each one would\n * otherwise read, recompile, and rewrite the same
|
|
1
|
+
{"version":3,"file":"bootstrapClaim.mjs","names":[],"sources":["../../src/adapters/bootstrapClaim.ts"],"sourcesContent":["import path from 'node:path';\n\n/**\n * Process-wide ownership of one repository's DoomPi load cycle.\n *\n * Pi unions the extension lists of its user and project settings scopes and\n * dedupes only by the resolved file's real path, so registering DoomPi in both\n * scopes loads two separate installs of the same package. Each one would\n * otherwise read, recompile, and rewrite the same home-scoped worktree state\n * for the same repository, and two installs at different versions disagree about the state\n * contract. A process-global symbol survives the distinct module URLs those\n * installs have, so the first factory owns the cycle and the rest stand down.\n * Pi resolves project resources before user ones, which makes the owner the\n * repository-local install whenever both scopes register the package.\n */\n\nconst BOOTSTRAP_CLAIM_KEY = Symbol.for('@agimon-ai/doompi:bootstrap-claim');\n\nexport type ReleaseBootstrapClaim = () => void;\n\n/**\n * The registry shared by every DoomPi install in this process.\n *\n * The symbol description is part of the cross-install contract and must stay\n * exactly as written: two installs only meet here when they compute the same\n * key. A value of another shape belongs to an install that spelled the\n * registry differently, so this one starts its own rather than corrupting it.\n */\nfunction claimRegistry(): Map<string, symbol> {\n const existing = Reflect.get(globalThis, BOOTSTRAP_CLAIM_KEY);\n if (existing instanceof Map) return existing as Map<string, symbol>;\n const created = new Map<string, symbol>();\n Reflect.set(globalThis, BOOTSTRAP_CLAIM_KEY, created);\n return created;\n}\n\n/**\n * Claims the load cycle for one repository, or reports that it is already owned.\n *\n * Callers must acquire before their first `await`, because releasing happens on\n * `session_start` and an interleaved second factory would otherwise slip in.\n */\nexport function acquireBootstrapClaim(repoRoot: string): ReleaseBootstrapClaim | undefined {\n const registry = claimRegistry();\n const key = path.resolve(repoRoot);\n if (registry.has(key)) return undefined;\n\n const claim = Symbol('doompi-bootstrap');\n registry.set(key, claim);\n return () => {\n if (registry.get(key) === claim) registry.delete(key);\n };\n}\n"],"mappings":"yBAgBA,MAAM,EAAsB,OAAO,IAAI,oCAAoC,CAY3E,SAAS,GAAqC,CAC5C,IAAM,EAAW,QAAQ,IAAI,WAAY,EAAoB,CAC7D,GAAI,aAAoB,IAAK,OAAO,EACpC,IAAM,EAAU,IAAI,IAEpB,OADA,QAAQ,IAAI,WAAY,EAAqB,EAAQ,CAC9C,EAST,SAAgB,EAAsB,EAAqD,CACzF,IAAM,EAAW,GAAe,CAC1B,EAAM,EAAK,QAAQ,EAAS,CAClC,GAAI,EAAS,IAAI,EAAI,CAAE,OAEvB,IAAM,EAAQ,OAAO,mBAAmB,CAExC,OADA,EAAS,IAAI,EAAK,EAAM,KACX,CACP,EAAS,IAAI,EAAI,GAAK,GAAO,EAAS,OAAO,EAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./repository/repository.cjs`);require(`./syncStateContract.cjs`);let
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`./repository/repository.cjs`),n=require(`./syncLocation.cjs`);require(`./syncStateContract.cjs`);const r=require(`./syncState.cjs`);let i=require(`node:url`),a=require(`node:path`);a=e.__toESM(a,1);let o=require(`node:fs`);o=e.__toESM(o,1);let s=require(`node:os`);s=e.__toESM(s,1);function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e){return c(e)?Object.fromEntries(Object.entries(e).filter(e=>typeof e[1]==`string`)):{}}function u(e){let t=a.default.resolve(e);try{return o.default.realpathSync(t)}catch{let e=a.default.dirname(t);return e===t?t:a.default.join(u(e),a.default.basename(t))}}function d(e,t){let n=a.default.relative(u(e),u(t));return n===``||!n.startsWith(`..`)&&!a.default.isAbsolute(n)}function f(e=require(`url`).pathToFileURL(__filename).href){let t=e.endsWith(`.ts`)?`ts`:`mjs`,n=a.default.dirname(a.default.dirname((0,i.fileURLToPath)(e)));return a.default.join(n,`extensions`,`entries`,`doom.${t}`)}function p(e){return`export { default } from ${JSON.stringify((0,i.pathToFileURL)(e).href)};\n`}function m(e,t){let r=n.resolveSyncLocation(e,t);return o.default.existsSync(r.statePath)||o.default.existsSync(r.legacyStatePath)}function h(e,n=s.default.homedir()){try{if(m(e,n))return u(e);let r=t.findRepositoryRoot(e);return m(r,n)?r:void 0}catch{return}}function g(e,t=s.default.homedir()){let n=r.readLocatedSyncState(e,t);if(!n)return;let{state:i}=n,o=n.layout===`global`?n.location.statePath:n.location.legacyStatePath,c=a.default.dirname(o),u=i.bootstrap;if(u&&!d(c,u))throw Error(`Doom bootstrap must stay inside ${c}: ${u}`);let f;if(i.precompile!==void 0){if(typeof i.precompile.version!=`number`||i.precompile.strategy!==`native`&&i.precompile.strategy!==`bundle`||typeof i.precompile.bootstrapEntry!=`string`||i.precompile.bootstrapManifest!==void 0&&typeof i.precompile.bootstrapManifest!=`string`||!Array.isArray(i.precompile.manifests)||i.precompile.manifests.some(e=>typeof e!=`string`))throw Error(`Doom sync state at ${o} has an invalid precompile record`);f={version:i.precompile.version,strategy:i.precompile.strategy,bootstrapEntry:i.precompile.bootstrapEntry,bootstrapManifest:i.precompile.bootstrapManifest,manifests:i.precompile.manifests}}return{statePath:o,generatedDirectory:c,bootstrap:u,bundles:l(i.bundles),precompile:f}}function _(e,t){if(d(t,e))try{let n=JSON.parse(o.default.readFileSync(e,`utf8`));if(!c(n)||typeof n.output!=`string`||!Array.isArray(n.artifacts)||n.artifacts.some(e=>typeof e!=`string`)||!Array.isArray(n.entries)||n.entries.some(e=>typeof e!=`string`)||!Array.isArray(n.inputs))return;let r=[];for(let e of n.inputs){if(!c(e)||typeof e.path!=`string`||typeof e.size!=`number`||typeof e.mtimeMs!=`number`)return;r.push({path:e.path,size:e.size,mtimeMs:e.mtimeMs})}let i=n.artifacts,a=n.entries;return!d(t,n.output)||i.some(e=>!d(t,e))?void 0:{output:n.output,artifacts:i,entries:a,inputs:r}}catch{return}}function v(e){return!o.default.existsSync(e.output)||e.artifacts.some(e=>!o.default.existsSync(e))?!1:e.inputs.every(e=>{try{let t=o.default.statSync(e.path);return t.isFile()&&t.size===e.size&&t.mtimeMs===e.mtimeMs}catch{return!1}})}function y(e,t=f(),n=s.default.homedir()){let r=g(e,n);if(!r?.bootstrap||!r.precompile)return{bootstrap:r?.bootstrap,fresh:!1};if(r.precompile.version!==2||u(r.precompile.bootstrapEntry)!==u(t))return{bootstrap:r.bootstrap,fresh:!1};if(r.precompile.strategy===`native`){let e=Object.keys(r.bundles).length===0;try{e&&=o.default.readFileSync(r.bootstrap,`utf8`)===p(t)}catch{e=!1}return{bootstrap:r.bootstrap,fresh:e}}if(r.precompile.strategy!==`bundle`||!r.precompile.bootstrapManifest)return{bootstrap:r.bootstrap,fresh:!1};let i=[...new Set(r.precompile.manifests)];if(i.length===0||i.length!==r.precompile.manifests.length||!i.includes(r.precompile.bootstrapManifest))return{bootstrap:r.bootstrap,fresh:!1};let a=r.generatedDirectory,c=i.map(e=>_(e,a));if(c.some(e=>!e||!v(e)))return{bootstrap:r.bootstrap,fresh:!1};let l=c[i.indexOf(r.precompile.bootstrapManifest)];if(!l||l.output!==r.bootstrap||l.entries.length!==1||u(l.entries[0]??``)!==u(t))return{bootstrap:r.bootstrap,fresh:!1};let d=new Set(c.flatMap(e=>e?[e.output]:[])),m=Object.values(r.bundles).every(e=>d.has(e));return{bootstrap:r.bootstrap,fresh:m}}exports.findSyncedRoot=h,exports.readBootstrapStatus=y;
|
|
2
2
|
//# sourceMappingURL=bootstrapLocator.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapLocator.cjs","names":["path","fs","findRepositoryRoot"],"sources":["../../src/adapters/bootstrapLocator.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { findRepositoryRoot } from './repository/repository.ts';\nimport {\n BUNDLED_PRECOMPILE_STRATEGY,\n NATIVE_PRECOMPILE_STRATEGY,\n PRECOMPILE_STATE_VERSION,\n SYNC_STATE_VERSION,\n} from './syncStateContract.ts';\n\nconst STATE_PATH = path.join('.pi', 'doom', 'state.json');\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n}\n\ninterface BootstrapState {\n bootstrap?: string;\n bundles: Record<string, string>;\n precompile?: {\n version: number;\n strategy: 'native' | 'bundle';\n bootstrapEntry: string;\n bootstrapManifest?: string;\n manifests: string[];\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringRecord(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n return Object.fromEntries(\n Object.entries(value).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction canonicalPath(target: string): string {\n try {\n return fs.realpathSync(target);\n } catch {\n return path.resolve(target);\n }\n}\n\nfunction isInside(directory: string, target: string): boolean {\n const relative = path.relative(canonicalPath(directory), canonicalPath(target));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nfunction packagedDoomEntry(moduleUrl: string = import.meta.url): string {\n const extension = moduleUrl.endsWith('.ts') ? 'ts' : 'mjs';\n const sourceRoot = path.dirname(path.dirname(fileURLToPath(moduleUrl)));\n return path.join(sourceRoot, 'extensions', 'entries', `doom.${extension}`);\n}\n\nfunction nativeBootstrapSource(entry: string): string {\n return `export { default } from ${JSON.stringify(pathToFileURL(entry).href)};\\n`;\n}\n\nexport function bootstrapStatePath(repoRoot: string): string {\n return path.join(repoRoot, STATE_PATH);\n}\n\n/** Finds the nearest configured repository with generated Doom sync state. */\nexport function findSyncedRoot(cwd: string): string | undefined {\n if (fs.existsSync(bootstrapStatePath(cwd))) return cwd;\n try {\n const root = findRepositoryRoot(cwd);\n return fs.existsSync(bootstrapStatePath(root)) ? root : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readBootstrapState(repoRoot: string): BootstrapState | undefined {\n const statePath = bootstrapStatePath(repoRoot);\n if (!fs.existsSync(statePath)) return undefined;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(statePath, 'utf8'));\n } catch (error) {\n throw new Error(`Doom sync state at ${statePath} is not valid JSON`, { cause: error });\n }\n if (!isRecord(parsed)) throw new Error(`Doom sync state at ${statePath} must be an object`);\n if (parsed.version !== SYNC_STATE_VERSION) {\n throw new Error(\n `Doom sync state at ${statePath} has version ${String(parsed.version)}, expected ${SYNC_STATE_VERSION}. Run doompi sync.`,\n );\n }\n if (typeof parsed.root !== 'string' || typeof parsed.inputsHash !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires string root and inputsHash`);\n }\n if (canonicalPath(parsed.root) !== canonicalPath(repoRoot)) {\n throw new Error(`Doom sync state at ${statePath} belongs to a different repository: ${parsed.root}`);\n }\n if (!isRecord(parsed.selection) || typeof parsed.selection.majorMode !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires a selection with a majorMode`);\n }\n if (!isRecord(parsed.baseline) || typeof parsed.baseline.themePath !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires a baseline with a themePath`);\n }\n if (!isRecord(parsed.env)) throw new Error(`Doom sync state at ${statePath} requires env to be an object`);\n if (!isRecord(parsed.resolved)) throw new Error(`Doom sync state at ${statePath} requires resolved to be an object`);\n if (parsed.compiled !== undefined && !isRecord(parsed.compiled)) {\n throw new Error(`Doom sync state at ${statePath} requires compiled to be an object`);\n }\n if (parsed.bundles !== undefined && !isRecord(parsed.bundles)) {\n throw new Error(`Doom sync state at ${statePath} requires bundles to be an object`);\n }\n\n const generatedDirectory = path.dirname(statePath);\n const bootstrap = typeof parsed.bootstrap === 'string' ? parsed.bootstrap : undefined;\n if (bootstrap && !isInside(generatedDirectory, bootstrap)) {\n throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);\n }\n\n let precompile: BootstrapState['precompile'];\n if (parsed.precompile !== undefined) {\n if (\n !isRecord(parsed.precompile) ||\n typeof parsed.precompile.version !== 'number' ||\n (parsed.precompile.strategy !== NATIVE_PRECOMPILE_STRATEGY &&\n parsed.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY) ||\n typeof parsed.precompile.bootstrapEntry !== 'string' ||\n (parsed.precompile.bootstrapManifest !== undefined && typeof parsed.precompile.bootstrapManifest !== 'string') ||\n !Array.isArray(parsed.precompile.manifests) ||\n parsed.precompile.manifests.some((manifest) => typeof manifest !== 'string')\n ) {\n throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);\n }\n precompile = {\n version: parsed.precompile.version,\n strategy: parsed.precompile.strategy,\n bootstrapEntry: parsed.precompile.bootstrapEntry,\n bootstrapManifest: parsed.precompile.bootstrapManifest as string | undefined,\n manifests: parsed.precompile.manifests as string[],\n };\n }\n\n return { bootstrap, bundles: stringRecord(parsed.bundles), precompile };\n}\n\nfunction readCompilerManifest(manifestPath: string, generatedDirectory: string): CompilerManifest | undefined {\n if (!isInside(generatedDirectory, manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (\n !isRecord(parsed) ||\n typeof parsed.output !== 'string' ||\n !Array.isArray(parsed.artifacts) ||\n parsed.artifacts.some((artifact) => typeof artifact !== 'string') ||\n !Array.isArray(parsed.entries) ||\n parsed.entries.some((entry) => typeof entry !== 'string') ||\n !Array.isArray(parsed.inputs)\n ) {\n return undefined;\n }\n const inputs: InputFingerprint[] = [];\n for (const input of parsed.inputs) {\n if (\n !isRecord(input) ||\n typeof input.path !== 'string' ||\n typeof input.size !== 'number' ||\n typeof input.mtimeMs !== 'number'\n ) {\n return undefined;\n }\n inputs.push({ path: input.path, size: input.size, mtimeMs: input.mtimeMs });\n }\n const artifacts = parsed.artifacts as string[];\n const entries = parsed.entries as string[];\n if (\n !isInside(generatedDirectory, parsed.output) ||\n artifacts.some((artifact) => !isInside(generatedDirectory, artifact))\n ) {\n return undefined;\n }\n return { output: parsed.output, artifacts, entries, inputs };\n } catch {\n return undefined;\n }\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest): boolean {\n if (!fs.existsSync(manifest.output) || manifest.artifacts.some((artifact) => !fs.existsSync(artifact))) return false;\n return manifest.inputs.every((input) => {\n try {\n const stat = fs.statSync(input.path);\n return stat.isFile() && stat.size === input.size && stat.mtimeMs === input.mtimeMs;\n } catch {\n return false;\n }\n });\n}\n\n/** Reads the generated pointer and validates every compiler input without loading the compiler. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry: string = packagedDoomEntry(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot);\n if (!state?.bootstrap || !state.precompile) return { bootstrap: state?.bootstrap, fresh: false };\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n if (state.precompile.strategy === NATIVE_PRECOMPILE_STRATEGY) {\n let fresh = Object.keys(state.bundles).length === 0;\n try {\n fresh = fresh && fs.readFileSync(state.bootstrap, 'utf8') === nativeBootstrapSource(expectedBootstrapEntry);\n } catch {\n fresh = false;\n }\n return { bootstrap: state.bootstrap, fresh };\n }\n if (state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY || !state.precompile.bootstrapManifest) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const manifests = [...new Set(state.precompile.manifests)];\n if (\n manifests.length === 0 ||\n manifests.length !== state.precompile.manifests.length ||\n !manifests.includes(state.precompile.bootstrapManifest)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const generatedDirectory = path.dirname(bootstrapStatePath(repoRoot));\n const records = manifests.map((manifest) => readCompilerManifest(manifest, generatedDirectory));\n if (records.some((record) => !record || !compilerManifestIsFresh(record))) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const bootstrapIndex = manifests.indexOf(state.precompile.bootstrapManifest);\n const bootstrapRecord = records[bootstrapIndex];\n if (\n !bootstrapRecord ||\n bootstrapRecord.output !== state.bootstrap ||\n bootstrapRecord.entries.length !== 1 ||\n canonicalPath(bootstrapRecord.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n const outputs = new Set(records.flatMap((record) => (record ? [record.output] : [])));\n const fresh = Object.values(state.bundles).every((bundle) => outputs.has(bundle));\n return { bootstrap: state.bootstrap, fresh };\n}\n\n/** Reads only the generated bootstrap pointer while retaining state validation. */\nexport function readBootstrapPointer(repoRoot: string): string | undefined {\n return readBootstrapState(repoRoot)?.bootstrap;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bootstrapLocator.cjs","names":["path","fs","resolveSyncLocation","os","findRepositoryRoot","readLocatedSyncState"],"sources":["../../src/adapters/bootstrapLocator.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { findRepositoryRoot } from './repository/repository.ts';\nimport { resolveSyncLocation } from './syncLocation.ts';\nimport { readLocatedSyncState } from './syncState.ts';\nimport {\n BUNDLED_PRECOMPILE_STRATEGY,\n NATIVE_PRECOMPILE_STRATEGY,\n PRECOMPILE_STATE_VERSION,\n} from './syncStateContract.ts';\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n}\n\ninterface BootstrapState {\n statePath: string;\n generatedDirectory: string;\n bootstrap?: string;\n bundles: Record<string, string>;\n precompile?: {\n version: number;\n strategy: 'native' | 'bundle';\n bootstrapEntry: string;\n bootstrapManifest?: string;\n manifests: string[];\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringRecord(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n return Object.fromEntries(\n Object.entries(value).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction canonicalPath(target: string): string {\n const absolute = path.resolve(target);\n try {\n return fs.realpathSync(absolute);\n } catch {\n const parent = path.dirname(absolute);\n if (parent === absolute) return absolute;\n return path.join(canonicalPath(parent), path.basename(absolute));\n }\n}\n\nfunction isInside(directory: string, target: string): boolean {\n const relative = path.relative(canonicalPath(directory), canonicalPath(target));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nfunction packagedDoomEntry(moduleUrl: string = import.meta.url): string {\n const extension = moduleUrl.endsWith('.ts') ? 'ts' : 'mjs';\n const sourceRoot = path.dirname(path.dirname(fileURLToPath(moduleUrl)));\n return path.join(sourceRoot, 'extensions', 'entries', `doom.${extension}`);\n}\n\nfunction nativeBootstrapSource(entry: string): string {\n return `export { default } from ${JSON.stringify(pathToFileURL(entry).href)};\\n`;\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n const location = resolveSyncLocation(repoRoot, homeDirectory);\n return fs.existsSync(location.statePath) || fs.existsSync(location.legacyStatePath);\n}\n\n/** Finds the nearest configured repository with generated Doom sync state. */\nexport function findSyncedRoot(cwd: string, homeDirectory: string = os.homedir()): string | undefined {\n try {\n if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = findRepositoryRoot(cwd);\n return locationHasState(root, homeDirectory) ? root : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const located = readLocatedSyncState(repoRoot, homeDirectory);\n if (!located) return undefined;\n const { state } = located;\n const statePath = located.layout === 'global' ? located.location.statePath : located.location.legacyStatePath;\n const generatedDirectory = path.dirname(statePath);\n const bootstrap = state.bootstrap;\n if (bootstrap && !isInside(generatedDirectory, bootstrap)) {\n throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);\n }\n\n let precompile: BootstrapState['precompile'];\n if (state.precompile !== undefined) {\n if (\n typeof state.precompile.version !== 'number' ||\n (state.precompile.strategy !== NATIVE_PRECOMPILE_STRATEGY &&\n state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY) ||\n typeof state.precompile.bootstrapEntry !== 'string' ||\n (state.precompile.bootstrapManifest !== undefined && typeof state.precompile.bootstrapManifest !== 'string') ||\n !Array.isArray(state.precompile.manifests) ||\n state.precompile.manifests.some((manifest) => typeof manifest !== 'string')\n ) {\n throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);\n }\n precompile = {\n version: state.precompile.version,\n strategy: state.precompile.strategy,\n bootstrapEntry: state.precompile.bootstrapEntry,\n bootstrapManifest: state.precompile.bootstrapManifest,\n manifests: state.precompile.manifests,\n };\n }\n\n return {\n statePath,\n generatedDirectory,\n bootstrap,\n bundles: stringRecord(state.bundles),\n precompile,\n };\n}\n\nfunction readCompilerManifest(manifestPath: string, generatedDirectory: string): CompilerManifest | undefined {\n if (!isInside(generatedDirectory, manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (\n !isRecord(parsed) ||\n typeof parsed.output !== 'string' ||\n !Array.isArray(parsed.artifacts) ||\n parsed.artifacts.some((artifact) => typeof artifact !== 'string') ||\n !Array.isArray(parsed.entries) ||\n parsed.entries.some((entry) => typeof entry !== 'string') ||\n !Array.isArray(parsed.inputs)\n ) {\n return undefined;\n }\n const inputs: InputFingerprint[] = [];\n for (const input of parsed.inputs) {\n if (\n !isRecord(input) ||\n typeof input.path !== 'string' ||\n typeof input.size !== 'number' ||\n typeof input.mtimeMs !== 'number'\n ) {\n return undefined;\n }\n inputs.push({ path: input.path, size: input.size, mtimeMs: input.mtimeMs });\n }\n const artifacts = parsed.artifacts as string[];\n const entries = parsed.entries as string[];\n if (\n !isInside(generatedDirectory, parsed.output) ||\n artifacts.some((artifact) => !isInside(generatedDirectory, artifact))\n ) {\n return undefined;\n }\n return { output: parsed.output, artifacts, entries, inputs };\n } catch {\n return undefined;\n }\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest): boolean {\n if (!fs.existsSync(manifest.output) || manifest.artifacts.some((artifact) => !fs.existsSync(artifact))) return false;\n return manifest.inputs.every((input) => {\n try {\n const stat = fs.statSync(input.path);\n return stat.isFile() && stat.size === input.size && stat.mtimeMs === input.mtimeMs;\n } catch {\n return false;\n }\n });\n}\n\n/** Reads the generated pointer and validates every compiler input without loading the compiler. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry: string = packagedDoomEntry(),\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n if (!state?.bootstrap || !state.precompile) return { bootstrap: state?.bootstrap, fresh: false };\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n if (state.precompile.strategy === NATIVE_PRECOMPILE_STRATEGY) {\n let fresh = Object.keys(state.bundles).length === 0;\n try {\n fresh = fresh && fs.readFileSync(state.bootstrap, 'utf8') === nativeBootstrapSource(expectedBootstrapEntry);\n } catch {\n fresh = false;\n }\n return { bootstrap: state.bootstrap, fresh };\n }\n if (state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY || !state.precompile.bootstrapManifest) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const manifests = [...new Set(state.precompile.manifests)];\n if (\n manifests.length === 0 ||\n manifests.length !== state.precompile.manifests.length ||\n !manifests.includes(state.precompile.bootstrapManifest)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const generatedDirectory = state.generatedDirectory;\n const records = manifests.map((manifest) => readCompilerManifest(manifest, generatedDirectory));\n if (records.some((record) => !record || !compilerManifestIsFresh(record))) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const bootstrapIndex = manifests.indexOf(state.precompile.bootstrapManifest);\n const bootstrapRecord = records[bootstrapIndex];\n if (\n !bootstrapRecord ||\n bootstrapRecord.output !== state.bootstrap ||\n bootstrapRecord.entries.length !== 1 ||\n canonicalPath(bootstrapRecord.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n const outputs = new Set(records.flatMap((record) => (record ? [record.output] : [])));\n const fresh = Object.values(state.bundles).every((bundle) => outputs.has(bundle));\n return { bootstrap: state.bootstrap, fresh };\n}\n\n/** Reads only the generated bootstrap pointer while retaining state validation. */\nexport function readBootstrapPointer(repoRoot: string, homeDirectory: string = os.homedir()): string | undefined {\n return readBootstrapState(repoRoot, homeDirectory)?.bootstrap;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/adapters/bootstrapLocator.d.ts
|
|
2
2
|
/** Finds the nearest configured repository with generated Doom sync state. */
|
|
3
|
-
declare function findSyncedRoot(cwd: string): string | undefined;
|
|
3
|
+
declare function findSyncedRoot(cwd: string, homeDirectory?: string): string | undefined;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { findSyncedRoot };
|
|
6
6
|
//# sourceMappingURL=bootstrapLocator.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapLocator.d.cts","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"bootstrapLocator.d.cts","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"mappings":";;iBAwFgB,cAAA,CAAe,GAAA,UAAa,aAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/adapters/bootstrapLocator.d.ts
|
|
2
2
|
/** Finds the nearest configured repository with generated Doom sync state. */
|
|
3
|
-
declare function findSyncedRoot(cwd: string): string | undefined;
|
|
3
|
+
declare function findSyncedRoot(cwd: string, homeDirectory?: string): string | undefined;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { findSyncedRoot };
|
|
6
6
|
//# sourceMappingURL=bootstrapLocator.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapLocator.d.mts","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"bootstrapLocator.d.mts","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"mappings":";;iBAwFgB,cAAA,CAAe,GAAA,UAAa,aAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{findRepositoryRoot as e}from"./repository/repository.mjs";import"./syncStateContract.mjs";import{fileURLToPath as
|
|
1
|
+
import{findRepositoryRoot as e}from"./repository/repository.mjs";import{resolveSyncLocation as t}from"./syncLocation.mjs";import"./syncStateContract.mjs";import{readLocatedSyncState as n}from"./syncState.mjs";import{fileURLToPath as r,pathToFileURL as i}from"node:url";import a from"node:path";import o from"node:fs";import s from"node:os";function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e){return c(e)?Object.fromEntries(Object.entries(e).filter(e=>typeof e[1]==`string`)):{}}function u(e){let t=a.resolve(e);try{return o.realpathSync(t)}catch{let e=a.dirname(t);return e===t?t:a.join(u(e),a.basename(t))}}function d(e,t){let n=a.relative(u(e),u(t));return n===``||!n.startsWith(`..`)&&!a.isAbsolute(n)}function f(e=import.meta.url){let t=e.endsWith(`.ts`)?`ts`:`mjs`,n=a.dirname(a.dirname(r(e)));return a.join(n,`extensions`,`entries`,`doom.${t}`)}function p(e){return`export { default } from ${JSON.stringify(i(e).href)};\n`}function m(e,n){let r=t(e,n);return o.existsSync(r.statePath)||o.existsSync(r.legacyStatePath)}function h(t,n=s.homedir()){try{if(m(t,n))return u(t);let r=e(t);return m(r,n)?r:void 0}catch{return}}function g(e,t=s.homedir()){let r=n(e,t);if(!r)return;let{state:i}=r,o=r.layout===`global`?r.location.statePath:r.location.legacyStatePath,c=a.dirname(o),u=i.bootstrap;if(u&&!d(c,u))throw Error(`Doom bootstrap must stay inside ${c}: ${u}`);let f;if(i.precompile!==void 0){if(typeof i.precompile.version!=`number`||i.precompile.strategy!==`native`&&i.precompile.strategy!==`bundle`||typeof i.precompile.bootstrapEntry!=`string`||i.precompile.bootstrapManifest!==void 0&&typeof i.precompile.bootstrapManifest!=`string`||!Array.isArray(i.precompile.manifests)||i.precompile.manifests.some(e=>typeof e!=`string`))throw Error(`Doom sync state at ${o} has an invalid precompile record`);f={version:i.precompile.version,strategy:i.precompile.strategy,bootstrapEntry:i.precompile.bootstrapEntry,bootstrapManifest:i.precompile.bootstrapManifest,manifests:i.precompile.manifests}}return{statePath:o,generatedDirectory:c,bootstrap:u,bundles:l(i.bundles),precompile:f}}function _(e,t){if(d(t,e))try{let n=JSON.parse(o.readFileSync(e,`utf8`));if(!c(n)||typeof n.output!=`string`||!Array.isArray(n.artifacts)||n.artifacts.some(e=>typeof e!=`string`)||!Array.isArray(n.entries)||n.entries.some(e=>typeof e!=`string`)||!Array.isArray(n.inputs))return;let r=[];for(let e of n.inputs){if(!c(e)||typeof e.path!=`string`||typeof e.size!=`number`||typeof e.mtimeMs!=`number`)return;r.push({path:e.path,size:e.size,mtimeMs:e.mtimeMs})}let i=n.artifacts,a=n.entries;return!d(t,n.output)||i.some(e=>!d(t,e))?void 0:{output:n.output,artifacts:i,entries:a,inputs:r}}catch{return}}function v(e){return!o.existsSync(e.output)||e.artifacts.some(e=>!o.existsSync(e))?!1:e.inputs.every(e=>{try{let t=o.statSync(e.path);return t.isFile()&&t.size===e.size&&t.mtimeMs===e.mtimeMs}catch{return!1}})}function y(e,t=f(),n=s.homedir()){let r=g(e,n);if(!r?.bootstrap||!r.precompile)return{bootstrap:r?.bootstrap,fresh:!1};if(r.precompile.version!==2||u(r.precompile.bootstrapEntry)!==u(t))return{bootstrap:r.bootstrap,fresh:!1};if(r.precompile.strategy===`native`){let e=Object.keys(r.bundles).length===0;try{e&&=o.readFileSync(r.bootstrap,`utf8`)===p(t)}catch{e=!1}return{bootstrap:r.bootstrap,fresh:e}}if(r.precompile.strategy!==`bundle`||!r.precompile.bootstrapManifest)return{bootstrap:r.bootstrap,fresh:!1};let i=[...new Set(r.precompile.manifests)];if(i.length===0||i.length!==r.precompile.manifests.length||!i.includes(r.precompile.bootstrapManifest))return{bootstrap:r.bootstrap,fresh:!1};let a=r.generatedDirectory,c=i.map(e=>_(e,a));if(c.some(e=>!e||!v(e)))return{bootstrap:r.bootstrap,fresh:!1};let l=c[i.indexOf(r.precompile.bootstrapManifest)];if(!l||l.output!==r.bootstrap||l.entries.length!==1||u(l.entries[0]??``)!==u(t))return{bootstrap:r.bootstrap,fresh:!1};let d=new Set(c.flatMap(e=>e?[e.output]:[])),m=Object.values(r.bundles).every(e=>d.has(e));return{bootstrap:r.bootstrap,fresh:m}}export{h as findSyncedRoot,y as readBootstrapStatus};
|
|
2
2
|
//# sourceMappingURL=bootstrapLocator.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapLocator.mjs","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { findRepositoryRoot } from './repository/repository.ts';\nimport {\n BUNDLED_PRECOMPILE_STRATEGY,\n NATIVE_PRECOMPILE_STRATEGY,\n PRECOMPILE_STATE_VERSION,\n SYNC_STATE_VERSION,\n} from './syncStateContract.ts';\n\nconst STATE_PATH = path.join('.pi', 'doom', 'state.json');\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n}\n\ninterface BootstrapState {\n bootstrap?: string;\n bundles: Record<string, string>;\n precompile?: {\n version: number;\n strategy: 'native' | 'bundle';\n bootstrapEntry: string;\n bootstrapManifest?: string;\n manifests: string[];\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringRecord(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n return Object.fromEntries(\n Object.entries(value).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction canonicalPath(target: string): string {\n try {\n return fs.realpathSync(target);\n } catch {\n return path.resolve(target);\n }\n}\n\nfunction isInside(directory: string, target: string): boolean {\n const relative = path.relative(canonicalPath(directory), canonicalPath(target));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nfunction packagedDoomEntry(moduleUrl: string = import.meta.url): string {\n const extension = moduleUrl.endsWith('.ts') ? 'ts' : 'mjs';\n const sourceRoot = path.dirname(path.dirname(fileURLToPath(moduleUrl)));\n return path.join(sourceRoot, 'extensions', 'entries', `doom.${extension}`);\n}\n\nfunction nativeBootstrapSource(entry: string): string {\n return `export { default } from ${JSON.stringify(pathToFileURL(entry).href)};\\n`;\n}\n\nexport function bootstrapStatePath(repoRoot: string): string {\n return path.join(repoRoot, STATE_PATH);\n}\n\n/** Finds the nearest configured repository with generated Doom sync state. */\nexport function findSyncedRoot(cwd: string): string | undefined {\n if (fs.existsSync(bootstrapStatePath(cwd))) return cwd;\n try {\n const root = findRepositoryRoot(cwd);\n return fs.existsSync(bootstrapStatePath(root)) ? root : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readBootstrapState(repoRoot: string): BootstrapState | undefined {\n const statePath = bootstrapStatePath(repoRoot);\n if (!fs.existsSync(statePath)) return undefined;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(statePath, 'utf8'));\n } catch (error) {\n throw new Error(`Doom sync state at ${statePath} is not valid JSON`, { cause: error });\n }\n if (!isRecord(parsed)) throw new Error(`Doom sync state at ${statePath} must be an object`);\n if (parsed.version !== SYNC_STATE_VERSION) {\n throw new Error(\n `Doom sync state at ${statePath} has version ${String(parsed.version)}, expected ${SYNC_STATE_VERSION}. Run doompi sync.`,\n );\n }\n if (typeof parsed.root !== 'string' || typeof parsed.inputsHash !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires string root and inputsHash`);\n }\n if (canonicalPath(parsed.root) !== canonicalPath(repoRoot)) {\n throw new Error(`Doom sync state at ${statePath} belongs to a different repository: ${parsed.root}`);\n }\n if (!isRecord(parsed.selection) || typeof parsed.selection.majorMode !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires a selection with a majorMode`);\n }\n if (!isRecord(parsed.baseline) || typeof parsed.baseline.themePath !== 'string') {\n throw new Error(`Doom sync state at ${statePath} requires a baseline with a themePath`);\n }\n if (!isRecord(parsed.env)) throw new Error(`Doom sync state at ${statePath} requires env to be an object`);\n if (!isRecord(parsed.resolved)) throw new Error(`Doom sync state at ${statePath} requires resolved to be an object`);\n if (parsed.compiled !== undefined && !isRecord(parsed.compiled)) {\n throw new Error(`Doom sync state at ${statePath} requires compiled to be an object`);\n }\n if (parsed.bundles !== undefined && !isRecord(parsed.bundles)) {\n throw new Error(`Doom sync state at ${statePath} requires bundles to be an object`);\n }\n\n const generatedDirectory = path.dirname(statePath);\n const bootstrap = typeof parsed.bootstrap === 'string' ? parsed.bootstrap : undefined;\n if (bootstrap && !isInside(generatedDirectory, bootstrap)) {\n throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);\n }\n\n let precompile: BootstrapState['precompile'];\n if (parsed.precompile !== undefined) {\n if (\n !isRecord(parsed.precompile) ||\n typeof parsed.precompile.version !== 'number' ||\n (parsed.precompile.strategy !== NATIVE_PRECOMPILE_STRATEGY &&\n parsed.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY) ||\n typeof parsed.precompile.bootstrapEntry !== 'string' ||\n (parsed.precompile.bootstrapManifest !== undefined && typeof parsed.precompile.bootstrapManifest !== 'string') ||\n !Array.isArray(parsed.precompile.manifests) ||\n parsed.precompile.manifests.some((manifest) => typeof manifest !== 'string')\n ) {\n throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);\n }\n precompile = {\n version: parsed.precompile.version,\n strategy: parsed.precompile.strategy,\n bootstrapEntry: parsed.precompile.bootstrapEntry,\n bootstrapManifest: parsed.precompile.bootstrapManifest as string | undefined,\n manifests: parsed.precompile.manifests as string[],\n };\n }\n\n return { bootstrap, bundles: stringRecord(parsed.bundles), precompile };\n}\n\nfunction readCompilerManifest(manifestPath: string, generatedDirectory: string): CompilerManifest | undefined {\n if (!isInside(generatedDirectory, manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (\n !isRecord(parsed) ||\n typeof parsed.output !== 'string' ||\n !Array.isArray(parsed.artifacts) ||\n parsed.artifacts.some((artifact) => typeof artifact !== 'string') ||\n !Array.isArray(parsed.entries) ||\n parsed.entries.some((entry) => typeof entry !== 'string') ||\n !Array.isArray(parsed.inputs)\n ) {\n return undefined;\n }\n const inputs: InputFingerprint[] = [];\n for (const input of parsed.inputs) {\n if (\n !isRecord(input) ||\n typeof input.path !== 'string' ||\n typeof input.size !== 'number' ||\n typeof input.mtimeMs !== 'number'\n ) {\n return undefined;\n }\n inputs.push({ path: input.path, size: input.size, mtimeMs: input.mtimeMs });\n }\n const artifacts = parsed.artifacts as string[];\n const entries = parsed.entries as string[];\n if (\n !isInside(generatedDirectory, parsed.output) ||\n artifacts.some((artifact) => !isInside(generatedDirectory, artifact))\n ) {\n return undefined;\n }\n return { output: parsed.output, artifacts, entries, inputs };\n } catch {\n return undefined;\n }\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest): boolean {\n if (!fs.existsSync(manifest.output) || manifest.artifacts.some((artifact) => !fs.existsSync(artifact))) return false;\n return manifest.inputs.every((input) => {\n try {\n const stat = fs.statSync(input.path);\n return stat.isFile() && stat.size === input.size && stat.mtimeMs === input.mtimeMs;\n } catch {\n return false;\n }\n });\n}\n\n/** Reads the generated pointer and validates every compiler input without loading the compiler. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry: string = packagedDoomEntry(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot);\n if (!state?.bootstrap || !state.precompile) return { bootstrap: state?.bootstrap, fresh: false };\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n if (state.precompile.strategy === NATIVE_PRECOMPILE_STRATEGY) {\n let fresh = Object.keys(state.bundles).length === 0;\n try {\n fresh = fresh && fs.readFileSync(state.bootstrap, 'utf8') === nativeBootstrapSource(expectedBootstrapEntry);\n } catch {\n fresh = false;\n }\n return { bootstrap: state.bootstrap, fresh };\n }\n if (state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY || !state.precompile.bootstrapManifest) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const manifests = [...new Set(state.precompile.manifests)];\n if (\n manifests.length === 0 ||\n manifests.length !== state.precompile.manifests.length ||\n !manifests.includes(state.precompile.bootstrapManifest)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const generatedDirectory = path.dirname(bootstrapStatePath(repoRoot));\n const records = manifests.map((manifest) => readCompilerManifest(manifest, generatedDirectory));\n if (records.some((record) => !record || !compilerManifestIsFresh(record))) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const bootstrapIndex = manifests.indexOf(state.precompile.bootstrapManifest);\n const bootstrapRecord = records[bootstrapIndex];\n if (\n !bootstrapRecord ||\n bootstrapRecord.output !== state.bootstrap ||\n bootstrapRecord.entries.length !== 1 ||\n canonicalPath(bootstrapRecord.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n const outputs = new Set(records.flatMap((record) => (record ? [record.output] : [])));\n const fresh = Object.values(state.bundles).every((bundle) => outputs.has(bundle));\n return { bootstrap: state.bootstrap, fresh };\n}\n\n/** Reads only the generated bootstrap pointer while retaining state validation. */\nexport function readBootstrapPointer(repoRoot: string): string | undefined {\n return readBootstrapState(repoRoot)?.bootstrap;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bootstrapLocator.mjs","names":[],"sources":["../../src/adapters/bootstrapLocator.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { findRepositoryRoot } from './repository/repository.ts';\nimport { resolveSyncLocation } from './syncLocation.ts';\nimport { readLocatedSyncState } from './syncState.ts';\nimport {\n BUNDLED_PRECOMPILE_STRATEGY,\n NATIVE_PRECOMPILE_STRATEGY,\n PRECOMPILE_STATE_VERSION,\n} from './syncStateContract.ts';\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n}\n\ninterface BootstrapState {\n statePath: string;\n generatedDirectory: string;\n bootstrap?: string;\n bundles: Record<string, string>;\n precompile?: {\n version: number;\n strategy: 'native' | 'bundle';\n bootstrapEntry: string;\n bootstrapManifest?: string;\n manifests: string[];\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringRecord(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n return Object.fromEntries(\n Object.entries(value).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction canonicalPath(target: string): string {\n const absolute = path.resolve(target);\n try {\n return fs.realpathSync(absolute);\n } catch {\n const parent = path.dirname(absolute);\n if (parent === absolute) return absolute;\n return path.join(canonicalPath(parent), path.basename(absolute));\n }\n}\n\nfunction isInside(directory: string, target: string): boolean {\n const relative = path.relative(canonicalPath(directory), canonicalPath(target));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nfunction packagedDoomEntry(moduleUrl: string = import.meta.url): string {\n const extension = moduleUrl.endsWith('.ts') ? 'ts' : 'mjs';\n const sourceRoot = path.dirname(path.dirname(fileURLToPath(moduleUrl)));\n return path.join(sourceRoot, 'extensions', 'entries', `doom.${extension}`);\n}\n\nfunction nativeBootstrapSource(entry: string): string {\n return `export { default } from ${JSON.stringify(pathToFileURL(entry).href)};\\n`;\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n const location = resolveSyncLocation(repoRoot, homeDirectory);\n return fs.existsSync(location.statePath) || fs.existsSync(location.legacyStatePath);\n}\n\n/** Finds the nearest configured repository with generated Doom sync state. */\nexport function findSyncedRoot(cwd: string, homeDirectory: string = os.homedir()): string | undefined {\n try {\n if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = findRepositoryRoot(cwd);\n return locationHasState(root, homeDirectory) ? root : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const located = readLocatedSyncState(repoRoot, homeDirectory);\n if (!located) return undefined;\n const { state } = located;\n const statePath = located.layout === 'global' ? located.location.statePath : located.location.legacyStatePath;\n const generatedDirectory = path.dirname(statePath);\n const bootstrap = state.bootstrap;\n if (bootstrap && !isInside(generatedDirectory, bootstrap)) {\n throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);\n }\n\n let precompile: BootstrapState['precompile'];\n if (state.precompile !== undefined) {\n if (\n typeof state.precompile.version !== 'number' ||\n (state.precompile.strategy !== NATIVE_PRECOMPILE_STRATEGY &&\n state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY) ||\n typeof state.precompile.bootstrapEntry !== 'string' ||\n (state.precompile.bootstrapManifest !== undefined && typeof state.precompile.bootstrapManifest !== 'string') ||\n !Array.isArray(state.precompile.manifests) ||\n state.precompile.manifests.some((manifest) => typeof manifest !== 'string')\n ) {\n throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);\n }\n precompile = {\n version: state.precompile.version,\n strategy: state.precompile.strategy,\n bootstrapEntry: state.precompile.bootstrapEntry,\n bootstrapManifest: state.precompile.bootstrapManifest,\n manifests: state.precompile.manifests,\n };\n }\n\n return {\n statePath,\n generatedDirectory,\n bootstrap,\n bundles: stringRecord(state.bundles),\n precompile,\n };\n}\n\nfunction readCompilerManifest(manifestPath: string, generatedDirectory: string): CompilerManifest | undefined {\n if (!isInside(generatedDirectory, manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (\n !isRecord(parsed) ||\n typeof parsed.output !== 'string' ||\n !Array.isArray(parsed.artifacts) ||\n parsed.artifacts.some((artifact) => typeof artifact !== 'string') ||\n !Array.isArray(parsed.entries) ||\n parsed.entries.some((entry) => typeof entry !== 'string') ||\n !Array.isArray(parsed.inputs)\n ) {\n return undefined;\n }\n const inputs: InputFingerprint[] = [];\n for (const input of parsed.inputs) {\n if (\n !isRecord(input) ||\n typeof input.path !== 'string' ||\n typeof input.size !== 'number' ||\n typeof input.mtimeMs !== 'number'\n ) {\n return undefined;\n }\n inputs.push({ path: input.path, size: input.size, mtimeMs: input.mtimeMs });\n }\n const artifacts = parsed.artifacts as string[];\n const entries = parsed.entries as string[];\n if (\n !isInside(generatedDirectory, parsed.output) ||\n artifacts.some((artifact) => !isInside(generatedDirectory, artifact))\n ) {\n return undefined;\n }\n return { output: parsed.output, artifacts, entries, inputs };\n } catch {\n return undefined;\n }\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest): boolean {\n if (!fs.existsSync(manifest.output) || manifest.artifacts.some((artifact) => !fs.existsSync(artifact))) return false;\n return manifest.inputs.every((input) => {\n try {\n const stat = fs.statSync(input.path);\n return stat.isFile() && stat.size === input.size && stat.mtimeMs === input.mtimeMs;\n } catch {\n return false;\n }\n });\n}\n\n/** Reads the generated pointer and validates every compiler input without loading the compiler. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry: string = packagedDoomEntry(),\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n if (!state?.bootstrap || !state.precompile) return { bootstrap: state?.bootstrap, fresh: false };\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n if (state.precompile.strategy === NATIVE_PRECOMPILE_STRATEGY) {\n let fresh = Object.keys(state.bundles).length === 0;\n try {\n fresh = fresh && fs.readFileSync(state.bootstrap, 'utf8') === nativeBootstrapSource(expectedBootstrapEntry);\n } catch {\n fresh = false;\n }\n return { bootstrap: state.bootstrap, fresh };\n }\n if (state.precompile.strategy !== BUNDLED_PRECOMPILE_STRATEGY || !state.precompile.bootstrapManifest) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const manifests = [...new Set(state.precompile.manifests)];\n if (\n manifests.length === 0 ||\n manifests.length !== state.precompile.manifests.length ||\n !manifests.includes(state.precompile.bootstrapManifest)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const generatedDirectory = state.generatedDirectory;\n const records = manifests.map((manifest) => readCompilerManifest(manifest, generatedDirectory));\n if (records.some((record) => !record || !compilerManifestIsFresh(record))) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n\n const bootstrapIndex = manifests.indexOf(state.precompile.bootstrapManifest);\n const bootstrapRecord = records[bootstrapIndex];\n if (\n !bootstrapRecord ||\n bootstrapRecord.output !== state.bootstrap ||\n bootstrapRecord.entries.length !== 1 ||\n canonicalPath(bootstrapRecord.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return { bootstrap: state.bootstrap, fresh: false };\n }\n const outputs = new Set(records.flatMap((record) => (record ? [record.output] : [])));\n const fresh = Object.values(state.bundles).every((bundle) => outputs.has(bundle));\n return { bootstrap: state.bootstrap, fresh };\n}\n\n/** Reads only the generated bootstrap pointer while retaining state validation. */\nexport function readBootstrapPointer(repoRoot: string, homeDirectory: string = os.homedir()): string | undefined {\n return readBootstrapState(repoRoot, homeDirectory)?.bootstrap;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../serialization/json.cjs`);require(`../../utils/index.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`node:
|
|
1
|
+
const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../serialization/json.cjs`);require(`../../utils/index.cjs`);let n=require(`node:path`);n=e.__toESM(n,1);let r=require(`node:fs`);r=e.__toESM(r,1);let i=require(`node:os`),a=require(`node:child_process`),o=require(`node:timers/promises`),s=require(`cross-spawn`);s=e.__toESM(s,1);const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let i=(0,a.spawnSync)(e,t,{cwd:n,encoding:`utf8`,env:r});if(i.error)throw i.error;if(i.stderr&&process.stderr.write(i.stderr),i.status!==0)throw Error(`${e} exited with status ${i.status??1}`);return i.stdout.trim()}function d(e,t,n,r){let i=(0,a.spawnSync)(e,t,{cwd:n,env:r,stdio:`inherit`});if(i.error)throw i.error;if(i.status!==0)throw Error(`${e} exited with status ${i.status??1}`)}function f(e){if(!e)return 1;let t=i.constants.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=(0,s.default)(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(e){let r=t.readJson(n.default.join(e,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.default.mkdirSync(n.default.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.default.promises.mkdir(e);try{t.writeJson(n.default.join(e,l),{pid:process.pid})}catch(t){throw await r.default.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.default.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.default.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.default.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await(0,o.setTimeout)(25)}}function y(e,t){let r=n.default.relative(e,t);return r===``||!r.startsWith(`..${n.default.sep}`)&&r!==`..`&&!n.default.isAbsolute(r)}exports.acquireDirectoryLock=v,exports.forwardSignals=p,exports.isFileSystemError=g,exports.lockOwnerIsRunning=_,exports.pathInside=y,exports.runCaptured=u,exports.runChecked=d,exports.runInteractive=h,exports.signalExitCode=f,exports.waitForExit=m;
|
|
2
2
|
//# sourceMappingURL=process.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readJson as e,writeJson as t}from"../serialization/json.mjs";import"../../utils/index.mjs";import n from"node:path";import r from"node:fs";import{
|
|
1
|
+
import{readJson as e,writeJson as t}from"../serialization/json.mjs";import"../../utils/index.mjs";import n from"node:path";import r from"node:fs";import{constants as i}from"node:os";import{spawnSync as a}from"node:child_process";import{setTimeout as o}from"node:timers/promises";import s from"cross-spawn";const c=[`SIGINT`,`SIGTERM`,`SIGHUP`,`SIGQUIT`],l=`owner.json`;function u(e,t,n,r){let i=a(e,t,{cwd:n,encoding:`utf8`,env:r});if(i.error)throw i.error;if(i.stderr&&process.stderr.write(i.stderr),i.status!==0)throw Error(`${e} exited with status ${i.status??1}`);return i.stdout.trim()}function d(e,t,n,r){let i=a(e,t,{cwd:n,env:r,stdio:`inherit`});if(i.error)throw i.error;if(i.status!==0)throw Error(`${e} exited with status ${i.status??1}`)}function f(e){if(!e)return 1;let t=i.signals[e];return t?128+t:1}function p(e){let t=t=>{e.exitCode===null&&e.signalCode===null&&e.kill(t)};for(let e of c)process.on(e,t);return()=>{for(let e of c)process.removeListener(e,t)}}function m(e){return new Promise((t,n)=>{e.once(`error`,n),e.once(`exit`,(e,n)=>t(e??f(n)))})}async function h(e,t,n,r){let i=s(e,t,{cwd:n,env:r,stdio:`inherit`}),a=p(i);try{return await m(i)}finally{a()}}function g(e){return e instanceof Error&&typeof e.code==`string`}function _(t){let r=e(n.join(t,l));if(typeof r.pid!=`number`||!Number.isSafeInteger(r.pid)||r.pid<=0)return!1;try{return process.kill(r.pid,0),!0}catch(e){return!g(e)||e.code!==`ESRCH`}}async function v(e){r.mkdirSync(n.dirname(e),{recursive:!0});let i=Date.now();for(;;)try{await r.promises.mkdir(e);try{t(n.join(e,l),{pid:process.pid})}catch(t){throw await r.promises.rm(e,{recursive:!0,force:!0}),t}return()=>r.promises.rm(e,{recursive:!0,force:!0})}catch(t){if(!g(t)||t.code!==`EEXIST`)throw t;try{let t=await r.promises.stat(e);if(Date.now()-t.mtimeMs>=1e4&&!_(e)){await r.promises.rm(e,{recursive:!0,force:!0});continue}}catch(e){if(g(e)&&e.code===`ENOENT`)continue;throw e}if(Date.now()-i>=3e4)throw Error(`Timed out waiting for Antigravity state lock: ${e}`);await o(25)}}function y(e,t){let r=n.relative(e,t);return r===``||!r.startsWith(`..${n.sep}`)&&r!==`..`&&!n.isAbsolute(r)}export{v as acquireDirectoryLock,p as forwardSignals,g as isFileSystemError,_ as lockOwnerIsRunning,y as pathInside,u as runCaptured,d as runChecked,h as runInteractive,f as signalExitCode,m as waitForExit};
|
|
2
2
|
//# sourceMappingURL=process.mjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../services/extensionAssembler.cjs`),n=require(`./syncState.cjs`),r=require(`./bootstrapLocator.cjs`),i=require(`./config/harnessState.cjs`),a=require(`./resourceCollector.cjs`),o=require(`./compositionState.cjs`),s=require(`./extensionCompiler.cjs`),c=require(`./harnessContext.cjs`);let l=require(`node:url`),u=require(`node:path`);u=e.__toESM(u,1);let d=require(`node:fs`);d=e.__toESM(d,1);let f=require(`node:os`);f=e.__toESM(f,1);let p=require(`@agimon-ai/doompi-config/majorModes`),m=require(`@agimon-ai/doompi-ui/extensionName`),h=require(`@earendil-works/pi-coding-agent`),g=require(`@agimon-ai/doompi-config/harnessStore`);const _=`./matrixSwitcher.ts`,v=`doompi is configured for Pi but this repository was never synced. Run doompi sync.`,y=process.env.DOOMPI_TIMING===`1`||process.env.PI_TIMING===`1`,b={majorMode:`major-mode`,domains:`domains`,profile:`profile`,mute:`mute`},x=`layer`;function S(e){return e instanceof Error?e.message:String(e)}function C(e){try{return d.default.realpathSync(e)}catch{return u.default.resolve(e)}}function w(e,t){let{extensions:n}=(0,h.parseArgs)(e);if(!n||n.length===0)return!1;let r=new Set(Object.values(t).map(C));return n.some(e=>r.has(C(e)))}async function T(e,t,n=process.env){let r=await k(t,n),a={...i.readHarnessState({...e.env,...n}),...e.fileState,temporaryDirectory:r};(0,g.createHarnessSession)(a,{directory:r,environment:n});for(let[e,t]of Object.entries(a.profileEnvironment))n[e]===void 0&&(n[e]=t);return a}function E(e){let{unknownFlags:t}=(0,h.parseArgs)(e),n=e=>{let n=t.get(e);return typeof n==`string`&&n.trim()?n.trim():void 0},r=n(b.domains);return{majorMode:n(b.majorMode),domains:r?.split(`,`).map(e=>e.trim()).filter(Boolean),profile:n(b.profile),mute:t.get(b.mute)!==void 0,removedLayer:t.get(x)!==void 0}}function D(e){e.registerFlag(b.majorMode,{type:`string`,description:`Named major mode from .doom/modes.yaml`}),e.registerFlag(b.domains,{type:`string`,description:`Comma-separated content domains`}),e.registerFlag(b.profile,{type:`string`,description:`Persona and env from .doom/profiles.yaml`}),e.registerFlag(b.mute,{type:`boolean`,description:`Disable the notification extension`})}async function O(e,t,n,r){if(e.removedLayer&&r.push(`--${x} was replaced by --${b.majorMode}`),e.majorMode)try{let{applyMajorMode:n}=await import(_);n(t,e.majorMode,i.getHarnessState())}catch(t){r.push(`--${b.majorMode} ${e.majorMode}: ${S(t)}`)}if(e.domains&&e.domains.length>0)try{let{applyDomains:t}=await import(_);await t(e.domains,i.getHarnessState())}catch(t){r.push(`--domains ${e.domains.join(`,`)}: ${S(t)}`)}if(e.profile)try{let[{applyProfile:t},{resolveProfile:r}]=await Promise.all([import(_),import(`@agimon-ai/doompi-config/profiles`)]);await t(r(n,e.profile),i.getHarnessState())}catch(t){r.push(`--profile ${e.profile}: ${S(t)}`)}}async function k(e,t=process.env){let r=n.runDirectory(e,process.pid,t.HOME??f.default.homedir());return await d.default.promises.mkdir(r,{mode:448,recursive:!0}),i.updateHarnessState({temporaryDirectory:r},t),r}async function A(e,t=process.env){await d.default.promises.rm(n.runDirectory(e,process.pid,t.HOME??f.default.homedir()),{recursive:!0,force:!0})}async function j(e,r=i.getHarnessState(),c=process.env){let l=r.root??e.root,d=n.createMapResolvers(e.resolved,e.compiled),f=r.mcp?d.optionalPackageEntry(t.CONTEXT_PACKAGES.mcp):void 0,m={agents:r.agents,autoStop:!1,preset:e.selection.preset,mcpEntry:f,personaEntry:d.ownEntry(t.PERSONA_ENTRY),workflowExtension:a.selectWorkflowExtensionForProcess(d.optionalPackageEntry(t.CONTEXT_PACKAGES.workflow),d.optionalPackageEntry(t.CONTEXT_PACKAGES.dispatcherWorkflow),c),layers:[...r.layers],majorModesConfig:(0,p.loadMajorModesConfig)(l),resolvers:d};i.updateHarnessState({childExtensions:t.assembleChildExtensions({...m,agents:!1,mute:!0})},c),r.agents&&(c.PI_SUBAGENT_EXTRA_AGENT_DIRS=r.agentDirectories.join(u.default.delimiter),c.PI_SUBAGENT_EXTRA_SKILL_DIRS=r.skillDirectories.join(u.default.delimiter));let h=[...t.assembleExtensions({...m,mute:c[o.MUTE_ENV]===`1`})].reverse(),g=e.bundles?.[s.extensionSetKey(h)];return g?[g]:h}async function M(e,t,n){let r=[];for(let i of t){let t=performance.now(),a;try{a=await import((0,l.pathToFileURL)(i).href),y&&process.stderr.write(`[doompi:timing] import ${(performance.now()-t).toFixed(1)}ms ${i}\n`)}catch(e){n.push(`${i}: ${S(e)}`);continue}if(typeof a.default!=`function`){n.push(`${i}: does not export an extension factory`);continue}let o=performance.now();try{await a.default((0,m.withExtensionSource)(e,i)),y&&process.stderr.write(`[doompi:timing] factory ${(performance.now()-o).toFixed(1)}ms ${i}\n`),r.push(i)}catch(e){n.push(`${i}: ${S(e)}`)}}return r}async function N(e,t={}){let i=t.environment??process.env,a=[],s=i.HOME??f.default.homedir(),l=r.findSyncedRoot(t.cwd??process.cwd(),s);if(!l)return{problems:[v],stale:!1,loaded:[]};let u;try{u=n.readSyncState(l,s)}catch(e){return{problems:[S(e)],stale:!1,loaded:[]}}if(!u)return{problems:[v],stale:!1,loaded:[]};let d=t.argv??process.argv.slice(2);if(i[o.EXTERNAL_EXTENSIONS_ENV]===`1`||w(d,{...u.resolved,...u.bundles}))return{problems:[],stale:!1,loaded:[]};if(c.configurePreset({preset:u.selection.preset,piArgs:[]},i),!o.alreadyComposed(i)){i[o.COMPOSED_ENV]=`1`,await T(u,l,i);let e=E(d);e.mute&&(i[o.MUTE_ENV]=`1`),await O(e,(0,p.loadMajorModesConfig)(l),l,a)}let m;try{m=await j(u,(0,g.loadHarnessState)(i).state,i)}catch(e){return{problems:[...a,S(e)],stale:!1,loaded:[]}}let h=await M(e,m,a);return{problems:a,stale:n.computeInputsHash(l,u.selection,s)!==u.inputsHash,loaded:h}}exports.DOOM_FLAGS=b,exports.REMOVED_LAYER_FLAG=x,exports.applyStartupFlags=O,exports.cleanupRunDirectory=A,exports.composeDoomSession=N,exports.composeLoadOrder=j,exports.extensionsProvidedExternally=w,exports.loadComposedExtensions=M,exports.prepareRunDirectory=k,exports.readStartupFlags=E,exports.registerDoomFlags=D,exports.startSyncedSession=T;
|
|
2
2
|
//# sourceMappingURL=composer.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.cjs","names":["fs","path","readHarnessState","getHarnessState","runDirectory","createMapResolvers","CONTEXT_PACKAGES","PERSONA_ENTRY","selectWorkflowExtensionForProcess","assembleChildExtensions","assembleExtensions","MUTE_ENV","extensionSetKey","findSyncedRoot","readSyncState","EXTERNAL_EXTENSIONS_ENV","alreadyComposed","COMPOSED_ENV","computeInputsHash"],"sources":["../../src/adapters/composer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { loadMajorModesConfig, type MajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\nimport { withExtensionSource } from '@agimon-ai/doompi-ui/extensionName';\nimport { type ExtensionAPI, parseArgs } from '@earendil-works/pi-coding-agent';\nimport type { HarnessPreset } from '../types/interfaces/index.ts';\nimport {\n createHarnessSession,\n getHarnessState,\n type HarnessState,\n loadHarnessState,\n readHarnessState,\n updateHarnessState,\n} from './config/harnessState.ts';\nimport {\n assembleChildExtensions,\n assembleExtensions,\n CONTEXT_PACKAGES,\n PERSONA_ENTRY,\n} from '../services/extensionAssembler.ts';\nimport { extensionSetKey } from './extensionCompiler.ts';\nimport { findSyncedRoot } from './bootstrapLocator.ts';\nimport { alreadyComposed, COMPOSED_ENV, EXTERNAL_EXTENSIONS_ENV, MUTE_ENV } from './compositionState.ts';\nimport { configurePreset } from './harnessContext.ts';\nimport { selectWorkflowExtensionForProcess } from './resourceCollector.ts';\nimport { computeInputsHash, createMapResolvers, readSyncState, runDirectory, type SyncState } from './syncState.ts';\n\nexport { findSyncedRoot } from './bootstrapLocator.ts';\nexport { alreadyComposed, COMPOSED_ENV, EXTERNAL_EXTENSIONS_ENV, MUTE_ENV } from './compositionState.ts';\n\n/**\n * The runtime half of `doom-pi sync`.\n *\n * Pi's own config carries a single entry, the doom-pi extension, and this is\n * what that entry runs: hydrate the harness environment, apply the startup\n * flags, then load the extension set the matrix selects. It runs again on every\n * `/reload`, which is what lets `/mode` swap the set without a restart,\n * since Pi rebuilds its extension runner from whatever a reload produced.\n */\n\nconst ENABLED_FLAG = '1';\nconst SUBAGENT_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\nconst SUBAGENT_SKILL_DIRS_ENV = 'PI_SUBAGENT_EXTRA_SKILL_DIRS';\nconst DOMAIN_SEPARATOR = ',';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst NOT_SYNCED = 'doompi is configured for Pi but this repository was never synced. Run doompi sync.';\nconst TIMING_ENABLED = process.env.DOOMPI_TIMING === ENABLED_FLAG || process.env.PI_TIMING === ENABLED_FLAG;\n\nexport const DOOM_FLAGS = {\n majorMode: 'major-mode',\n domains: 'domains',\n profile: 'profile',\n mute: 'mute',\n} as const;\n\n/** Removed flag, reported rather than ignored when a synced session passes it. */\nexport const REMOVED_LAYER_FLAG = 'layer';\n\nexport interface StartupFlags {\n majorMode?: string;\n domains?: string[];\n profile?: string;\n mute: boolean;\n /** True when the caller passed the removed `--layer` flag. */\n removedLayer: boolean;\n}\n\nexport interface ComposeOutcome {\n /** Everything that went wrong, reported once the session can show messages. */\n problems: string[];\n /** Config changed since the last sync, which is a prompt to re-sync. */\n stale: boolean;\n loaded: string[];\n}\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction realPath(target: string): string {\n try {\n return fs.realpathSync(target);\n } catch {\n return path.resolve(target);\n }\n}\n\n/**\n * True when this process was handed the doom extension set on the command line.\n *\n * The launcher and detached Doom Team children both pass the composed list as\n * `--extension` arguments, and Pi merges those with whatever project settings\n * declare. Composing again here would load every extension twice, which Pi\n * reports as each tool and flag conflicting with itself.\n *\n * Matching against the synced paths rather than the mere presence of\n * `--extension` keeps an unrelated one-off, `pi -e ./debug.ts`, from silently\n * costing the user their whole setup.\n */\nexport function extensionsProvidedExternally(argv: string[], resolved: Record<string, string>): boolean {\n const { extensions } = parseArgs(argv);\n if (!extensions || extensions.length === 0) return false;\n const composed = new Set(Object.values(resolved).map(realPath));\n return extensions.some((entry) => composed.has(realPath(entry)));\n}\n\n/**\n * Opens this process's session from what sync pinned.\n *\n * The synced record is decoded underneath the live environment, so an inherited\n * value still wins: a launcher run, a nested session, or a CI override is more\n * specific than anything sync wrote. The result becomes the session's state\n * file, which is the authority from here on; the environment it publishes is\n * for the bash hooks and the packages that can only read one.\n */\nexport async function startSyncedSession(\n state: SyncState,\n repoRoot: string,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<HarnessState> {\n const directory = await prepareRunDirectory(repoRoot);\n const harness: HarnessState = {\n ...readHarnessState({ ...state.env, ...environment }),\n // Recorded separately because no variable carries them.\n ...state.fileState,\n temporaryDirectory: directory,\n };\n createHarnessSession(harness, { directory, environment });\n // The profile's own defaults, which the launcher applies at spawn. They are\n // recorded as a map rather than as variables so /profile can tell which ones\n // it owns when it swaps them out later.\n for (const [key, value] of Object.entries(harness.profileEnvironment)) {\n if (environment[key] === undefined) environment[key] = value;\n }\n return harness;\n}\n\n/**\n * Reads the doom flags off the command line.\n *\n * Pi collects unrecognized flags for extensions but hands their values back\n * only after every extension has loaded, which is too late to decide what to\n * load. Parsing argv with Pi's own parser keeps the value rules identical.\n */\nexport function readStartupFlags(argv: string[]): StartupFlags {\n const { unknownFlags } = parseArgs(argv);\n const text = (name: string): string | undefined => {\n const value = unknownFlags.get(name);\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n };\n const domains = text(DOOM_FLAGS.domains);\n return {\n majorMode: text(DOOM_FLAGS.majorMode),\n domains: domains\n ?.split(DOMAIN_SEPARATOR)\n .map((name) => name.trim())\n .filter(Boolean),\n profile: text(DOOM_FLAGS.profile),\n mute: unknownFlags.get(DOOM_FLAGS.mute) !== undefined,\n removedLayer: unknownFlags.get(REMOVED_LAYER_FLAG) !== undefined,\n };\n}\n\n/** Registers the flags so Pi accepts them and lists them in `pi --help`. */\nexport function registerDoomFlags(pi: Pick<ExtensionAPI, 'registerFlag'>): void {\n pi.registerFlag(DOOM_FLAGS.majorMode, {\n type: 'string',\n description: 'Named major mode from .doom/modes.yaml',\n });\n pi.registerFlag(DOOM_FLAGS.domains, { type: 'string', description: 'Comma-separated content domains' });\n pi.registerFlag(DOOM_FLAGS.profile, { type: 'string', description: 'Persona and env from .doom/profiles.yaml' });\n pi.registerFlag(DOOM_FLAGS.mute, { type: 'boolean', description: 'Disable the notification extension' });\n}\n\n/**\n * Applies the startup flags through the same switchers the slash commands use.\n *\n * A bad value is collected rather than thrown: a factory that throws takes the\n * whole doom setup down with it, which is far worse than one unapplied flag.\n */\nexport async function applyStartupFlags(\n flags: StartupFlags,\n majorModesConfig: MajorModesConfig,\n repoRoot: string,\n problems: string[],\n): Promise<void> {\n // Reported rather than ignored: Pi hands unrecognized flags to extensions, so\n // a stale `--layer dev` would otherwise start a session on the wrong mode\n // without saying anything.\n if (flags.removedLayer) problems.push(`--${REMOVED_LAYER_FLAG} was replaced by --${DOOM_FLAGS.majorMode}`);\n if (flags.majorMode) {\n try {\n const { applyMajorMode } = await import('./matrixSwitcher.ts');\n applyMajorMode(majorModesConfig, flags.majorMode, getHarnessState());\n } catch (error) {\n problems.push(`--${DOOM_FLAGS.majorMode} ${flags.majorMode}: ${message(error)}`);\n }\n }\n if (flags.domains && flags.domains.length > 0) {\n try {\n const { applyDomains } = await import('./matrixSwitcher.ts');\n await applyDomains(flags.domains, getHarnessState());\n } catch (error) {\n problems.push(`--domains ${flags.domains.join(DOMAIN_SEPARATOR)}: ${message(error)}`);\n }\n }\n if (flags.profile) {\n try {\n const [{ applyProfile }, { resolveProfile }] = await Promise.all([\n import('./matrixSwitcher.ts'),\n import('@agimon-ai/doompi-config/profiles'),\n ]);\n await applyProfile(resolveProfile(repoRoot, flags.profile), getHarnessState());\n } catch (error) {\n problems.push(`--profile ${flags.profile}: ${message(error)}`);\n }\n }\n}\n\n/**\n * Points harness state at a per-process directory before anything writes there.\n *\n * The synced directory is a baseline that every session reads; live switches\n * materialize into this one instead, so a second session in the same repository\n * cannot overwrite what the first is using.\n */\nexport async function prepareRunDirectory(\n repoRoot: string,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n const directory = runDirectory(repoRoot);\n await fs.promises.mkdir(directory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n // Through the store rather than the environment: the state file is the\n // authority, and a switcher reading a stale directory would write a live\n // session's resources into the wrong place.\n updateHarnessState({ temporaryDirectory: directory }, environment);\n return directory;\n}\n\n/** Removes this session's scratch directory. */\nexport async function cleanupRunDirectory(repoRoot: string): Promise<void> {\n await fs.promises.rm(runDirectory(repoRoot), { recursive: true, force: true });\n}\n\n/**\n * Builds the ordered list of extensions to load for the current state.\n *\n * Returns them in Pi load order. `assembleExtensions` produces the order the\n * launcher passes to Pi, where the last element becomes the first `--extension`\n * argument, so reversing here keeps that rule stated in exactly one place.\n */\nexport async function composeLoadOrder(\n state: SyncState,\n harness: HarnessState = getHarnessState(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<string[]> {\n const repoRoot = harness.root ?? state.root;\n const resolvers = createMapResolvers(state.resolved, state.compiled);\n // Resolved from the sync map rather than generated: doom-mcp reads the\n // repository and plugin layers itself, and the environment the launcher wrote\n // already tells it which plugins and allowlist this session selected.\n const mcpEntry = harness.mcp ? resolvers.optionalPackageEntry(CONTEXT_PACKAGES.mcp) : undefined;\n const context = {\n agents: harness.agents,\n // Exiting when the agent settles is a launcher decision with no synced\n // equivalent: a session started by hand is meant to stay open.\n autoStop: false,\n preset: state.selection.preset,\n mcpEntry,\n personaEntry: resolvers.ownEntry(PERSONA_ENTRY),\n workflowExtension: selectWorkflowExtensionForProcess(\n resolvers.optionalPackageEntry(CONTEXT_PACKAGES.workflow),\n resolvers.optionalPackageEntry(CONTEXT_PACKAGES.dispatcherWorkflow),\n environment,\n ),\n layers: [...harness.layers],\n majorModesConfig: loadMajorModesConfig(repoRoot),\n resolvers,\n };\n\n // A state field, so it goes through the store: Doom Team reads it from the\n // environment the store publishes when it builds a child's spawn snapshot.\n updateHarnessState(\n { childExtensions: assembleChildExtensions({ ...context, agents: false, mute: true }) },\n environment,\n );\n if (harness.agents) {\n environment[SUBAGENT_AGENT_DIRS_ENV] = harness.agentDirectories.join(path.delimiter);\n environment[SUBAGENT_SKILL_DIRS_ENV] = harness.skillDirectories.join(path.delimiter);\n }\n const entries = [...assembleExtensions({ ...context, mute: environment[MUTE_ENV] === ENABLED_FLAG })].reverse();\n const bundle = state.bundles?.[extensionSetKey(entries)];\n return bundle ? [bundle] : entries;\n}\n\n/**\n * Imports each extension and hands it a source-aware view of the Pi API.\n *\n * Every Pi extension entry is a factory of the same shape, so one extension can\n * activate the rest. The view delegates to the same host API while retaining the\n * entry path for tools registered through a composed loader. Failures are per\n * entry: one unloadable module must not cost the session everything after it.\n */\nexport async function loadComposedExtensions(\n pi: ExtensionAPI,\n entries: string[],\n problems: string[],\n): Promise<string[]> {\n const loaded: string[] = [];\n for (const entry of entries) {\n const importStartedAt = performance.now();\n let module: { default?: unknown };\n try {\n module = (await import(pathToFileURL(entry).href)) as { default?: unknown };\n if (TIMING_ENABLED) {\n process.stderr.write(`[doompi:timing] import ${(performance.now() - importStartedAt).toFixed(1)}ms ${entry}\\n`);\n }\n } catch (error) {\n problems.push(`${entry}: ${message(error)}`);\n continue;\n }\n if (typeof module.default !== 'function') {\n problems.push(`${entry}: does not export an extension factory`);\n continue;\n }\n const factoryStartedAt = performance.now();\n try {\n await (module.default as (api: ExtensionAPI) => void | Promise<void>)(withExtensionSource(pi, entry));\n if (TIMING_ENABLED) {\n process.stderr.write(\n `[doompi:timing] factory ${(performance.now() - factoryStartedAt).toFixed(1)}ms ${entry}\\n`,\n );\n }\n loaded.push(entry);\n } catch (error) {\n problems.push(`${entry}: ${message(error)}`);\n }\n }\n return loaded;\n}\n\nexport interface ComposeOptions {\n cwd?: string;\n argv?: string[];\n environment?: NodeJS.ProcessEnv;\n}\n\n/**\n * Runs the whole synced startup for one Pi session.\n *\n * Never throws: whatever fails is reported through the outcome so the session\n * still starts and can say what is wrong.\n */\nexport async function composeDoomSession(pi: ExtensionAPI, options: ComposeOptions = {}): Promise<ComposeOutcome> {\n const environment = options.environment ?? process.env;\n const problems: string[] = [];\n const repoRoot = findSyncedRoot(options.cwd ?? process.cwd());\n if (!repoRoot) return { problems: [NOT_SYNCED], stale: false, loaded: [] };\n\n let state: SyncState | undefined;\n try {\n state = readSyncState(repoRoot);\n } catch (error) {\n return { problems: [message(error)], stale: false, loaded: [] };\n }\n if (!state) return { problems: [NOT_SYNCED], stale: false, loaded: [] };\n\n const argv = options.argv ?? process.argv.slice(2);\n // The launcher and Doom Team children compose the set themselves and pass it\n // in, so this entry has nothing left to do but stay out of the way.\n if (\n environment[EXTERNAL_EXTENSIONS_ENV] === ENABLED_FLAG ||\n extensionsProvidedExternally(argv, { ...state.resolved, ...state.bundles })\n ) {\n return { problems: [], stale: false, loaded: [] };\n }\n\n configurePreset({ preset: state.selection.preset as HarnessPreset, piArgs: [] }, environment);\n\n // Only the first load opens a session. A reload finds the pointer this set\n // and reads the file back, which is what carries a live /domains or /profile\n // switch across the reload instead of resetting it to what sync pinned.\n if (!alreadyComposed(environment)) {\n environment[COMPOSED_ENV] = ENABLED_FLAG;\n await startSyncedSession(state, repoRoot, environment);\n const flags = readStartupFlags(argv);\n if (flags.mute) environment[MUTE_ENV] = ENABLED_FLAG;\n await applyStartupFlags(flags, loadMajorModesConfig(repoRoot), repoRoot, problems);\n }\n\n let entries: string[];\n try {\n // Read back through the store rather than from this process: the startup\n // flags may have switched the layer or the domains a moment ago, and the\n // environment being managed is not always this process's own.\n entries = await composeLoadOrder(state, loadHarnessState(environment).state, environment);\n } catch (error) {\n return { problems: [...problems, message(error)], stale: false, loaded: [] };\n }\n\n const loaded = await loadComposedExtensions(pi, entries, problems);\n return { problems, stale: computeInputsHash(repoRoot, state.selection) !== state.inputsHash, loaded };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"composer.cjs","names":["fs","path","readHarnessState","getHarnessState","runDirectory","os","createMapResolvers","CONTEXT_PACKAGES","PERSONA_ENTRY","selectWorkflowExtensionForProcess","assembleChildExtensions","assembleExtensions","MUTE_ENV","extensionSetKey","findSyncedRoot","readSyncState","EXTERNAL_EXTENSIONS_ENV","alreadyComposed","COMPOSED_ENV","computeInputsHash"],"sources":["../../src/adapters/composer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { loadMajorModesConfig, type MajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\nimport { withExtensionSource } from '@agimon-ai/doompi-ui/extensionName';\nimport { type ExtensionAPI, parseArgs } from '@earendil-works/pi-coding-agent';\nimport {\n assembleChildExtensions,\n assembleExtensions,\n CONTEXT_PACKAGES,\n PERSONA_ENTRY,\n} from '../services/extensionAssembler.ts';\nimport type { HarnessPreset } from '../types/interfaces/index.ts';\nimport { findSyncedRoot } from './bootstrapLocator.ts';\nimport { alreadyComposed, COMPOSED_ENV, EXTERNAL_EXTENSIONS_ENV, MUTE_ENV } from './compositionState.ts';\nimport {\n createHarnessSession,\n getHarnessState,\n type HarnessState,\n loadHarnessState,\n readHarnessState,\n updateHarnessState,\n} from './config/harnessState.ts';\nimport { extensionSetKey } from './extensionCompiler.ts';\nimport { configurePreset } from './harnessContext.ts';\nimport { selectWorkflowExtensionForProcess } from './resourceCollector.ts';\nimport { computeInputsHash, createMapResolvers, readSyncState, runDirectory, type SyncState } from './syncState.ts';\n\nexport { findSyncedRoot } from './bootstrapLocator.ts';\nexport { alreadyComposed, COMPOSED_ENV, EXTERNAL_EXTENSIONS_ENV, MUTE_ENV } from './compositionState.ts';\n\n/**\n * The runtime half of `doom-pi sync`.\n *\n * Pi's own config carries a single entry, the doom-pi extension, and this is\n * what that entry runs: hydrate the harness environment, apply the startup\n * flags, then load the extension set the matrix selects. It runs again on every\n * `/reload`, which is what lets `/mode` swap the set without a restart,\n * since Pi rebuilds its extension runner from whatever a reload produced.\n */\n\nconst ENABLED_FLAG = '1';\nconst SUBAGENT_AGENT_DIRS_ENV = 'PI_SUBAGENT_EXTRA_AGENT_DIRS';\nconst SUBAGENT_SKILL_DIRS_ENV = 'PI_SUBAGENT_EXTRA_SKILL_DIRS';\nconst DOMAIN_SEPARATOR = ',';\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst MATRIX_SWITCHER_MODULE = './matrixSwitcher.ts';\nconst NOT_SYNCED = 'doompi is configured for Pi but this repository was never synced. Run doompi sync.';\nconst TIMING_ENABLED = process.env.DOOMPI_TIMING === ENABLED_FLAG || process.env.PI_TIMING === ENABLED_FLAG;\n\nexport const DOOM_FLAGS = {\n majorMode: 'major-mode',\n domains: 'domains',\n profile: 'profile',\n mute: 'mute',\n} as const;\n\n/** Removed flag, reported rather than ignored when a synced session passes it. */\nexport const REMOVED_LAYER_FLAG = 'layer';\n\nexport interface StartupFlags {\n majorMode?: string;\n domains?: string[];\n profile?: string;\n mute: boolean;\n /** True when the caller passed the removed `--layer` flag. */\n removedLayer: boolean;\n}\n\nexport interface ComposeOutcome {\n /** Everything that went wrong, reported once the session can show messages. */\n problems: string[];\n /** Config changed since the last sync, which is a prompt to re-sync. */\n stale: boolean;\n loaded: string[];\n}\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction realPath(target: string): string {\n try {\n return fs.realpathSync(target);\n } catch {\n return path.resolve(target);\n }\n}\n\n/**\n * True when this process was handed the doom extension set on the command line.\n *\n * The launcher and detached Doom Team children both pass the composed list as\n * `--extension` arguments, and Pi merges those with whatever project settings\n * declare. Composing again here would load every extension twice, which Pi\n * reports as each tool and flag conflicting with itself.\n *\n * Matching against the synced paths rather than the mere presence of\n * `--extension` keeps an unrelated one-off, `pi -e ./debug.ts`, from silently\n * costing the user their whole setup.\n */\nexport function extensionsProvidedExternally(argv: string[], resolved: Record<string, string>): boolean {\n const { extensions } = parseArgs(argv);\n if (!extensions || extensions.length === 0) return false;\n const composed = new Set(Object.values(resolved).map(realPath));\n return extensions.some((entry) => composed.has(realPath(entry)));\n}\n\n/**\n * Opens this process's session from what sync pinned.\n *\n * The synced record is decoded underneath the live environment, so an inherited\n * value still wins: a launcher run, a nested session, or a CI override is more\n * specific than anything sync wrote. The result becomes the session's state\n * file, which is the authority from here on; the environment it publishes is\n * for the bash hooks and the packages that can only read one.\n */\nexport async function startSyncedSession(\n state: SyncState,\n repoRoot: string,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<HarnessState> {\n const directory = await prepareRunDirectory(repoRoot, environment);\n const harness: HarnessState = {\n ...readHarnessState({ ...state.env, ...environment }),\n // Recorded separately because no variable carries them.\n ...state.fileState,\n temporaryDirectory: directory,\n };\n createHarnessSession(harness, { directory, environment });\n // The profile's own defaults, which the launcher applies at spawn. They are\n // recorded as a map rather than as variables so /profile can tell which ones\n // it owns when it swaps them out later.\n for (const [key, value] of Object.entries(harness.profileEnvironment)) {\n if (environment[key] === undefined) environment[key] = value;\n }\n return harness;\n}\n\n/**\n * Reads the doom flags off the command line.\n *\n * Pi collects unrecognized flags for extensions but hands their values back\n * only after every extension has loaded, which is too late to decide what to\n * load. Parsing argv with Pi's own parser keeps the value rules identical.\n */\nexport function readStartupFlags(argv: string[]): StartupFlags {\n const { unknownFlags } = parseArgs(argv);\n const text = (name: string): string | undefined => {\n const value = unknownFlags.get(name);\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n };\n const domains = text(DOOM_FLAGS.domains);\n return {\n majorMode: text(DOOM_FLAGS.majorMode),\n domains: domains\n ?.split(DOMAIN_SEPARATOR)\n .map((name) => name.trim())\n .filter(Boolean),\n profile: text(DOOM_FLAGS.profile),\n mute: unknownFlags.get(DOOM_FLAGS.mute) !== undefined,\n removedLayer: unknownFlags.get(REMOVED_LAYER_FLAG) !== undefined,\n };\n}\n\n/** Registers the flags so Pi accepts them and lists them in `pi --help`. */\nexport function registerDoomFlags(pi: Pick<ExtensionAPI, 'registerFlag'>): void {\n pi.registerFlag(DOOM_FLAGS.majorMode, {\n type: 'string',\n description: 'Named major mode from .doom/modes.yaml',\n });\n pi.registerFlag(DOOM_FLAGS.domains, { type: 'string', description: 'Comma-separated content domains' });\n pi.registerFlag(DOOM_FLAGS.profile, { type: 'string', description: 'Persona and env from .doom/profiles.yaml' });\n pi.registerFlag(DOOM_FLAGS.mute, { type: 'boolean', description: 'Disable the notification extension' });\n}\n\n/**\n * Applies the startup flags through the same switchers the slash commands use.\n *\n * A bad value is collected rather than thrown: a factory that throws takes the\n * whole doom setup down with it, which is far worse than one unapplied flag.\n */\nexport async function applyStartupFlags(\n flags: StartupFlags,\n majorModesConfig: MajorModesConfig,\n repoRoot: string,\n problems: string[],\n): Promise<void> {\n // Reported rather than ignored: Pi hands unrecognized flags to extensions, so\n // a stale `--layer dev` would otherwise start a session on the wrong mode\n // without saying anything.\n if (flags.removedLayer) problems.push(`--${REMOVED_LAYER_FLAG} was replaced by --${DOOM_FLAGS.majorMode}`);\n if (flags.majorMode) {\n try {\n const { applyMajorMode } = await import(MATRIX_SWITCHER_MODULE);\n applyMajorMode(majorModesConfig, flags.majorMode, getHarnessState());\n } catch (error) {\n problems.push(`--${DOOM_FLAGS.majorMode} ${flags.majorMode}: ${message(error)}`);\n }\n }\n if (flags.domains && flags.domains.length > 0) {\n try {\n const { applyDomains } = await import(MATRIX_SWITCHER_MODULE);\n await applyDomains(flags.domains, getHarnessState());\n } catch (error) {\n problems.push(`--domains ${flags.domains.join(DOMAIN_SEPARATOR)}: ${message(error)}`);\n }\n }\n if (flags.profile) {\n try {\n const [{ applyProfile }, { resolveProfile }] = await Promise.all([\n import(MATRIX_SWITCHER_MODULE),\n import('@agimon-ai/doompi-config/profiles'),\n ]);\n await applyProfile(resolveProfile(repoRoot, flags.profile), getHarnessState());\n } catch (error) {\n problems.push(`--profile ${flags.profile}: ${message(error)}`);\n }\n }\n}\n\n/**\n * Points harness state at a per-process directory before anything writes there.\n *\n * The synced directory is a baseline that every session reads; live switches\n * materialize into this one instead, so a second session in the same repository\n * cannot overwrite what the first is using.\n */\nexport async function prepareRunDirectory(\n repoRoot: string,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n const directory = runDirectory(repoRoot, process.pid, environment.HOME ?? os.homedir());\n await fs.promises.mkdir(directory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n // Through the store rather than the environment: the state file is the\n // authority, and a switcher reading a stale directory would write a live\n // session's resources into the wrong place.\n updateHarnessState({ temporaryDirectory: directory }, environment);\n return directory;\n}\n\n/** Removes this session's scratch directory. */\nexport async function cleanupRunDirectory(\n repoRoot: string,\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n await fs.promises.rm(runDirectory(repoRoot, process.pid, environment.HOME ?? os.homedir()), {\n recursive: true,\n force: true,\n });\n}\n\n/**\n * Builds the ordered list of extensions to load for the current state.\n *\n * Returns them in Pi load order. `assembleExtensions` produces the order the\n * launcher passes to Pi, where the last element becomes the first `--extension`\n * argument, so reversing here keeps that rule stated in exactly one place.\n */\nexport async function composeLoadOrder(\n state: SyncState,\n harness: HarnessState = getHarnessState(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<string[]> {\n const repoRoot = harness.root ?? state.root;\n const resolvers = createMapResolvers(state.resolved, state.compiled);\n // Resolved from the sync map rather than generated: doom-mcp reads the\n // repository and plugin layers itself, and the environment the launcher wrote\n // already tells it which plugins and allowlist this session selected.\n const mcpEntry = harness.mcp ? resolvers.optionalPackageEntry(CONTEXT_PACKAGES.mcp) : undefined;\n const context = {\n agents: harness.agents,\n // Exiting when the agent settles is a launcher decision with no synced\n // equivalent: a session started by hand is meant to stay open.\n autoStop: false,\n preset: state.selection.preset,\n mcpEntry,\n personaEntry: resolvers.ownEntry(PERSONA_ENTRY),\n workflowExtension: selectWorkflowExtensionForProcess(\n resolvers.optionalPackageEntry(CONTEXT_PACKAGES.workflow),\n resolvers.optionalPackageEntry(CONTEXT_PACKAGES.dispatcherWorkflow),\n environment,\n ),\n layers: [...harness.layers],\n majorModesConfig: loadMajorModesConfig(repoRoot),\n resolvers,\n };\n\n // A state field, so it goes through the store: Doom Team reads it from the\n // environment the store publishes when it builds a child's spawn snapshot.\n updateHarnessState(\n { childExtensions: assembleChildExtensions({ ...context, agents: false, mute: true }) },\n environment,\n );\n if (harness.agents) {\n environment[SUBAGENT_AGENT_DIRS_ENV] = harness.agentDirectories.join(path.delimiter);\n environment[SUBAGENT_SKILL_DIRS_ENV] = harness.skillDirectories.join(path.delimiter);\n }\n const entries = [...assembleExtensions({ ...context, mute: environment[MUTE_ENV] === ENABLED_FLAG })].reverse();\n const bundle = state.bundles?.[extensionSetKey(entries)];\n return bundle ? [bundle] : entries;\n}\n\n/**\n * Imports each extension and hands it a source-aware view of the Pi API.\n *\n * Every Pi extension entry is a factory of the same shape, so one extension can\n * activate the rest. The view delegates to the same host API while retaining the\n * entry path for tools registered through a composed loader. Failures are per\n * entry: one unloadable module must not cost the session everything after it.\n */\nexport async function loadComposedExtensions(\n pi: ExtensionAPI,\n entries: string[],\n problems: string[],\n): Promise<string[]> {\n const loaded: string[] = [];\n for (const entry of entries) {\n const importStartedAt = performance.now();\n let module: { default?: unknown };\n try {\n module = (await import(pathToFileURL(entry).href)) as { default?: unknown };\n if (TIMING_ENABLED) {\n process.stderr.write(`[doompi:timing] import ${(performance.now() - importStartedAt).toFixed(1)}ms ${entry}\\n`);\n }\n } catch (error) {\n problems.push(`${entry}: ${message(error)}`);\n continue;\n }\n if (typeof module.default !== 'function') {\n problems.push(`${entry}: does not export an extension factory`);\n continue;\n }\n const factoryStartedAt = performance.now();\n try {\n await (module.default as (api: ExtensionAPI) => void | Promise<void>)(withExtensionSource(pi, entry));\n if (TIMING_ENABLED) {\n process.stderr.write(\n `[doompi:timing] factory ${(performance.now() - factoryStartedAt).toFixed(1)}ms ${entry}\\n`,\n );\n }\n loaded.push(entry);\n } catch (error) {\n problems.push(`${entry}: ${message(error)}`);\n }\n }\n return loaded;\n}\n\nexport interface ComposeOptions {\n cwd?: string;\n argv?: string[];\n environment?: NodeJS.ProcessEnv;\n}\n\n/**\n * Runs the whole synced startup for one Pi session.\n *\n * Never throws: whatever fails is reported through the outcome so the session\n * still starts and can say what is wrong.\n */\nexport async function composeDoomSession(pi: ExtensionAPI, options: ComposeOptions = {}): Promise<ComposeOutcome> {\n const environment = options.environment ?? process.env;\n const problems: string[] = [];\n const homeDirectory = environment.HOME ?? os.homedir();\n const repoRoot = findSyncedRoot(options.cwd ?? process.cwd(), homeDirectory);\n if (!repoRoot) return { problems: [NOT_SYNCED], stale: false, loaded: [] };\n\n let state: SyncState | undefined;\n try {\n state = readSyncState(repoRoot, homeDirectory);\n } catch (error) {\n return { problems: [message(error)], stale: false, loaded: [] };\n }\n if (!state) return { problems: [NOT_SYNCED], stale: false, loaded: [] };\n\n const argv = options.argv ?? process.argv.slice(2);\n // The launcher and Doom Team children compose the set themselves and pass it\n // in, so this entry has nothing left to do but stay out of the way.\n if (\n environment[EXTERNAL_EXTENSIONS_ENV] === ENABLED_FLAG ||\n extensionsProvidedExternally(argv, { ...state.resolved, ...state.bundles })\n ) {\n return { problems: [], stale: false, loaded: [] };\n }\n\n configurePreset({ preset: state.selection.preset as HarnessPreset, piArgs: [] }, environment);\n\n // Only the first load opens a session. A reload finds the pointer this set\n // and reads the file back, which is what carries a live /domains or /profile\n // switch across the reload instead of resetting it to what sync pinned.\n if (!alreadyComposed(environment)) {\n environment[COMPOSED_ENV] = ENABLED_FLAG;\n await startSyncedSession(state, repoRoot, environment);\n const flags = readStartupFlags(argv);\n if (flags.mute) environment[MUTE_ENV] = ENABLED_FLAG;\n await applyStartupFlags(flags, loadMajorModesConfig(repoRoot), repoRoot, problems);\n }\n\n let entries: string[];\n try {\n // Read back through the store rather than from this process: the startup\n // flags may have switched the layer or the domains a moment ago, and the\n // environment being managed is not always this process's own.\n entries = await composeLoadOrder(state, loadHarnessState(environment).state, environment);\n } catch (error) {\n return { problems: [...problems, message(error)], stale: false, loaded: [] };\n }\n\n const loaded = await loadComposedExtensions(pi, entries, problems);\n return {\n problems,\n stale: computeInputsHash(repoRoot, state.selection, homeDirectory) !== state.inputsHash,\n loaded,\n };\n}\n"],"mappings":"wrBA0CA,MAKM,EAAyB,sBACzB,EAAa,qFACb,EAAiB,QAAQ,IAAI,gBAAkB,KAAgB,QAAQ,IAAI,YAAc,IAElF,EAAa,CACxB,UAAW,aACX,QAAS,UACT,QAAS,UACT,KAAM,OACP,CAGY,EAAqB,QAmBlC,SAAS,EAAQ,EAAwB,CACvC,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAG/D,SAAS,EAAS,EAAwB,CACxC,GAAI,CACF,OAAOA,EAAAA,QAAG,aAAa,EAAO,MACxB,CACN,OAAOC,EAAAA,QAAK,QAAQ,EAAO,EAgB/B,SAAgB,EAA6B,EAAgB,EAA2C,CACtG,GAAM,CAAE,eAAA,EAAA,EAAA,WAAyB,EAAK,CACtC,GAAI,CAAC,GAAc,EAAW,SAAW,EAAG,MAAO,GACnD,IAAM,EAAW,IAAI,IAAI,OAAO,OAAO,EAAS,CAAC,IAAI,EAAS,CAAC,CAC/D,OAAO,EAAW,KAAM,GAAU,EAAS,IAAI,EAAS,EAAM,CAAC,CAAC,CAYlE,eAAsB,EACpB,EACA,EACA,EAAiC,QAAQ,IAClB,CACvB,IAAM,EAAY,MAAM,EAAoB,EAAU,EAAY,CAC5D,EAAwB,CAC5B,GAAGC,EAAAA,iBAAiB,CAAE,GAAG,EAAM,IAAK,GAAG,EAAa,CAAC,CAErD,GAAG,EAAM,UACT,mBAAoB,EACrB,EACD,EAAA,EAAA,sBAAqB,EAAS,CAAE,YAAW,cAAa,CAAC,CAIzD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAQ,mBAAmB,CAC/D,EAAY,KAAS,IAAA,KAAW,EAAY,GAAO,GAEzD,OAAO,EAUT,SAAgB,EAAiB,EAA8B,CAC7D,GAAM,CAAE,iBAAA,EAAA,EAAA,WAA2B,EAAK,CAClC,EAAQ,GAAqC,CACjD,IAAM,EAAQ,EAAa,IAAI,EAAK,CACpC,OAAO,OAAO,GAAU,UAAY,EAAM,MAAM,CAAG,EAAM,MAAM,CAAG,IAAA,IAE9D,EAAU,EAAK,EAAW,QAAQ,CACxC,MAAO,CACL,UAAW,EAAK,EAAW,UAAU,CACrC,QAAS,GACL,MAAM,IAAiB,CACxB,IAAK,GAAS,EAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ,CAClB,QAAS,EAAK,EAAW,QAAQ,CACjC,KAAM,EAAa,IAAI,EAAW,KAAK,GAAK,IAAA,GAC5C,aAAc,EAAa,IAAI,EAAmB,GAAK,IAAA,GACxD,CAIH,SAAgB,EAAkB,EAA8C,CAC9E,EAAG,aAAa,EAAW,UAAW,CACpC,KAAM,SACN,YAAa,yCACd,CAAC,CACF,EAAG,aAAa,EAAW,QAAS,CAAE,KAAM,SAAU,YAAa,kCAAmC,CAAC,CACvG,EAAG,aAAa,EAAW,QAAS,CAAE,KAAM,SAAU,YAAa,2CAA4C,CAAC,CAChH,EAAG,aAAa,EAAW,KAAM,CAAE,KAAM,UAAW,YAAa,qCAAsC,CAAC,CAS1G,eAAsB,EACpB,EACA,EACA,EACA,EACe,CAKf,GADI,EAAM,cAAc,EAAS,KAAK,KAAK,EAAmB,qBAAqB,EAAW,YAAY,CACtG,EAAM,UACR,GAAI,CACF,GAAM,CAAE,kBAAmB,MAAM,OAAO,GACxC,EAAe,EAAkB,EAAM,UAAWC,EAAAA,iBAAiB,CAAC,OAC7D,EAAO,CACd,EAAS,KAAK,KAAK,EAAW,UAAU,GAAG,EAAM,UAAU,IAAI,EAAQ,EAAM,GAAG,CAGpF,GAAI,EAAM,SAAW,EAAM,QAAQ,OAAS,EAC1C,GAAI,CACF,GAAM,CAAE,gBAAiB,MAAM,OAAO,GACtC,MAAM,EAAa,EAAM,QAASA,EAAAA,iBAAiB,CAAC,OAC7C,EAAO,CACd,EAAS,KAAK,aAAa,EAAM,QAAQ,KAAK,IAAiB,CAAC,IAAI,EAAQ,EAAM,GAAG,CAGzF,GAAI,EAAM,QACR,GAAI,CACF,GAAM,CAAC,CAAE,gBAAgB,CAAE,mBAAoB,MAAM,QAAQ,IAAI,CAC/D,OAAO,GACP,OAAO,qCACR,CAAC,CACF,MAAM,EAAa,EAAe,EAAU,EAAM,QAAQ,CAAEA,EAAAA,iBAAiB,CAAC,OACvE,EAAO,CACd,EAAS,KAAK,aAAa,EAAM,QAAQ,IAAI,EAAQ,EAAM,GAAG,EAYpE,eAAsB,EACpB,EACA,EAAiC,QAAQ,IACxB,CACjB,IAAM,EAAYC,EAAAA,aAAa,EAAU,QAAQ,IAAK,EAAY,MAAQC,EAAAA,QAAG,SAAS,CAAC,CAMvF,OALA,MAAML,EAAAA,QAAG,SAAS,MAAM,EAAW,CAAE,KAAM,IAAwB,UAAW,GAAM,CAAC,CAIrF,EAAA,mBAAmB,CAAE,mBAAoB,EAAW,CAAE,EAAY,CAC3D,EAIT,eAAsB,EACpB,EACA,EAAiC,QAAQ,IAC1B,CACf,MAAMA,EAAAA,QAAG,SAAS,GAAGI,EAAAA,aAAa,EAAU,QAAQ,IAAK,EAAY,MAAQC,EAAAA,QAAG,SAAS,CAAC,CAAE,CAC1F,UAAW,GACX,MAAO,GACR,CAAC,CAUJ,eAAsB,EACpB,EACA,EAAwBF,EAAAA,iBAAiB,CACzC,EAAiC,QAAQ,IACtB,CACnB,IAAM,EAAW,EAAQ,MAAQ,EAAM,KACjC,EAAYG,EAAAA,mBAAmB,EAAM,SAAU,EAAM,SAAS,CAI9D,EAAW,EAAQ,IAAM,EAAU,qBAAqBC,EAAAA,iBAAiB,IAAI,CAAG,IAAA,GAChF,EAAU,CACd,OAAQ,EAAQ,OAGhB,SAAU,GACV,OAAQ,EAAM,UAAU,OACxB,WACA,aAAc,EAAU,SAASC,EAAAA,cAAc,CAC/C,kBAAmBC,EAAAA,kCACjB,EAAU,qBAAqBF,EAAAA,iBAAiB,SAAS,CACzD,EAAU,qBAAqBA,EAAAA,iBAAiB,mBAAmB,CACnE,EACD,CACD,OAAQ,CAAC,GAAG,EAAQ,OAAO,CAC3B,kBAAA,EAAA,EAAA,sBAAuC,EAAS,CAChD,YACD,CAID,EAAA,mBACE,CAAE,gBAAiBG,EAAAA,wBAAwB,CAAE,GAAG,EAAS,OAAQ,GAAO,KAAM,GAAM,CAAC,CAAE,CACvF,EACD,CACG,EAAQ,SACV,EAAY,6BAA2B,EAAQ,iBAAiB,KAAKT,EAAAA,QAAK,UAAU,CACpF,EAAY,6BAA2B,EAAQ,iBAAiB,KAAKA,EAAAA,QAAK,UAAU,EAEtF,IAAM,EAAU,CAAC,GAAGU,EAAAA,mBAAmB,CAAE,GAAG,EAAS,KAAM,EAAYC,EAAAA,YAAc,IAAc,CAAC,CAAC,CAAC,SAAS,CACzG,EAAS,EAAM,UAAUC,EAAAA,gBAAgB,EAAQ,EACvD,OAAO,EAAS,CAAC,EAAO,CAAG,EAW7B,eAAsB,EACpB,EACA,EACA,EACmB,CACnB,IAAM,EAAmB,EAAE,CAC3B,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAkB,YAAY,KAAK,CACrC,EACJ,GAAI,CACF,EAAU,MAAM,QAAA,EAAA,EAAA,eAAqB,EAAM,CAAC,MACxC,GACF,QAAQ,OAAO,MAAM,2BAA2B,YAAY,KAAK,CAAG,GAAiB,QAAQ,EAAE,CAAC,KAAK,EAAM,IAAI,OAE1G,EAAO,CACd,EAAS,KAAK,GAAG,EAAM,IAAI,EAAQ,EAAM,GAAG,CAC5C,SAEF,GAAI,OAAO,EAAO,SAAY,WAAY,CACxC,EAAS,KAAK,GAAG,EAAM,wCAAwC,CAC/D,SAEF,IAAM,EAAmB,YAAY,KAAK,CAC1C,GAAI,CACF,MAAO,EAAO,SAAA,EAAA,EAAA,qBAA4E,EAAI,EAAM,CAAC,CACjG,GACF,QAAQ,OAAO,MACb,4BAA4B,YAAY,KAAK,CAAG,GAAkB,QAAQ,EAAE,CAAC,KAAK,EAAM,IACzF,CAEH,EAAO,KAAK,EAAM,OACX,EAAO,CACd,EAAS,KAAK,GAAG,EAAM,IAAI,EAAQ,EAAM,GAAG,EAGhD,OAAO,EAeT,eAAsB,EAAmB,EAAkB,EAA0B,EAAE,CAA2B,CAChH,IAAM,EAAc,EAAQ,aAAe,QAAQ,IAC7C,EAAqB,EAAE,CACvB,EAAgB,EAAY,MAAQR,EAAAA,QAAG,SAAS,CAChD,EAAWS,EAAAA,eAAe,EAAQ,KAAO,QAAQ,KAAK,CAAE,EAAc,CAC5E,GAAI,CAAC,EAAU,MAAO,CAAE,SAAU,CAAC,EAAW,CAAE,MAAO,GAAO,OAAQ,EAAE,CAAE,CAE1E,IAAI,EACJ,GAAI,CACF,EAAQC,EAAAA,cAAc,EAAU,EAAc,OACvC,EAAO,CACd,MAAO,CAAE,SAAU,CAAC,EAAQ,EAAM,CAAC,CAAE,MAAO,GAAO,OAAQ,EAAE,CAAE,CAEjE,GAAI,CAAC,EAAO,MAAO,CAAE,SAAU,CAAC,EAAW,CAAE,MAAO,GAAO,OAAQ,EAAE,CAAE,CAEvE,IAAM,EAAO,EAAQ,MAAQ,QAAQ,KAAK,MAAM,EAAE,CAGlD,GACE,EAAYC,EAAAA,2BAA6B,KACzC,EAA6B,EAAM,CAAE,GAAG,EAAM,SAAU,GAAG,EAAM,QAAS,CAAC,CAE3E,MAAO,CAAE,SAAU,EAAE,CAAE,MAAO,GAAO,OAAQ,EAAE,CAAE,CAQnD,GALA,EAAA,gBAAgB,CAAE,OAAQ,EAAM,UAAU,OAAyB,OAAQ,EAAE,CAAE,CAAE,EAAY,CAKzF,CAACC,EAAAA,gBAAgB,EAAY,CAAE,CACjC,EAAYC,EAAAA,cAAgB,IAC5B,MAAM,EAAmB,EAAO,EAAU,EAAY,CACtD,IAAM,EAAQ,EAAiB,EAAK,CAChC,EAAM,OAAM,EAAYN,EAAAA,UAAY,KACxC,MAAM,EAAkB,GAAA,EAAA,EAAA,sBAA4B,EAAS,CAAE,EAAU,EAAS,CAGpF,IAAI,EACJ,GAAI,CAIF,EAAU,MAAM,EAAiB,GAAA,EAAA,EAAA,kBAAwB,EAAY,CAAC,MAAO,EAAY,OAClF,EAAO,CACd,MAAO,CAAE,SAAU,CAAC,GAAG,EAAU,EAAQ,EAAM,CAAC,CAAE,MAAO,GAAO,OAAQ,EAAE,CAAE,CAG9E,IAAM,EAAS,MAAM,EAAuB,EAAI,EAAS,EAAS,CAClE,MAAO,CACL,WACA,MAAOO,EAAAA,kBAAkB,EAAU,EAAM,UAAW,EAAc,GAAK,EAAM,WAC7E,SACD"}
|
|
@@ -78,7 +78,7 @@ declare function applyStartupFlags(flags: StartupFlags, majorModesConfig: MajorM
|
|
|
78
78
|
*/
|
|
79
79
|
declare function prepareRunDirectory(repoRoot: string, environment?: NodeJS.ProcessEnv): Promise<string>;
|
|
80
80
|
/** Removes this session's scratch directory. */
|
|
81
|
-
declare function cleanupRunDirectory(repoRoot: string): Promise<void>;
|
|
81
|
+
declare function cleanupRunDirectory(repoRoot: string, environment?: NodeJS.ProcessEnv): Promise<void>;
|
|
82
82
|
/**
|
|
83
83
|
* Builds the ordered list of extensions to load for the current state.
|
|
84
84
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.d.cts","names":[],"sources":["../../src/adapters/composer.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"composer.d.cts","names":[],"sources":["../../src/adapters/composer.ts"],"mappings":";;;;;;;;cAmDa,UAAA;EAAA;;;;;;cAQA,kBAAA;AAAA,UAEI,YAAA;EACf,SAAA;EACA,OAAA;EACA,OAAA;EACA,IAAA;EAN6B;EAQ7B,YAAA;AAAA;AAAA,UAGe,cAAA;EATA;EAWf,QAAA;;EAEA,KAAA;EACA,MAAA;AAAA;;;;;;AALF;;;;;;;iBAgCgB,4BAAA,CAA6B,IAAA,YAAgB,QAAA,EAAU,MAAA;;AAAvE;;;;;;;;iBAgBsB,kBAAA,CACpB,KAAA,EAAO,SAAA,EACP,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA,CAAQ,YAAA;AAJX;;;;;;;AAAA,iBA6BgB,gBAAA,CAAiB,IAAA,aAAiB,YAAA;;iBAoBlC,iBAAA,CAAkB,EAAA,EAAI,IAAA,CAAK,YAAA;;;;;;;iBAgBrB,iBAAA,CACpB,KAAA,EAAO,YAAA,EACP,gBAAA,EAAkB,gBAAA,EAClB,QAAA,UACA,QAAA,aACC,OAAA;;;AAzCH;;;;;iBAkFsB,mBAAA,CACpB,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;iBAWmB,mBAAA,CACpB,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;;;;;;AA/DH;iBA6EsB,gBAAA,CACpB,KAAA,EAAO,SAAA,EACP,OAAA,GAAS,YAAA,EACT,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;;;;;;;;iBAgDmB,sBAAA,CACpB,EAAA,EAAI,YAAA,EACJ,OAAA,YACA,QAAA,aACC,OAAA;AAAA,UAkCc,cAAA;EACf,GAAA;EACA,IAAA;EACA,WAAA,GAAc,MAAA,CAAO,UAAA;AAAA;;AA5HvB;;;;;iBAqIsB,kBAAA,CAAmB,EAAA,EAAI,YAAA,EAAc,OAAA,GAAS,cAAA,GAAsB,OAAA,CAAQ,cAAA"}
|
|
@@ -78,7 +78,7 @@ declare function applyStartupFlags(flags: StartupFlags, majorModesConfig: MajorM
|
|
|
78
78
|
*/
|
|
79
79
|
declare function prepareRunDirectory(repoRoot: string, environment?: NodeJS.ProcessEnv): Promise<string>;
|
|
80
80
|
/** Removes this session's scratch directory. */
|
|
81
|
-
declare function cleanupRunDirectory(repoRoot: string): Promise<void>;
|
|
81
|
+
declare function cleanupRunDirectory(repoRoot: string, environment?: NodeJS.ProcessEnv): Promise<void>;
|
|
82
82
|
/**
|
|
83
83
|
* Builds the ordered list of extensions to load for the current state.
|
|
84
84
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.d.mts","names":[],"sources":["../../src/adapters/composer.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"composer.d.mts","names":[],"sources":["../../src/adapters/composer.ts"],"mappings":";;;;;;;;cAmDa,UAAA;EAAA;;;;;;cAQA,kBAAA;AAAA,UAEI,YAAA;EACf,SAAA;EACA,OAAA;EACA,OAAA;EACA,IAAA;EAN6B;EAQ7B,YAAA;AAAA;AAAA,UAGe,cAAA;EATA;EAWf,QAAA;;EAEA,KAAA;EACA,MAAA;AAAA;;;;;;AALF;;;;;;;iBAgCgB,4BAAA,CAA6B,IAAA,YAAgB,QAAA,EAAU,MAAA;;AAAvE;;;;;;;;iBAgBsB,kBAAA,CACpB,KAAA,EAAO,SAAA,EACP,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA,CAAQ,YAAA;AAJX;;;;;;;AAAA,iBA6BgB,gBAAA,CAAiB,IAAA,aAAiB,YAAA;;iBAoBlC,iBAAA,CAAkB,EAAA,EAAI,IAAA,CAAK,YAAA;;;;;;;iBAgBrB,iBAAA,CACpB,KAAA,EAAO,YAAA,EACP,gBAAA,EAAkB,gBAAA,EAClB,QAAA,UACA,QAAA,aACC,OAAA;;;AAzCH;;;;;iBAkFsB,mBAAA,CACpB,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;iBAWmB,mBAAA,CACpB,QAAA,UACA,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;;;;;;AA/DH;iBA6EsB,gBAAA,CACpB,KAAA,EAAO,SAAA,EACP,OAAA,GAAS,YAAA,EACT,WAAA,GAAa,MAAA,CAAO,UAAA,GACnB,OAAA;;;;;;;;;iBAgDmB,sBAAA,CACpB,EAAA,EAAI,YAAA,EACJ,OAAA,YACA,QAAA,aACC,OAAA;AAAA,UAkCc,cAAA;EACf,GAAA;EACA,IAAA;EACA,WAAA,GAAc,MAAA,CAAO,UAAA;AAAA;;AA5HvB;;;;;iBAqIsB,kBAAA,CAAmB,EAAA,EAAI,YAAA,EAAc,OAAA,GAAS,cAAA,GAAsB,OAAA,CAAQ,cAAA"}
|