@agimon-ai/doompi 0.0.1-alpha.90 → 0.0.1-alpha.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/src/builders/cli/bootstrapLocator/index.cjs +18 -11
  2. package/dist/src/builders/cli/bootstrapLocator/index.cjs.map +1 -1
  3. package/dist/src/builders/cli/bootstrapLocator/index.d.mts +1 -0
  4. package/dist/src/builders/cli/bootstrapLocator/index.d.mts.map +1 -1
  5. package/dist/src/builders/cli/bootstrapLocator/index.mjs +19 -13
  6. package/dist/src/builders/cli/bootstrapLocator/index.mjs.map +1 -1
  7. package/dist/src/builders/server/logSink.cjs +57 -0
  8. package/dist/src/builders/server/logSink.cjs.map +1 -0
  9. package/dist/src/builders/server/logSink.mjs +57 -0
  10. package/dist/src/builders/server/logSink.mjs.map +1 -0
  11. package/dist/src/builders/server/mcpApp.cjs +120 -0
  12. package/dist/src/builders/server/mcpApp.cjs.map +1 -0
  13. package/dist/src/builders/server/mcpApp.mjs +116 -0
  14. package/dist/src/builders/server/mcpApp.mjs.map +1 -0
  15. package/dist/src/builders/server/mcpBundle.cjs +25 -1
  16. package/dist/src/builders/server/mcpBundle.cjs.map +1 -1
  17. package/dist/src/builders/server/mcpBundle.mjs +25 -1
  18. package/dist/src/builders/server/mcpBundle.mjs.map +1 -1
  19. package/dist/src/builders/server/runtime.cjs +170 -68
  20. package/dist/src/builders/server/runtime.cjs.map +1 -1
  21. package/dist/src/builders/server/runtime.mjs +170 -68
  22. package/dist/src/builders/server/runtime.mjs.map +1 -1
  23. package/dist/src/builders/server/sessionArtifact.cjs +11 -0
  24. package/dist/src/builders/server/sessionArtifact.cjs.map +1 -0
  25. package/dist/src/builders/server/sessionArtifact.mjs +11 -0
  26. package/dist/src/builders/server/sessionArtifact.mjs.map +1 -0
  27. package/dist/src/cli/commands/sync/index.cjs +3 -1
  28. package/dist/src/cli/commands/sync/index.cjs.map +1 -1
  29. package/dist/src/cli/commands/sync/index.mjs +3 -1
  30. package/dist/src/cli/commands/sync/index.mjs.map +1 -1
  31. package/dist/src/composition/layerPackageInstaller/index.cjs +1 -1
  32. package/dist/src/composition/layerPackageInstaller/index.cjs.map +1 -1
  33. package/dist/src/composition/layerPackageInstaller/index.mjs +1 -1
  34. package/dist/src/composition/layerPackageInstaller/index.mjs.map +1 -1
  35. package/dist/src/composition/syncDrift/index.cjs +5 -0
  36. package/dist/src/composition/syncDrift/index.cjs.map +1 -1
  37. package/dist/src/composition/syncDrift/index.d.mts +1 -1
  38. package/dist/src/composition/syncDrift/index.d.mts.map +1 -1
  39. package/dist/src/composition/syncDrift/index.mjs +5 -0
  40. package/dist/src/composition/syncDrift/index.mjs.map +1 -1
  41. package/dist/src/composition/syncState/index.cjs +12 -5
  42. package/dist/src/composition/syncState/index.cjs.map +1 -1
  43. package/dist/src/composition/syncState/index.d.mts +3 -0
  44. package/dist/src/composition/syncState/index.d.mts.map +1 -1
  45. package/dist/src/composition/syncState/index.mjs +13 -7
  46. package/dist/src/composition/syncState/index.mjs.map +1 -1
  47. package/dist/syncState.cjs +1 -0
  48. package/dist/syncState.d.mts +2 -2
  49. package/dist/syncState.mjs +2 -2
  50. package/package.json +25 -19
@@ -19,10 +19,6 @@ const SHA256 = /^[a-f0-9]{64}$/u;
19
19
  function isRecord(value) {
20
20
  return typeof value === "object" && value !== null && !Array.isArray(value);
21
21
  }
22
- function stringRecord(value) {
23
- if (!isRecord(value)) return {};
24
- return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
25
- }
26
22
  function canonicalPath(target) {
27
23
  const absolute = node_path.default.resolve(target);
28
24
  try {
@@ -54,19 +50,16 @@ function findSyncedRoot(cwd, homeDirectory = node_os.default.homedir()) {
54
50
  const root = require_index.resolveDoomConfigurationRoot(cwd, homeDirectory);
55
51
  return locationHasState(root, homeDirectory) ? canonicalPath(root) : void 0;
56
52
  }
57
- function readBootstrapState(repoRoot, homeDirectory = node_os.default.homedir()) {
58
- const registration = (0, _agimon_ai_doompi_core_syncRegistration.readSyncRegistration)(repoRoot, homeDirectory);
59
- if (!registration) return void 0;
53
+ function readBootstrapStateFromRegistration(registration, homeDirectory = node_os.default.homedir()) {
60
54
  const statePath = registration.statePath;
61
55
  const generatedDirectory = registration.generationRoot;
62
- const state = require_index$1.readSyncState(repoRoot, homeDirectory);
63
- if (!state) return void 0;
56
+ const state = require_index$1.readRegisteredSyncState(registration, homeDirectory);
64
57
  const bootstrap = typeof state.bootstrap === "string" ? state.bootstrap : void 0;
65
58
  if (bootstrap && !isInside(generatedDirectory, bootstrap)) throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);
66
59
  let precompile;
67
60
  if (state.precompile !== void 0) {
68
61
  const value = state.precompile;
69
- if (!isRecord(value) || typeof value.version !== "number" || value.strategy !== _agimon_ai_doompi_core_syncStateContract.BUNDLED_PRECOMPILE_STRATEGY || typeof value.bootstrapEntry !== "string" || typeof value.bootstrapManifest !== "string" || !isRecord(value.bundleManifests) || Object.values(value.bundleManifests).some((manifest) => typeof manifest !== "string")) throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);
62
+ if (value.version !== _agimon_ai_doompi_core_syncStateContract.PRECOMPILE_STATE_VERSION || value.strategy !== _agimon_ai_doompi_core_syncStateContract.BUNDLED_PRECOMPILE_STRATEGY || typeof value.bootstrapEntry !== "string" || typeof value.bootstrapManifest !== "string" || !isRecord(value.bundleManifests) || Object.values(value.bundleManifests).some((manifest) => typeof manifest !== "string")) throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);
70
63
  precompile = {
71
64
  version: value.version,
72
65
  strategy: value.strategy,
@@ -79,10 +72,14 @@ function readBootstrapState(repoRoot, homeDirectory = node_os.default.homedir())
79
72
  statePath,
80
73
  generatedDirectory,
81
74
  bootstrap,
82
- bundles: stringRecord(state.bundles),
75
+ bundles: state.bundles ?? {},
83
76
  precompile
84
77
  };
85
78
  }
79
+ function readBootstrapState(repoRoot, homeDirectory = node_os.default.homedir()) {
80
+ const registration = (0, _agimon_ai_doompi_core_syncRegistration.readSyncRegistration)(repoRoot, homeDirectory);
81
+ return registration ? readBootstrapStateFromRegistration(registration, homeDirectory) : void 0;
82
+ }
86
83
  function readCompilerManifest(manifestPath, generatedDirectory) {
87
84
  if (!isInside(generatedDirectory, manifestPath)) return void 0;
88
85
  try {
@@ -156,6 +153,15 @@ function readStartupBootstrapStatus(repoRoot, expectedBootstrapEntry, homeDirect
156
153
  fresh: usableBootstrapRecord(state, expected) !== void 0
157
154
  };
158
155
  }
156
+ /** Validates the bootstrap owned by one exact immutable registration. */
157
+ function readRegisteredBootstrapStatus(registration, expectedBootstrapEntry, homeDirectory = node_os.default.homedir()) {
158
+ const state = readBootstrapStateFromRegistration(registration, homeDirectory);
159
+ const expected = expectedBootstrapEntry ?? packagedDoomEntry();
160
+ return {
161
+ bootstrap: state.bootstrap,
162
+ fresh: usableBootstrapRecord(state, expected) !== void 0
163
+ };
164
+ }
159
165
  /** Validates one selected composition without touching any inactive bundle inputs. */
160
166
  function readBundleStatus(repoRoot, compositionFingerprint, homeDirectory = node_os.default.homedir()) {
161
167
  const state = readBootstrapState(repoRoot, homeDirectory);
@@ -199,6 +205,7 @@ function readBootstrapStatus(repoRoot, expectedBootstrapEntry, homeDirectory = n
199
205
  exports.findSyncedRoot = findSyncedRoot;
200
206
  exports.readBootstrapStatus = readBootstrapStatus;
201
207
  exports.readBundleStatus = readBundleStatus;
208
+ exports.readRegisteredBootstrapStatus = readRegisteredBootstrapStatus;
202
209
  exports.readStartupBootstrapStatus = readStartupBootstrapStatus;
203
210
 
204
211
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["path","fs","parseInputFingerprint","ownEntry","readSyncRegistration","os","resolveDoomConfigurationRoot","readSyncState","BUNDLED_PRECOMPILE_STRATEGY","crypto","inputsAreFresh","PRECOMPILE_STATE_VERSION"],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport { BUNDLED_PRECOMPILE_STRATEGY, PRECOMPILE_STATE_VERSION } from '@agimon-ai/doompi-core/syncStateContract';\n\nimport { inputsAreFresh, parseInputFingerprint, type InputFingerprint } from '../../../compiler/inputs';\nimport { EXTENSION_COMPILER_VERSION } from '../../../compiler/version';\nimport { resolveDoomConfigurationRoot } from '../../../composition/repository';\nimport { readSyncState } from '../../../composition/syncState';\nimport { ownEntry } from '../entryResolution';\n\nconst BOOTSTRAP_ENTRY_ENV = 'DOOMPI_BOOTSTRAP_ENTRY';\nconst SHA256 = /^[a-f0-9]{64}$/u;\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n artifactInputs?: 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: 'bundle';\n bootstrapEntry: string;\n bootstrapManifest: string;\n bundleManifests: Record<string, string>;\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nexport interface BundleStatus {\n bundle?: 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 parseFingerprints(value: unknown): InputFingerprint[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const fingerprints = value.map(parseInputFingerprint);\n return fingerprints.some((fingerprint) => fingerprint === undefined)\n ? undefined\n : (fingerprints as InputFingerprint[]);\n}\n\nfunction packagedDoomEntry(): string {\n return process.env[BOOTSTRAP_ENTRY_ENV] || ownEntry('composedPi');\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n return readSyncRegistration(repoRoot, homeDirectory) !== undefined;\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 if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = resolveDoomConfigurationRoot(cwd, homeDirectory);\n return locationHasState(root, homeDirectory) ? canonicalPath(root) : undefined;\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const registration = readSyncRegistration(repoRoot, homeDirectory);\n if (!registration) return undefined;\n const statePath = registration.statePath;\n const generatedDirectory = registration.generationRoot;\n const state = readSyncState(repoRoot, homeDirectory);\n if (!state) return undefined;\n const bootstrap = typeof state.bootstrap === 'string' ? state.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 (state.precompile !== undefined) {\n const value = state.precompile;\n if (\n !isRecord(value) ||\n typeof value.version !== 'number' ||\n value.strategy !== BUNDLED_PRECOMPILE_STRATEGY ||\n typeof value.bootstrapEntry !== 'string' ||\n typeof value.bootstrapManifest !== 'string' ||\n !isRecord(value.bundleManifests) ||\n Object.values(value.bundleManifests).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: value.version,\n strategy: value.strategy,\n bootstrapEntry: value.bootstrapEntry,\n bootstrapManifest: value.bootstrapManifest,\n bundleManifests: value.bundleManifests as Record<string, string>,\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 parsed.version !== EXTENSION_COMPILER_VERSION ||\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 (parsed.artifactInputs !== undefined && !Array.isArray(parsed.artifactInputs))\n ) {\n return undefined;\n }\n const inputs = parseFingerprints(parsed.inputs);\n const artifactInputs = parsed.artifactInputs === undefined ? undefined : parseFingerprints(parsed.artifactInputs);\n if (!inputs || (parsed.artifactInputs !== undefined && !artifactInputs)) return undefined;\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, ...(artifactInputs ? { artifactInputs } : {}) };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactInputsAreIntact(manifest: CompilerManifest, generatedDirectory: string): boolean {\n try {\n if (!manifest.artifactInputs || manifest.artifactInputs.length === 0) return false;\n const expected = new Set([manifest.output, ...manifest.artifacts].map(canonicalPath));\n const seen = new Set<string>();\n for (const input of manifest.artifactInputs) {\n if (!SHA256.test(input.sha256) || !isInside(generatedDirectory, input.path)) return false;\n const target = canonicalPath(input.path);\n if (!expected.has(target)) return false;\n const stat = fs.statSync(target);\n if (!stat.isFile() || stat.size !== input.size) return false;\n if (crypto.createHash('sha256').update(fs.readFileSync(target)).digest('hex') !== input.sha256) return false;\n seen.add(target);\n }\n return seen.size === expected.size;\n } catch {\n return false;\n }\n}\n\nfunction compilerManifestIsUsable(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return artifactInputsAreIntact(manifest, generatedDirectory);\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return compilerManifestIsUsable(manifest, generatedDirectory) && inputsAreFresh(manifest.inputs);\n}\n\nfunction bootstrapRecord(\n state: BootstrapState,\n expectedBootstrapEntry: string,\n requireFreshInputs: boolean,\n): CompilerManifest | undefined {\n if (!state.bootstrap || !state.precompile) return undefined;\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n const record = readCompilerManifest(state.precompile.bootstrapManifest, state.generatedDirectory);\n if (\n !record ||\n !compilerManifestIsUsable(record, state.generatedDirectory) ||\n (requireFreshInputs && !compilerManifestIsFresh(record, state.generatedDirectory)) ||\n record.output !== state.bootstrap ||\n record.entries.length !== 1 ||\n canonicalPath(record.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n return record;\n}\n\nfunction usableBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, false);\n}\n\nfunction freshBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, true);\n}\n\n/** Validates only the bootstrap graph needed before the generated bootstrap is imported. */\nexport function readStartupBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state) return { bootstrap: undefined, fresh: false };\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates one selected composition without touching any inactive bundle inputs. */\nexport function readBundleStatus(\n repoRoot: string,\n compositionFingerprint: string,\n homeDirectory: string = os.homedir(),\n): BundleStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const bundle = state?.bundles[compositionFingerprint];\n const manifestPath = state?.precompile?.bundleManifests[compositionFingerprint];\n if (!state || state.precompile?.version !== PRECOMPILE_STATE_VERSION || !bundle || !manifestPath) {\n return { bundle, fresh: false };\n }\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return {\n bundle,\n fresh: Boolean(\n manifest && manifest.output === bundle && compilerManifestIsUsable(manifest, state.generatedDirectory),\n ),\n };\n}\n\n/** Validates the bootstrap and every bundle for `doompi sync --check` diagnostics. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state?.bootstrap || !state.precompile || !freshBootstrapRecord(state, expected)) {\n return { bootstrap: state?.bootstrap, fresh: false };\n }\n const manifests = Object.values(state.precompile.bundleManifests);\n if (new Set(manifests).size !== manifests.length) return { bootstrap: state.bootstrap, fresh: false };\n const fresh = Object.entries(state.bundles).every(([fingerprint, bundle]) => {\n const manifestPath = state.precompile?.bundleManifests[fingerprint];\n if (!manifestPath) return false;\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return Boolean(\n manifest && manifest.output === bundle && compilerManifestIsFresh(manifest, state.generatedDirectory),\n );\n });\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":";;;;;;;;;;;;;;;;AAcA,MAAM,sBAAsB;AAC5B,MAAM,SAAS;AAkCf,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,aAAa,OAAwC;CAC5D,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO,CAAC;CAC9B,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,UAAqC,OAAO,MAAM,OAAO,QAAQ,CACjG;AACF;AAEA,SAAS,cAAc,QAAwB;CAC7C,MAAM,WAAWA,UAAAA,QAAK,QAAQ,MAAM;CACpC,IAAI;EACF,OAAOC,QAAAA,QAAG,aAAa,QAAQ;CACjC,QAAQ;EACN,MAAM,SAASD,UAAAA,QAAK,QAAQ,QAAQ;EACpC,IAAI,WAAW,UAAU,OAAO;EAChC,OAAOA,UAAAA,QAAK,KAAK,cAAc,MAAM,GAAGA,UAAAA,QAAK,SAAS,QAAQ,CAAC;CACjE;AACF;AAEA,SAAS,SAAS,WAAmB,QAAyB;CAC5D,MAAM,WAAWA,UAAAA,QAAK,SAAS,cAAc,SAAS,GAAG,cAAc,MAAM,CAAC;CAC9E,OAAO,aAAa,MAAO,CAAC,SAAS,WAAW,IAAI,KAAK,CAACA,UAAAA,QAAK,WAAW,QAAQ;AACpF;AAEA,SAAS,kBAAkB,OAAgD;CACzE,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;CAClC,MAAM,eAAe,MAAM,IAAIE,eAAAA,qBAAqB;CACpD,OAAO,aAAa,MAAM,gBAAgB,gBAAgB,KAAA,CAAS,IAC/D,KAAA,IACC;AACP;AAEA,SAAS,oBAA4B;CACnC,OAAO,QAAQ,IAAI,wBAAwBC,wBAAAA,SAAS,YAAY;AAClE;AAEA,SAAS,iBAAiB,UAAkB,eAAgC;CAC1E,QAAA,GAAOC,wCAAAA,qBAAAA,CAAqB,UAAU,aAAa,MAAM,KAAA;AAC3D;;AAGA,SAAgB,eAAe,KAAa,gBAAwBC,QAAAA,QAAG,QAAQ,GAAuB;CACpG,IAAI,iBAAiB,KAAK,aAAa,GAAG,OAAO,cAAc,GAAG;CAClE,MAAM,OAAOC,cAAAA,6BAA6B,KAAK,aAAa;CAC5D,OAAO,iBAAiB,MAAM,aAAa,IAAI,cAAc,IAAI,IAAI,KAAA;AACvE;AAEA,SAAS,mBAAmB,UAAkB,gBAAwBD,QAAAA,QAAG,QAAQ,GAA+B;CAC9G,MAAM,gBAAA,GAAeD,wCAAAA,qBAAAA,CAAqB,UAAU,aAAa;CACjE,IAAI,CAAC,cAAc,OAAO,KAAA;CAC1B,MAAM,YAAY,aAAa;CAC/B,MAAM,qBAAqB,aAAa;CACxC,MAAM,QAAQG,gBAAAA,cAAc,UAAU,aAAa;CACnD,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,MAAM,YAAY,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY,KAAA;CAC1E,IAAI,aAAa,CAAC,SAAS,oBAAoB,SAAS,GACtD,MAAM,IAAI,MAAM,mCAAmC,mBAAmB,IAAI,WAAW;CAGvF,IAAI;CACJ,IAAI,MAAM,eAAe,KAAA,GAAW;EAClC,MAAM,QAAQ,MAAM;EACpB,IACE,CAAC,SAAS,KAAK,KACf,OAAO,MAAM,YAAY,YACzB,MAAM,aAAaC,yCAAAA,+BACnB,OAAO,MAAM,mBAAmB,YAChC,OAAO,MAAM,sBAAsB,YACnC,CAAC,SAAS,MAAM,eAAe,KAC/B,OAAO,OAAO,MAAM,eAAe,CAAC,CAAC,MAAM,aAAa,OAAO,aAAa,QAAQ,GAEpF,MAAM,IAAI,MAAM,sBAAsB,UAAU,kCAAkC;EAEpF,aAAa;GACX,SAAS,MAAM;GACf,UAAU,MAAM;GAChB,gBAAgB,MAAM;GACtB,mBAAmB,MAAM;GACzB,iBAAiB,MAAM;EACzB;CACF;CAEA,OAAO;EACL;EACA;EACA;EACA,SAAS,aAAa,MAAM,OAAO;EACnC;CACF;AACF;AAEA,SAAS,qBAAqB,cAAsB,oBAA0D;CAC5G,IAAI,CAAC,SAAS,oBAAoB,YAAY,GAAG,OAAO,KAAA;CACxD,IAAI;EACF,MAAM,SAAS,KAAK,MAAMP,QAAAA,QAAG,aAAa,cAAc,MAAM,CAAC;EAC/D,IACE,CAAC,SAAS,MAAM,KAChB,OAAO,YAAA,SACP,OAAO,OAAO,WAAW,YACzB,CAAC,MAAM,QAAQ,OAAO,SAAS,KAC/B,OAAO,UAAU,MAAM,aAAa,OAAO,aAAa,QAAQ,KAChE,CAAC,MAAM,QAAQ,OAAO,OAAO,KAC7B,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,QAAQ,KACxD,CAAC,MAAM,QAAQ,OAAO,MAAM,KAC3B,OAAO,mBAAmB,KAAA,KAAa,CAAC,MAAM,QAAQ,OAAO,cAAc,GAE5E;EAEF,MAAM,SAAS,kBAAkB,OAAO,MAAM;EAC9C,MAAM,iBAAiB,OAAO,mBAAmB,KAAA,IAAY,KAAA,IAAY,kBAAkB,OAAO,cAAc;EAChH,IAAI,CAAC,UAAW,OAAO,mBAAmB,KAAA,KAAa,CAAC,gBAAiB,OAAO,KAAA;EAChF,MAAM,YAAY,OAAO;EACzB,MAAM,UAAU,OAAO;EACvB,IACE,CAAC,SAAS,oBAAoB,OAAO,MAAM,KAC3C,UAAU,MAAM,aAAa,CAAC,SAAS,oBAAoB,QAAQ,CAAC,GAEpE;EAEF,OAAO;GAAE,QAAQ,OAAO;GAAQ;GAAW;GAAS;GAAQ,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;EAAG;CAC5G,QAAQ;EACN;CACF;AACF;AAEA,SAAS,wBAAwB,UAA4B,oBAAqC;CAChG,IAAI;EACF,IAAI,CAAC,SAAS,kBAAkB,SAAS,eAAe,WAAW,GAAG,OAAO;EAC7E,MAAM,WAAW,IAAI,IAAI,CAAC,SAAS,QAAQ,GAAG,SAAS,SAAS,CAAC,CAAC,IAAI,aAAa,CAAC;EACpF,MAAM,uBAAO,IAAI,IAAY;EAC7B,KAAK,MAAM,SAAS,SAAS,gBAAgB;GAC3C,IAAI,CAAC,OAAO,KAAK,MAAM,MAAM,KAAK,CAAC,SAAS,oBAAoB,MAAM,IAAI,GAAG,OAAO;GACpF,MAAM,SAAS,cAAc,MAAM,IAAI;GACvC,IAAI,CAAC,SAAS,IAAI,MAAM,GAAG,OAAO;GAClC,MAAM,OAAOA,QAAAA,QAAG,SAAS,MAAM;GAC/B,IAAI,CAAC,KAAK,OAAO,KAAK,KAAK,SAAS,MAAM,MAAM,OAAO;GACvD,IAAIQ,YAAAA,QAAO,WAAW,QAAQ,CAAC,CAAC,OAAOR,QAAAA,QAAG,aAAa,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,MAAM,QAAQ,OAAO;GACvG,KAAK,IAAI,MAAM;EACjB;EACA,OAAO,KAAK,SAAS,SAAS;CAChC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,yBAAyB,UAA4B,oBAAqC;CACjG,OAAO,wBAAwB,UAAU,kBAAkB;AAC7D;AAEA,SAAS,wBAAwB,UAA4B,oBAAqC;CAChG,OAAO,yBAAyB,UAAU,kBAAkB,KAAKS,eAAAA,eAAe,SAAS,MAAM;AACjG;AAEA,SAAS,gBACP,OACA,wBACA,oBAC8B;CAC9B,IAAI,CAAC,MAAM,aAAa,CAAC,MAAM,YAAY,OAAO,KAAA;CAClD,IACE,MAAM,WAAW,YAAYC,yCAAAA,4BAC7B,cAAc,MAAM,WAAW,cAAc,MAAM,cAAc,sBAAsB,GAEvF;CAEF,MAAM,SAAS,qBAAqB,MAAM,WAAW,mBAAmB,MAAM,kBAAkB;CAChG,IACE,CAAC,UACD,CAAC,yBAAyB,QAAQ,MAAM,kBAAkB,KACzD,sBAAsB,CAAC,wBAAwB,QAAQ,MAAM,kBAAkB,KAChF,OAAO,WAAW,MAAM,aACxB,OAAO,QAAQ,WAAW,KAC1B,cAAc,OAAO,QAAQ,MAAM,EAAE,MAAM,cAAc,sBAAsB,GAE/E;CAEF,OAAO;AACT;AAEA,SAAS,sBAAsB,OAAuB,wBAA8D;CAClH,OAAO,gBAAgB,OAAO,wBAAwB,KAAK;AAC7D;AAEA,SAAS,qBAAqB,OAAuB,wBAA8D;CACjH,OAAO,gBAAgB,OAAO,wBAAwB,IAAI;AAC5D;;AAGA,SAAgB,2BACd,UACA,wBACA,gBAAwBN,QAAAA,QAAG,QAAQ,GAClB;CACjB,MAAM,QAAQ,mBAAmB,UAAU,aAAa;CACxD,MAAM,WAAW,0BAA0B,kBAAkB;CAC7D,IAAI,CAAC,OAAO,OAAO;EAAE,WAAW,KAAA;EAAW,OAAO;CAAM;CACxD,OAAO;EACL,WAAW,MAAM;EACjB,OAAO,sBAAsB,OAAO,QAAQ,MAAM,KAAA;CACpD;AACF;;AAGA,SAAgB,iBACd,UACA,wBACA,gBAAwBA,QAAAA,QAAG,QAAQ,GACrB;CACd,MAAM,QAAQ,mBAAmB,UAAU,aAAa;CACxD,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,eAAe,OAAO,YAAY,gBAAgB;CACxD,IAAI,CAAC,SAAS,MAAM,YAAY,YAAYM,yCAAAA,4BAA4B,CAAC,UAAU,CAAC,cAClF,OAAO;EAAE;EAAQ,OAAO;CAAM;CAEhC,MAAM,WAAW,qBAAqB,cAAc,MAAM,kBAAkB;CAC5E,OAAO;EACL;EACA,OAAO,QACL,YAAY,SAAS,WAAW,UAAU,yBAAyB,UAAU,MAAM,kBAAkB,CACvG;CACF;AACF;;AAGA,SAAgB,oBACd,UACA,wBACA,gBAAwBN,QAAAA,QAAG,QAAQ,GAClB;CACjB,MAAM,QAAQ,mBAAmB,UAAU,aAAa;CACxD,MAAM,WAAW,0BAA0B,kBAAkB;CAC7D,IAAI,CAAC,OAAO,aAAa,CAAC,MAAM,cAAc,CAAC,qBAAqB,OAAO,QAAQ,GACjF,OAAO;EAAE,WAAW,OAAO;EAAW,OAAO;CAAM;CAErD,MAAM,YAAY,OAAO,OAAO,MAAM,WAAW,eAAe;CAChE,IAAI,IAAI,IAAI,SAAS,CAAC,CAAC,SAAS,UAAU,QAAQ,OAAO;EAAE,WAAW,MAAM;EAAW,OAAO;CAAM;CACpG,MAAM,QAAQ,OAAO,QAAQ,MAAM,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,YAAY;EAC3E,MAAM,eAAe,MAAM,YAAY,gBAAgB;EACvD,IAAI,CAAC,cAAc,OAAO;EAC1B,MAAM,WAAW,qBAAqB,cAAc,MAAM,kBAAkB;EAC5E,OAAO,QACL,YAAY,SAAS,WAAW,UAAU,wBAAwB,UAAU,MAAM,kBAAkB,CACtG;CACF,CAAC;CACD,OAAO;EAAE,WAAW,MAAM;EAAW;CAAM;AAC7C"}
1
+ {"version":3,"file":"index.cjs","names":["path","fs","parseInputFingerprint","ownEntry","readSyncRegistration","os","resolveDoomConfigurationRoot","readRegisteredSyncState","PRECOMPILE_STATE_VERSION","BUNDLED_PRECOMPILE_STRATEGY","crypto","inputsAreFresh"],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { readSyncRegistration, type SyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport { BUNDLED_PRECOMPILE_STRATEGY, PRECOMPILE_STATE_VERSION } from '@agimon-ai/doompi-core/syncStateContract';\n\nimport { inputsAreFresh, parseInputFingerprint, type InputFingerprint } from '../../../compiler/inputs';\nimport { EXTENSION_COMPILER_VERSION } from '../../../compiler/version';\nimport { resolveDoomConfigurationRoot } from '../../../composition/repository';\nimport { readRegisteredSyncState } from '../../../composition/syncState';\nimport { ownEntry } from '../entryResolution';\n\nconst BOOTSTRAP_ENTRY_ENV = 'DOOMPI_BOOTSTRAP_ENTRY';\nconst SHA256 = /^[a-f0-9]{64}$/u;\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n artifactInputs?: 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: 'bundle';\n bootstrapEntry: string;\n bootstrapManifest: string;\n bundleManifests: Record<string, string>;\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nexport interface BundleStatus {\n bundle?: 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 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 parseFingerprints(value: unknown): InputFingerprint[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const fingerprints = value.map(parseInputFingerprint);\n return fingerprints.some((fingerprint) => fingerprint === undefined)\n ? undefined\n : (fingerprints as InputFingerprint[]);\n}\n\nfunction packagedDoomEntry(): string {\n return process.env[BOOTSTRAP_ENTRY_ENV] || ownEntry('composedPi');\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n return readSyncRegistration(repoRoot, homeDirectory) !== undefined;\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 if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = resolveDoomConfigurationRoot(cwd, homeDirectory);\n return locationHasState(root, homeDirectory) ? canonicalPath(root) : undefined;\n}\n\nfunction readBootstrapStateFromRegistration(\n registration: SyncRegistration,\n homeDirectory: string = os.homedir(),\n): BootstrapState {\n const statePath = registration.statePath;\n const generatedDirectory = registration.generationRoot;\n const state = readRegisteredSyncState(registration, homeDirectory);\n const bootstrap = typeof state.bootstrap === 'string' ? state.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 (state.precompile !== undefined) {\n const value = state.precompile;\n if (\n value.version !== PRECOMPILE_STATE_VERSION ||\n value.strategy !== BUNDLED_PRECOMPILE_STRATEGY ||\n typeof value.bootstrapEntry !== 'string' ||\n typeof value.bootstrapManifest !== 'string' ||\n !isRecord(value.bundleManifests) ||\n Object.values(value.bundleManifests).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: value.version,\n strategy: value.strategy,\n bootstrapEntry: value.bootstrapEntry,\n bootstrapManifest: value.bootstrapManifest,\n bundleManifests: value.bundleManifests,\n };\n }\n\n return {\n statePath,\n generatedDirectory,\n bootstrap,\n bundles: state.bundles ?? {},\n precompile,\n };\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const registration = readSyncRegistration(repoRoot, homeDirectory);\n return registration ? readBootstrapStateFromRegistration(registration, homeDirectory) : undefined;\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 parsed.version !== EXTENSION_COMPILER_VERSION ||\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 (parsed.artifactInputs !== undefined && !Array.isArray(parsed.artifactInputs))\n ) {\n return undefined;\n }\n const inputs = parseFingerprints(parsed.inputs);\n const artifactInputs = parsed.artifactInputs === undefined ? undefined : parseFingerprints(parsed.artifactInputs);\n if (!inputs || (parsed.artifactInputs !== undefined && !artifactInputs)) return undefined;\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, ...(artifactInputs ? { artifactInputs } : {}) };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactInputsAreIntact(manifest: CompilerManifest, generatedDirectory: string): boolean {\n try {\n if (!manifest.artifactInputs || manifest.artifactInputs.length === 0) return false;\n const expected = new Set([manifest.output, ...manifest.artifacts].map(canonicalPath));\n const seen = new Set<string>();\n for (const input of manifest.artifactInputs) {\n if (!SHA256.test(input.sha256) || !isInside(generatedDirectory, input.path)) return false;\n const target = canonicalPath(input.path);\n if (!expected.has(target)) return false;\n const stat = fs.statSync(target);\n if (!stat.isFile() || stat.size !== input.size) return false;\n if (crypto.createHash('sha256').update(fs.readFileSync(target)).digest('hex') !== input.sha256) return false;\n seen.add(target);\n }\n return seen.size === expected.size;\n } catch {\n return false;\n }\n}\n\nfunction compilerManifestIsUsable(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return artifactInputsAreIntact(manifest, generatedDirectory);\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return compilerManifestIsUsable(manifest, generatedDirectory) && inputsAreFresh(manifest.inputs);\n}\n\nfunction bootstrapRecord(\n state: BootstrapState,\n expectedBootstrapEntry: string,\n requireFreshInputs: boolean,\n): CompilerManifest | undefined {\n if (!state.bootstrap || !state.precompile) return undefined;\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n const record = readCompilerManifest(state.precompile.bootstrapManifest, state.generatedDirectory);\n if (\n !record ||\n !compilerManifestIsUsable(record, state.generatedDirectory) ||\n (requireFreshInputs && !compilerManifestIsFresh(record, state.generatedDirectory)) ||\n record.output !== state.bootstrap ||\n record.entries.length !== 1 ||\n canonicalPath(record.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n return record;\n}\n\nfunction usableBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, false);\n}\n\nfunction freshBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, true);\n}\n\n/** Validates only the bootstrap graph needed before the generated bootstrap is imported. */\nexport function readStartupBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state) return { bootstrap: undefined, fresh: false };\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates the bootstrap owned by one exact immutable registration. */\nexport function readRegisteredBootstrapStatus(\n registration: SyncRegistration,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapStateFromRegistration(registration, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates one selected composition without touching any inactive bundle inputs. */\nexport function readBundleStatus(\n repoRoot: string,\n compositionFingerprint: string,\n homeDirectory: string = os.homedir(),\n): BundleStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const bundle = state?.bundles[compositionFingerprint];\n const manifestPath = state?.precompile?.bundleManifests[compositionFingerprint];\n if (!state || state.precompile?.version !== PRECOMPILE_STATE_VERSION || !bundle || !manifestPath) {\n return { bundle, fresh: false };\n }\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return {\n bundle,\n fresh: Boolean(\n manifest && manifest.output === bundle && compilerManifestIsUsable(manifest, state.generatedDirectory),\n ),\n };\n}\n\n/** Validates the bootstrap and every bundle for `doompi sync --check` diagnostics. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state?.bootstrap || !state.precompile || !freshBootstrapRecord(state, expected)) {\n return { bootstrap: state?.bootstrap, fresh: false };\n }\n const manifests = Object.values(state.precompile.bundleManifests);\n if (new Set(manifests).size !== manifests.length) return { bootstrap: state.bootstrap, fresh: false };\n const fresh = Object.entries(state.bundles).every(([fingerprint, bundle]) => {\n const manifestPath = state.precompile?.bundleManifests[fingerprint];\n if (!manifestPath) return false;\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return Boolean(\n manifest && manifest.output === bundle && compilerManifestIsFresh(manifest, state.generatedDirectory),\n );\n });\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,3 +1,4 @@
1
+ import { SyncRegistration } from "@agimon-ai/doompi-core/syncRegistration";
1
2
  //#region src/builders/cli/bootstrapLocator/index.d.ts
2
3
  /** Finds the nearest configured repository with generated Doom sync state. */
3
4
  export declare function findSyncedRoot(cwd: string, homeDirectory?: string): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"mappings":";;wBA6FgB,eAAe,aAAa"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"mappings":";;;wBAsFgB,eAAe,aAAa"}
@@ -1,6 +1,6 @@
1
1
  import { resolveDoomConfigurationRoot } from "../../../composition/repository/index.mjs";
2
2
  import { ownEntry } from "../entryResolution.mjs";
3
- import { readSyncState } from "../../../composition/syncState/index.mjs";
3
+ import { readRegisteredSyncState } from "../../../composition/syncState/index.mjs";
4
4
  import { inputsAreFresh, parseInputFingerprint } from "../../../compiler/inputs.mjs";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
@@ -14,10 +14,6 @@ const SHA256 = /^[a-f0-9]{64}$/u;
14
14
  function isRecord(value) {
15
15
  return typeof value === "object" && value !== null && !Array.isArray(value);
16
16
  }
17
- function stringRecord(value) {
18
- if (!isRecord(value)) return {};
19
- return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
20
- }
21
17
  function canonicalPath(target) {
22
18
  const absolute = path.resolve(target);
23
19
  try {
@@ -49,19 +45,16 @@ function findSyncedRoot(cwd, homeDirectory = os.homedir()) {
49
45
  const root = resolveDoomConfigurationRoot(cwd, homeDirectory);
50
46
  return locationHasState(root, homeDirectory) ? canonicalPath(root) : void 0;
51
47
  }
52
- function readBootstrapState(repoRoot, homeDirectory = os.homedir()) {
53
- const registration = readSyncRegistration(repoRoot, homeDirectory);
54
- if (!registration) return void 0;
48
+ function readBootstrapStateFromRegistration(registration, homeDirectory = os.homedir()) {
55
49
  const statePath = registration.statePath;
56
50
  const generatedDirectory = registration.generationRoot;
57
- const state = readSyncState(repoRoot, homeDirectory);
58
- if (!state) return void 0;
51
+ const state = readRegisteredSyncState(registration, homeDirectory);
59
52
  const bootstrap = typeof state.bootstrap === "string" ? state.bootstrap : void 0;
60
53
  if (bootstrap && !isInside(generatedDirectory, bootstrap)) throw new Error(`Doom bootstrap must stay inside ${generatedDirectory}: ${bootstrap}`);
61
54
  let precompile;
62
55
  if (state.precompile !== void 0) {
63
56
  const value = state.precompile;
64
- if (!isRecord(value) || typeof value.version !== "number" || value.strategy !== BUNDLED_PRECOMPILE_STRATEGY || typeof value.bootstrapEntry !== "string" || typeof value.bootstrapManifest !== "string" || !isRecord(value.bundleManifests) || Object.values(value.bundleManifests).some((manifest) => typeof manifest !== "string")) throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);
57
+ if (value.version !== PRECOMPILE_STATE_VERSION || value.strategy !== BUNDLED_PRECOMPILE_STRATEGY || typeof value.bootstrapEntry !== "string" || typeof value.bootstrapManifest !== "string" || !isRecord(value.bundleManifests) || Object.values(value.bundleManifests).some((manifest) => typeof manifest !== "string")) throw new Error(`Doom sync state at ${statePath} has an invalid precompile record`);
65
58
  precompile = {
66
59
  version: value.version,
67
60
  strategy: value.strategy,
@@ -74,10 +67,14 @@ function readBootstrapState(repoRoot, homeDirectory = os.homedir()) {
74
67
  statePath,
75
68
  generatedDirectory,
76
69
  bootstrap,
77
- bundles: stringRecord(state.bundles),
70
+ bundles: state.bundles ?? {},
78
71
  precompile
79
72
  };
80
73
  }
74
+ function readBootstrapState(repoRoot, homeDirectory = os.homedir()) {
75
+ const registration = readSyncRegistration(repoRoot, homeDirectory);
76
+ return registration ? readBootstrapStateFromRegistration(registration, homeDirectory) : void 0;
77
+ }
81
78
  function readCompilerManifest(manifestPath, generatedDirectory) {
82
79
  if (!isInside(generatedDirectory, manifestPath)) return void 0;
83
80
  try {
@@ -151,6 +148,15 @@ function readStartupBootstrapStatus(repoRoot, expectedBootstrapEntry, homeDirect
151
148
  fresh: usableBootstrapRecord(state, expected) !== void 0
152
149
  };
153
150
  }
151
+ /** Validates the bootstrap owned by one exact immutable registration. */
152
+ function readRegisteredBootstrapStatus(registration, expectedBootstrapEntry, homeDirectory = os.homedir()) {
153
+ const state = readBootstrapStateFromRegistration(registration, homeDirectory);
154
+ const expected = expectedBootstrapEntry ?? packagedDoomEntry();
155
+ return {
156
+ bootstrap: state.bootstrap,
157
+ fresh: usableBootstrapRecord(state, expected) !== void 0
158
+ };
159
+ }
154
160
  /** Validates one selected composition without touching any inactive bundle inputs. */
155
161
  function readBundleStatus(repoRoot, compositionFingerprint, homeDirectory = os.homedir()) {
156
162
  const state = readBootstrapState(repoRoot, homeDirectory);
@@ -191,6 +197,6 @@ function readBootstrapStatus(repoRoot, expectedBootstrapEntry, homeDirectory = o
191
197
  };
192
198
  }
193
199
  //#endregion
194
- export { findSyncedRoot, readBootstrapStatus, readBundleStatus, readStartupBootstrapStatus };
200
+ export { findSyncedRoot, readBootstrapStatus, readBundleStatus, readRegisteredBootstrapStatus, readStartupBootstrapStatus };
195
201
 
196
202
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport { BUNDLED_PRECOMPILE_STRATEGY, PRECOMPILE_STATE_VERSION } from '@agimon-ai/doompi-core/syncStateContract';\n\nimport { inputsAreFresh, parseInputFingerprint, type InputFingerprint } from '../../../compiler/inputs';\nimport { EXTENSION_COMPILER_VERSION } from '../../../compiler/version';\nimport { resolveDoomConfigurationRoot } from '../../../composition/repository';\nimport { readSyncState } from '../../../composition/syncState';\nimport { ownEntry } from '../entryResolution';\n\nconst BOOTSTRAP_ENTRY_ENV = 'DOOMPI_BOOTSTRAP_ENTRY';\nconst SHA256 = /^[a-f0-9]{64}$/u;\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n artifactInputs?: 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: 'bundle';\n bootstrapEntry: string;\n bootstrapManifest: string;\n bundleManifests: Record<string, string>;\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nexport interface BundleStatus {\n bundle?: 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 parseFingerprints(value: unknown): InputFingerprint[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const fingerprints = value.map(parseInputFingerprint);\n return fingerprints.some((fingerprint) => fingerprint === undefined)\n ? undefined\n : (fingerprints as InputFingerprint[]);\n}\n\nfunction packagedDoomEntry(): string {\n return process.env[BOOTSTRAP_ENTRY_ENV] || ownEntry('composedPi');\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n return readSyncRegistration(repoRoot, homeDirectory) !== undefined;\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 if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = resolveDoomConfigurationRoot(cwd, homeDirectory);\n return locationHasState(root, homeDirectory) ? canonicalPath(root) : undefined;\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const registration = readSyncRegistration(repoRoot, homeDirectory);\n if (!registration) return undefined;\n const statePath = registration.statePath;\n const generatedDirectory = registration.generationRoot;\n const state = readSyncState(repoRoot, homeDirectory);\n if (!state) return undefined;\n const bootstrap = typeof state.bootstrap === 'string' ? state.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 (state.precompile !== undefined) {\n const value = state.precompile;\n if (\n !isRecord(value) ||\n typeof value.version !== 'number' ||\n value.strategy !== BUNDLED_PRECOMPILE_STRATEGY ||\n typeof value.bootstrapEntry !== 'string' ||\n typeof value.bootstrapManifest !== 'string' ||\n !isRecord(value.bundleManifests) ||\n Object.values(value.bundleManifests).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: value.version,\n strategy: value.strategy,\n bootstrapEntry: value.bootstrapEntry,\n bootstrapManifest: value.bootstrapManifest,\n bundleManifests: value.bundleManifests as Record<string, string>,\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 parsed.version !== EXTENSION_COMPILER_VERSION ||\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 (parsed.artifactInputs !== undefined && !Array.isArray(parsed.artifactInputs))\n ) {\n return undefined;\n }\n const inputs = parseFingerprints(parsed.inputs);\n const artifactInputs = parsed.artifactInputs === undefined ? undefined : parseFingerprints(parsed.artifactInputs);\n if (!inputs || (parsed.artifactInputs !== undefined && !artifactInputs)) return undefined;\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, ...(artifactInputs ? { artifactInputs } : {}) };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactInputsAreIntact(manifest: CompilerManifest, generatedDirectory: string): boolean {\n try {\n if (!manifest.artifactInputs || manifest.artifactInputs.length === 0) return false;\n const expected = new Set([manifest.output, ...manifest.artifacts].map(canonicalPath));\n const seen = new Set<string>();\n for (const input of manifest.artifactInputs) {\n if (!SHA256.test(input.sha256) || !isInside(generatedDirectory, input.path)) return false;\n const target = canonicalPath(input.path);\n if (!expected.has(target)) return false;\n const stat = fs.statSync(target);\n if (!stat.isFile() || stat.size !== input.size) return false;\n if (crypto.createHash('sha256').update(fs.readFileSync(target)).digest('hex') !== input.sha256) return false;\n seen.add(target);\n }\n return seen.size === expected.size;\n } catch {\n return false;\n }\n}\n\nfunction compilerManifestIsUsable(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return artifactInputsAreIntact(manifest, generatedDirectory);\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return compilerManifestIsUsable(manifest, generatedDirectory) && inputsAreFresh(manifest.inputs);\n}\n\nfunction bootstrapRecord(\n state: BootstrapState,\n expectedBootstrapEntry: string,\n requireFreshInputs: boolean,\n): CompilerManifest | undefined {\n if (!state.bootstrap || !state.precompile) return undefined;\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n const record = readCompilerManifest(state.precompile.bootstrapManifest, state.generatedDirectory);\n if (\n !record ||\n !compilerManifestIsUsable(record, state.generatedDirectory) ||\n (requireFreshInputs && !compilerManifestIsFresh(record, state.generatedDirectory)) ||\n record.output !== state.bootstrap ||\n record.entries.length !== 1 ||\n canonicalPath(record.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n return record;\n}\n\nfunction usableBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, false);\n}\n\nfunction freshBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, true);\n}\n\n/** Validates only the bootstrap graph needed before the generated bootstrap is imported. */\nexport function readStartupBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state) return { bootstrap: undefined, fresh: false };\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates one selected composition without touching any inactive bundle inputs. */\nexport function readBundleStatus(\n repoRoot: string,\n compositionFingerprint: string,\n homeDirectory: string = os.homedir(),\n): BundleStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const bundle = state?.bundles[compositionFingerprint];\n const manifestPath = state?.precompile?.bundleManifests[compositionFingerprint];\n if (!state || state.precompile?.version !== PRECOMPILE_STATE_VERSION || !bundle || !manifestPath) {\n return { bundle, fresh: false };\n }\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return {\n bundle,\n fresh: Boolean(\n manifest && manifest.output === bundle && compilerManifestIsUsable(manifest, state.generatedDirectory),\n ),\n };\n}\n\n/** Validates the bootstrap and every bundle for `doompi sync --check` diagnostics. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state?.bootstrap || !state.precompile || !freshBootstrapRecord(state, expected)) {\n return { bootstrap: state?.bootstrap, fresh: false };\n }\n const manifests = Object.values(state.precompile.bundleManifests);\n if (new Set(manifests).size !== manifests.length) return { bootstrap: state.bootstrap, fresh: false };\n const fresh = Object.entries(state.bundles).every(([fingerprint, bundle]) => {\n const manifestPath = state.precompile?.bundleManifests[fingerprint];\n if (!manifestPath) return false;\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return Boolean(\n manifest && manifest.output === bundle && compilerManifestIsFresh(manifest, state.generatedDirectory),\n );\n });\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
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/builders/cli/bootstrapLocator/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { readSyncRegistration, type SyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport { BUNDLED_PRECOMPILE_STRATEGY, PRECOMPILE_STATE_VERSION } from '@agimon-ai/doompi-core/syncStateContract';\n\nimport { inputsAreFresh, parseInputFingerprint, type InputFingerprint } from '../../../compiler/inputs';\nimport { EXTENSION_COMPILER_VERSION } from '../../../compiler/version';\nimport { resolveDoomConfigurationRoot } from '../../../composition/repository';\nimport { readRegisteredSyncState } from '../../../composition/syncState';\nimport { ownEntry } from '../entryResolution';\n\nconst BOOTSTRAP_ENTRY_ENV = 'DOOMPI_BOOTSTRAP_ENTRY';\nconst SHA256 = /^[a-f0-9]{64}$/u;\n\ninterface CompilerManifest {\n output: string;\n artifacts: string[];\n entries: string[];\n inputs: InputFingerprint[];\n artifactInputs?: 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: 'bundle';\n bootstrapEntry: string;\n bootstrapManifest: string;\n bundleManifests: Record<string, string>;\n };\n}\n\nexport interface BootstrapStatus {\n bootstrap?: string;\n fresh: boolean;\n}\n\nexport interface BundleStatus {\n bundle?: 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 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 parseFingerprints(value: unknown): InputFingerprint[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const fingerprints = value.map(parseInputFingerprint);\n return fingerprints.some((fingerprint) => fingerprint === undefined)\n ? undefined\n : (fingerprints as InputFingerprint[]);\n}\n\nfunction packagedDoomEntry(): string {\n return process.env[BOOTSTRAP_ENTRY_ENV] || ownEntry('composedPi');\n}\n\nfunction locationHasState(repoRoot: string, homeDirectory: string): boolean {\n return readSyncRegistration(repoRoot, homeDirectory) !== undefined;\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 if (locationHasState(cwd, homeDirectory)) return canonicalPath(cwd);\n const root = resolveDoomConfigurationRoot(cwd, homeDirectory);\n return locationHasState(root, homeDirectory) ? canonicalPath(root) : undefined;\n}\n\nfunction readBootstrapStateFromRegistration(\n registration: SyncRegistration,\n homeDirectory: string = os.homedir(),\n): BootstrapState {\n const statePath = registration.statePath;\n const generatedDirectory = registration.generationRoot;\n const state = readRegisteredSyncState(registration, homeDirectory);\n const bootstrap = typeof state.bootstrap === 'string' ? state.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 (state.precompile !== undefined) {\n const value = state.precompile;\n if (\n value.version !== PRECOMPILE_STATE_VERSION ||\n value.strategy !== BUNDLED_PRECOMPILE_STRATEGY ||\n typeof value.bootstrapEntry !== 'string' ||\n typeof value.bootstrapManifest !== 'string' ||\n !isRecord(value.bundleManifests) ||\n Object.values(value.bundleManifests).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: value.version,\n strategy: value.strategy,\n bootstrapEntry: value.bootstrapEntry,\n bootstrapManifest: value.bootstrapManifest,\n bundleManifests: value.bundleManifests,\n };\n }\n\n return {\n statePath,\n generatedDirectory,\n bootstrap,\n bundles: state.bundles ?? {},\n precompile,\n };\n}\n\nfunction readBootstrapState(repoRoot: string, homeDirectory: string = os.homedir()): BootstrapState | undefined {\n const registration = readSyncRegistration(repoRoot, homeDirectory);\n return registration ? readBootstrapStateFromRegistration(registration, homeDirectory) : undefined;\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 parsed.version !== EXTENSION_COMPILER_VERSION ||\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 (parsed.artifactInputs !== undefined && !Array.isArray(parsed.artifactInputs))\n ) {\n return undefined;\n }\n const inputs = parseFingerprints(parsed.inputs);\n const artifactInputs = parsed.artifactInputs === undefined ? undefined : parseFingerprints(parsed.artifactInputs);\n if (!inputs || (parsed.artifactInputs !== undefined && !artifactInputs)) return undefined;\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, ...(artifactInputs ? { artifactInputs } : {}) };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactInputsAreIntact(manifest: CompilerManifest, generatedDirectory: string): boolean {\n try {\n if (!manifest.artifactInputs || manifest.artifactInputs.length === 0) return false;\n const expected = new Set([manifest.output, ...manifest.artifacts].map(canonicalPath));\n const seen = new Set<string>();\n for (const input of manifest.artifactInputs) {\n if (!SHA256.test(input.sha256) || !isInside(generatedDirectory, input.path)) return false;\n const target = canonicalPath(input.path);\n if (!expected.has(target)) return false;\n const stat = fs.statSync(target);\n if (!stat.isFile() || stat.size !== input.size) return false;\n if (crypto.createHash('sha256').update(fs.readFileSync(target)).digest('hex') !== input.sha256) return false;\n seen.add(target);\n }\n return seen.size === expected.size;\n } catch {\n return false;\n }\n}\n\nfunction compilerManifestIsUsable(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return artifactInputsAreIntact(manifest, generatedDirectory);\n}\n\nfunction compilerManifestIsFresh(manifest: CompilerManifest, generatedDirectory: string): boolean {\n return compilerManifestIsUsable(manifest, generatedDirectory) && inputsAreFresh(manifest.inputs);\n}\n\nfunction bootstrapRecord(\n state: BootstrapState,\n expectedBootstrapEntry: string,\n requireFreshInputs: boolean,\n): CompilerManifest | undefined {\n if (!state.bootstrap || !state.precompile) return undefined;\n if (\n state.precompile.version !== PRECOMPILE_STATE_VERSION ||\n canonicalPath(state.precompile.bootstrapEntry) !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n const record = readCompilerManifest(state.precompile.bootstrapManifest, state.generatedDirectory);\n if (\n !record ||\n !compilerManifestIsUsable(record, state.generatedDirectory) ||\n (requireFreshInputs && !compilerManifestIsFresh(record, state.generatedDirectory)) ||\n record.output !== state.bootstrap ||\n record.entries.length !== 1 ||\n canonicalPath(record.entries[0] ?? '') !== canonicalPath(expectedBootstrapEntry)\n ) {\n return undefined;\n }\n return record;\n}\n\nfunction usableBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, false);\n}\n\nfunction freshBootstrapRecord(state: BootstrapState, expectedBootstrapEntry: string): CompilerManifest | undefined {\n return bootstrapRecord(state, expectedBootstrapEntry, true);\n}\n\n/** Validates only the bootstrap graph needed before the generated bootstrap is imported. */\nexport function readStartupBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state) return { bootstrap: undefined, fresh: false };\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates the bootstrap owned by one exact immutable registration. */\nexport function readRegisteredBootstrapStatus(\n registration: SyncRegistration,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapStateFromRegistration(registration, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n return {\n bootstrap: state.bootstrap,\n fresh: usableBootstrapRecord(state, expected) !== undefined,\n };\n}\n\n/** Validates one selected composition without touching any inactive bundle inputs. */\nexport function readBundleStatus(\n repoRoot: string,\n compositionFingerprint: string,\n homeDirectory: string = os.homedir(),\n): BundleStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const bundle = state?.bundles[compositionFingerprint];\n const manifestPath = state?.precompile?.bundleManifests[compositionFingerprint];\n if (!state || state.precompile?.version !== PRECOMPILE_STATE_VERSION || !bundle || !manifestPath) {\n return { bundle, fresh: false };\n }\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return {\n bundle,\n fresh: Boolean(\n manifest && manifest.output === bundle && compilerManifestIsUsable(manifest, state.generatedDirectory),\n ),\n };\n}\n\n/** Validates the bootstrap and every bundle for `doompi sync --check` diagnostics. */\nexport function readBootstrapStatus(\n repoRoot: string,\n expectedBootstrapEntry?: string,\n homeDirectory: string = os.homedir(),\n): BootstrapStatus {\n const state = readBootstrapState(repoRoot, homeDirectory);\n const expected = expectedBootstrapEntry ?? packagedDoomEntry();\n if (!state?.bootstrap || !state.precompile || !freshBootstrapRecord(state, expected)) {\n return { bootstrap: state?.bootstrap, fresh: false };\n }\n const manifests = Object.values(state.precompile.bundleManifests);\n if (new Set(manifests).size !== manifests.length) return { bootstrap: state.bootstrap, fresh: false };\n const fresh = Object.entries(state.bundles).every(([fingerprint, bundle]) => {\n const manifestPath = state.precompile?.bundleManifests[fingerprint];\n if (!manifestPath) return false;\n const manifest = readCompilerManifest(manifestPath, state.generatedDirectory);\n return Boolean(\n manifest && manifest.output === bundle && compilerManifestIsFresh(manifest, state.generatedDirectory),\n );\n });\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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"}
@@ -0,0 +1,57 @@
1
+ let node_child_process = require("node:child_process");
2
+ let node_timers_promises = require("node:timers/promises");
3
+ let node_url = require("node:url");
4
+ let node_util = require("node:util");
5
+ let _agimon_ai_log_sink_mcp = require("@agimon-ai/log-sink-mcp");
6
+ //#region src/builders/server/logSink.ts
7
+ const START_TIMEOUT_MS = 5e3;
8
+ const DISCOVERY_TIMEOUT_MS = 4e3;
9
+ const HEALTH_TIMEOUT_MS = 750;
10
+ const DISCOVERY_INTERVAL_MS = 1100;
11
+ const execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
12
+ async function healthy(env) {
13
+ let timer;
14
+ try {
15
+ return await Promise.race([(0, _agimon_ai_log_sink_mcp.resolveLogSinkPort)({
16
+ env,
17
+ healthCheck: true
18
+ }), new Promise((resolve) => {
19
+ timer = setTimeout(() => resolve(void 0), HEALTH_TIMEOUT_MS);
20
+ })]) !== void 0;
21
+ } finally {
22
+ if (timer) clearTimeout(timer);
23
+ }
24
+ }
25
+ /** Attach to the shared daemon or start it through its published CLI. Never own its shutdown. */
26
+ async function ensureGlobalLogSink(options) {
27
+ const { cwd, env, notice } = options;
28
+ let failure;
29
+ try {
30
+ if (await healthy(env)) return;
31
+ const cli = (0, node_url.fileURLToPath)({}.resolve("@agimon-ai/log-sink-mcp/cli"));
32
+ await execFileAsync(process.execPath, [
33
+ cli,
34
+ "start",
35
+ "--global",
36
+ "--http-only"
37
+ ], {
38
+ cwd,
39
+ env,
40
+ timeout: START_TIMEOUT_MS,
41
+ maxBuffer: 65536
42
+ });
43
+ } catch (error) {
44
+ failure = error instanceof Error ? error.message : String(error);
45
+ }
46
+ const deadline = Date.now() + DISCOVERY_TIMEOUT_MS;
47
+ do {
48
+ if (await healthy(env)) return;
49
+ if (Date.now() + DISCOVERY_INTERVAL_MS > deadline) break;
50
+ await (0, node_timers_promises.setTimeout)(DISCOVERY_INTERVAL_MS);
51
+ } while (Date.now() < deadline);
52
+ notice(`Global log sink unavailable: ${failure ?? "healthy discovery timed out"}. Telemetry remains nonfatal.`);
53
+ }
54
+ //#endregion
55
+ exports.ensureGlobalLogSink = ensureGlobalLogSink;
56
+
57
+ //# sourceMappingURL=logSink.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSink.cjs","names":["promisify","execFile","resolveLogSinkPort","fileURLToPath","sleep"],"sources":["../../../../src/builders/server/logSink.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { fileURLToPath } from 'node:url';\nimport { promisify } from 'node:util';\n\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\n\nconst START_TIMEOUT_MS = 5_000;\nconst DISCOVERY_TIMEOUT_MS = 4_000;\nconst HEALTH_TIMEOUT_MS = 750;\nconst DISCOVERY_INTERVAL_MS = 1_100;\n\nconst execFileAsync = promisify(execFile);\n\nasync function healthy(env: NodeJS.ProcessEnv): Promise<boolean> {\n // Registry discovery may wait on a broken daemon's health endpoint. The\n // server must still start, without allowing that endpoint to select a local\n // fallback or hold the startup path indefinitely.\n let timer: NodeJS.Timeout | undefined;\n try {\n const result = await Promise.race([\n resolveLogSinkPort({ env, healthCheck: true }),\n new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), HEALTH_TIMEOUT_MS);\n }),\n ]);\n return result !== undefined;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** Attach to the shared daemon or start it through its published CLI. Never own its shutdown. */\nexport async function ensureGlobalLogSink(options: {\n cwd: string;\n env: NodeJS.ProcessEnv;\n notice: (message: string) => void;\n}): Promise<void> {\n const { cwd, env, notice } = options;\n let failure: string | undefined;\n try {\n if (await healthy(env)) return;\n const cli = fileURLToPath(import.meta.resolve('@agimon-ai/log-sink-mcp/cli'));\n await execFileAsync(process.execPath, [cli, 'start', '--global', '--http-only'], {\n cwd,\n env,\n timeout: START_TIMEOUT_MS,\n maxBuffer: 64 * 1024,\n });\n } catch (error) {\n failure = error instanceof Error ? error.message : String(error);\n }\n\n const deadline = Date.now() + DISCOVERY_TIMEOUT_MS;\n do {\n if (await healthy(env)) return;\n if (Date.now() + DISCOVERY_INTERVAL_MS > deadline) break;\n await sleep(DISCOVERY_INTERVAL_MS);\n } while (Date.now() < deadline);\n\n notice(`Global log sink unavailable: ${failure ?? 'healthy discovery timed out'}. Telemetry remains nonfatal.`);\n}\n"],"mappings":";;;;;;AAOA,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,wBAAwB;AAE9B,MAAM,iBAAA,GAAgBA,UAAAA,UAAAA,CAAUC,mBAAAA,QAAQ;AAExC,eAAe,QAAQ,KAA0C;CAI/D,IAAI;CACJ,IAAI;EAOF,OAAO,MANc,QAAQ,KAAK,EAAA,GAChCC,wBAAAA,mBAAAA,CAAmB;GAAE;GAAK,aAAa;EAAK,CAAC,GAC7C,IAAI,SAAoB,YAAY;GAClC,QAAQ,iBAAiB,QAAQ,KAAA,CAAS,GAAG,iBAAiB;EAChE,CAAC,CACH,CAAC,MACiB,KAAA;CACpB,UAAU;EACR,IAAI,OAAO,aAAa,KAAK;CAC/B;AACF;;AAGA,eAAsB,oBAAoB,SAIxB;CAChB,MAAM,EAAE,KAAK,KAAK,WAAW;CAC7B,IAAI;CACJ,IAAI;EACF,IAAI,MAAM,QAAQ,GAAG,GAAG;EACxB,MAAM,OAAA,GAAMC,SAAAA,cAAAA,CAAAA,CAAAA,EAA0B,QAAQ,6BAA6B,CAAC;EAC5E,MAAM,cAAc,QAAQ,UAAU;GAAC;GAAK;GAAS;GAAY;EAAa,GAAG;GAC/E;GACA;GACA,SAAS;GACT,WAAW;EACb,CAAC;CACH,SAAS,OAAO;EACd,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACjE;CAEA,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,GAAG;EACD,IAAI,MAAM,QAAQ,GAAG,GAAG;EACxB,IAAI,KAAK,IAAI,IAAI,wBAAwB,UAAU;EACnD,OAAA,GAAMC,qBAAAA,WAAAA,CAAM,qBAAqB;CACnC,SAAS,KAAK,IAAI,IAAI;CAEtB,OAAO,gCAAgC,WAAW,8BAA8B,8BAA8B;AAChH"}
@@ -0,0 +1,57 @@
1
+ import { execFile } from "node:child_process";
2
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
3
+ import { fileURLToPath } from "node:url";
4
+ import { promisify } from "node:util";
5
+ import { resolveLogSinkPort } from "@agimon-ai/log-sink-mcp";
6
+ //#region src/builders/server/logSink.ts
7
+ const START_TIMEOUT_MS = 5e3;
8
+ const DISCOVERY_TIMEOUT_MS = 4e3;
9
+ const HEALTH_TIMEOUT_MS = 750;
10
+ const DISCOVERY_INTERVAL_MS = 1100;
11
+ const execFileAsync = promisify(execFile);
12
+ async function healthy(env) {
13
+ let timer;
14
+ try {
15
+ return await Promise.race([resolveLogSinkPort({
16
+ env,
17
+ healthCheck: true
18
+ }), new Promise((resolve) => {
19
+ timer = setTimeout(() => resolve(void 0), HEALTH_TIMEOUT_MS);
20
+ })]) !== void 0;
21
+ } finally {
22
+ if (timer) clearTimeout(timer);
23
+ }
24
+ }
25
+ /** Attach to the shared daemon or start it through its published CLI. Never own its shutdown. */
26
+ async function ensureGlobalLogSink(options) {
27
+ const { cwd, env, notice } = options;
28
+ let failure;
29
+ try {
30
+ if (await healthy(env)) return;
31
+ const cli = fileURLToPath(import.meta.resolve("@agimon-ai/log-sink-mcp/cli"));
32
+ await execFileAsync(process.execPath, [
33
+ cli,
34
+ "start",
35
+ "--global",
36
+ "--http-only"
37
+ ], {
38
+ cwd,
39
+ env,
40
+ timeout: START_TIMEOUT_MS,
41
+ maxBuffer: 65536
42
+ });
43
+ } catch (error) {
44
+ failure = error instanceof Error ? error.message : String(error);
45
+ }
46
+ const deadline = Date.now() + DISCOVERY_TIMEOUT_MS;
47
+ do {
48
+ if (await healthy(env)) return;
49
+ if (Date.now() + DISCOVERY_INTERVAL_MS > deadline) break;
50
+ await setTimeout$1(DISCOVERY_INTERVAL_MS);
51
+ } while (Date.now() < deadline);
52
+ notice(`Global log sink unavailable: ${failure ?? "healthy discovery timed out"}. Telemetry remains nonfatal.`);
53
+ }
54
+ //#endregion
55
+ export { ensureGlobalLogSink };
56
+
57
+ //# sourceMappingURL=logSink.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSink.mjs","names":["sleep"],"sources":["../../../../src/builders/server/logSink.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { fileURLToPath } from 'node:url';\nimport { promisify } from 'node:util';\n\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\n\nconst START_TIMEOUT_MS = 5_000;\nconst DISCOVERY_TIMEOUT_MS = 4_000;\nconst HEALTH_TIMEOUT_MS = 750;\nconst DISCOVERY_INTERVAL_MS = 1_100;\n\nconst execFileAsync = promisify(execFile);\n\nasync function healthy(env: NodeJS.ProcessEnv): Promise<boolean> {\n // Registry discovery may wait on a broken daemon's health endpoint. The\n // server must still start, without allowing that endpoint to select a local\n // fallback or hold the startup path indefinitely.\n let timer: NodeJS.Timeout | undefined;\n try {\n const result = await Promise.race([\n resolveLogSinkPort({ env, healthCheck: true }),\n new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), HEALTH_TIMEOUT_MS);\n }),\n ]);\n return result !== undefined;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** Attach to the shared daemon or start it through its published CLI. Never own its shutdown. */\nexport async function ensureGlobalLogSink(options: {\n cwd: string;\n env: NodeJS.ProcessEnv;\n notice: (message: string) => void;\n}): Promise<void> {\n const { cwd, env, notice } = options;\n let failure: string | undefined;\n try {\n if (await healthy(env)) return;\n const cli = fileURLToPath(import.meta.resolve('@agimon-ai/log-sink-mcp/cli'));\n await execFileAsync(process.execPath, [cli, 'start', '--global', '--http-only'], {\n cwd,\n env,\n timeout: START_TIMEOUT_MS,\n maxBuffer: 64 * 1024,\n });\n } catch (error) {\n failure = error instanceof Error ? error.message : String(error);\n }\n\n const deadline = Date.now() + DISCOVERY_TIMEOUT_MS;\n do {\n if (await healthy(env)) return;\n if (Date.now() + DISCOVERY_INTERVAL_MS > deadline) break;\n await sleep(DISCOVERY_INTERVAL_MS);\n } while (Date.now() < deadline);\n\n notice(`Global log sink unavailable: ${failure ?? 'healthy discovery timed out'}. Telemetry remains nonfatal.`);\n}\n"],"mappings":";;;;;;AAOA,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,wBAAwB;AAE9B,MAAM,gBAAgB,UAAU,QAAQ;AAExC,eAAe,QAAQ,KAA0C;CAI/D,IAAI;CACJ,IAAI;EAOF,OAAO,MANc,QAAQ,KAAK,CAChC,mBAAmB;GAAE;GAAK,aAAa;EAAK,CAAC,GAC7C,IAAI,SAAoB,YAAY;GAClC,QAAQ,iBAAiB,QAAQ,KAAA,CAAS,GAAG,iBAAiB;EAChE,CAAC,CACH,CAAC,MACiB,KAAA;CACpB,UAAU;EACR,IAAI,OAAO,aAAa,KAAK;CAC/B;AACF;;AAGA,eAAsB,oBAAoB,SAIxB;CAChB,MAAM,EAAE,KAAK,KAAK,WAAW;CAC7B,IAAI;CACJ,IAAI;EACF,IAAI,MAAM,QAAQ,GAAG,GAAG;EACxB,MAAM,MAAM,cAAc,YAAY,QAAQ,6BAA6B,CAAC;EAC5E,MAAM,cAAc,QAAQ,UAAU;GAAC;GAAK;GAAS;GAAY;EAAa,GAAG;GAC/E;GACA;GACA,SAAS;GACT,WAAW;EACb,CAAC;CACH,SAAS,OAAO;EACd,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACjE;CAEA,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,GAAG;EACD,IAAI,MAAM,QAAQ,GAAG,GAAG;EACxB,IAAI,KAAK,IAAI,IAAI,wBAAwB,UAAU;EACnD,MAAMA,aAAM,qBAAqB;CACnC,SAAS,KAAK,IAAI,IAAI;CAEtB,OAAO,gCAAgC,WAAW,8BAA8B,8BAA8B;AAChH"}
@@ -0,0 +1,120 @@
1
+ const require_runtime = require("../../../_virtual/_rolldown/runtime.cjs");
2
+ let node_fs = require("node:fs");
3
+ node_fs = require_runtime.__toESM(node_fs, 1);
4
+ let node_path = require("node:path");
5
+ node_path = require_runtime.__toESM(node_path, 1);
6
+ let node_module = require("node:module");
7
+ let node_crypto = require("node:crypto");
8
+ node_crypto = require_runtime.__toESM(node_crypto, 1);
9
+ //#region src/builders/server/mcpApp.ts
10
+ /** Composes the installed packages' browser registries. No tool names or presentation policies live here. */
11
+ async function bundleMcpApp(sources, outputDirectory) {
12
+ if (sources.length === 0) return void 0;
13
+ const names = /* @__PURE__ */ new Set();
14
+ for (const source of sources) for (const name of source.widgets) {
15
+ if (names.has(name)) throw new Error(`Duplicate MCP widget '${name}'`);
16
+ names.add(name);
17
+ }
18
+ const runtimeRequire = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
19
+ const coreRoot = node_path.default.dirname(runtimeRequire.resolve("@agimon-ai/doompi-core/package.json"));
20
+ const componentsRoot = node_path.default.dirname(runtimeRequire.resolve("@agimon-ai/doompi-web-components/package.json"));
21
+ const componentsManifest = JSON.parse(node_fs.default.readFileSync(node_path.default.join(componentsRoot, "package.json"), "utf8"));
22
+ const appEntry = node_path.default.resolve(componentsRoot, componentsManifest.exports["./mcpWidget"].import);
23
+ const reactRequire = (0, node_module.createRequire)(node_path.default.join(coreRoot, "package.json"));
24
+ const directory = node_path.default.join(outputDirectory, "ui");
25
+ node_fs.default.mkdirSync(directory, { recursive: true });
26
+ const outputRoot = node_fs.default.realpathSync(outputDirectory);
27
+ const entry = node_path.default.join(directory, "entry.js");
28
+ const css = node_path.default.join(directory, "app.css");
29
+ const relative = (file) => file.split(node_path.default.sep).join("/");
30
+ node_fs.default.writeFileSync(entry, [
31
+ `import { mountMcpApp } from ${JSON.stringify(relative(appEntry))};`,
32
+ "import './app.css';",
33
+ ...sources.map((source, index) => `import { widgets as widgets${index} } from ${JSON.stringify(relative(source.file))};`),
34
+ "const widgets = Object.create(null);",
35
+ ...sources.flatMap((source, index) => source.widgets.map((name) => `widgets[${JSON.stringify(name)}] = widgets${index}[${JSON.stringify(name)}];`)),
36
+ "void mountMcpApp(widgets);",
37
+ ""
38
+ ].join("\n"));
39
+ node_fs.default.writeFileSync(css, [
40
+ `@import ${JSON.stringify(relative(runtimeRequire.resolve("tailwindcss/index.css")))};`,
41
+ `@import ${JSON.stringify(relative(node_path.default.join(componentsRoot, "styles/mcp.css")))};`,
42
+ `@source ${JSON.stringify(relative(node_path.default.join(componentsRoot, "dist")))};`,
43
+ ...sources.map((source) => `@source ${JSON.stringify(relative(source.file))};`),
44
+ ""
45
+ ].join("\n"));
46
+ const inputs = /* @__PURE__ */ new Set([
47
+ appEntry,
48
+ node_path.default.join(coreRoot, "package.json"),
49
+ node_path.default.join(componentsRoot, "package.json")
50
+ ]);
51
+ for (const root of [node_path.default.join(componentsRoot, "styles"), node_path.default.dirname(runtimeRequire.resolve("tailwindcss/package.json"))]) for (const file of node_fs.default.readdirSync(root, { recursive: true })) if (typeof file === "string" && file.endsWith(".css")) inputs.add(node_path.default.join(root, file));
52
+ const { build } = await import("vite");
53
+ const { default: tailwindcss } = await import("@tailwindcss/vite");
54
+ const built = await build({
55
+ configFile: false,
56
+ envDir: false,
57
+ root: directory,
58
+ logLevel: "warn",
59
+ define: { "process.env.NODE_ENV": JSON.stringify("production") },
60
+ plugins: [tailwindcss(), {
61
+ name: "doompi-mcp-inputs",
62
+ generateBundle() {
63
+ for (const id of this.getModuleIds()) {
64
+ const file = id.split("?")[0];
65
+ if (file.includes("\0") || !node_path.default.isAbsolute(file) || !node_fs.default.existsSync(file) || !node_fs.default.statSync(file).isFile()) continue;
66
+ const resolved = node_fs.default.realpathSync(file);
67
+ const withinOutput = node_path.default.relative(outputRoot, resolved);
68
+ if (withinOutput !== "" && !withinOutput.startsWith("..") && !node_path.default.isAbsolute(withinOutput)) continue;
69
+ inputs.add(resolved);
70
+ }
71
+ }
72
+ }],
73
+ resolve: { alias: [{
74
+ find: /^@agimon-ai\/doompi-web-components$/u,
75
+ replacement: appEntry
76
+ }, ...[
77
+ "react",
78
+ "react/jsx-runtime",
79
+ "react/jsx-dev-runtime",
80
+ "react-dom",
81
+ "react-dom/client"
82
+ ].map((specifier) => ({
83
+ find: new RegExp(`^${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "u"),
84
+ replacement: reactRequire.resolve(specifier)
85
+ }))] },
86
+ build: {
87
+ write: false,
88
+ emptyOutDir: false,
89
+ sourcemap: false,
90
+ cssCodeSplit: false,
91
+ assetsInlineLimit: 0,
92
+ lib: {
93
+ entry,
94
+ formats: ["iife"],
95
+ name: "DoompiMcpApp",
96
+ fileName: "app",
97
+ cssFileName: "app"
98
+ }
99
+ }
100
+ });
101
+ const output = (Array.isArray(built) ? built : [built]).flatMap((bundle) => "output" in bundle ? bundle.output : []);
102
+ const scripts = output.filter((item) => item.type === "chunk");
103
+ const styles = output.filter((item) => item.type === "asset").filter((item) => item.fileName.endsWith(".css"));
104
+ if (scripts.length !== 1 || scripts[0].imports.some((file) => file !== scripts[0].fileName) || scripts[0].dynamicImports.length || output.length !== scripts.length + styles.length) throw new Error(`The composed MCP app must contain one self-contained script and inline CSS only: ${output.map((item) => item.fileName).join(", ")}; imports: ${scripts.flatMap((item) => [...item.imports, ...item.dynamicImports]).join(", ")}`);
105
+ const script = scripts[0].code.replace(/<\/script/giu, "<\\/script");
106
+ const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Doompi tools</title><style>${styles.map((item) => typeof item.source === "string" ? item.source : Buffer.from(item.source).toString("utf8")).join("\n").replace(/<\/style/giu, "<\\/style")}</style></head><body><div id="root"></div><script>${script}<\/script></body></html>`;
107
+ node_fs.default.writeFileSync(node_path.default.join(directory, "index.html"), html);
108
+ return {
109
+ file: "./ui/index.html",
110
+ sha256: node_crypto.default.createHash("sha256").update(html).digest("hex"),
111
+ inputs: [...inputs].sort().map((file) => ({
112
+ path: file,
113
+ sha256: node_crypto.default.createHash("sha256").update(node_fs.default.readFileSync(file)).digest("hex")
114
+ }))
115
+ };
116
+ }
117
+ //#endregion
118
+ exports.bundleMcpApp = bundleMcpApp;
119
+
120
+ //# sourceMappingURL=mcpApp.cjs.map