@agimon-ai/po 0.0.0-alpha.2 → 0.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/README.md +14 -11
  2. package/dist/antigravity.mjs +1 -2
  3. package/dist/baseCommand.mjs +1 -2
  4. package/dist/bin/cli.cjs +37 -14
  5. package/dist/bin/cli.cjs.map +1 -1
  6. package/dist/bin/cli.mjs +34 -14
  7. package/dist/bin/cli.mjs.map +1 -1
  8. package/dist/bin/{doomRunner.cjs → poRunner.cjs} +5 -5
  9. package/dist/bin/poRunner.cjs.map +1 -0
  10. package/dist/bin/{doomRunner.d.mts → poRunner.d.mts} +2 -2
  11. package/dist/bin/poRunner.d.mts.map +1 -0
  12. package/dist/bin/{doomRunner.mjs → poRunner.mjs} +5 -5
  13. package/dist/bin/poRunner.mjs.map +1 -0
  14. package/dist/builders/cli/extensionAssembler/index.cjs +14 -12
  15. package/dist/builders/cli/extensionAssembler/index.cjs.map +1 -1
  16. package/dist/builders/cli/extensionAssembler/index.d.mts +2 -1
  17. package/dist/builders/cli/extensionAssembler/index.d.mts.map +1 -1
  18. package/dist/builders/cli/extensionAssembler/index.mjs +14 -12
  19. package/dist/builders/cli/extensionAssembler/index.mjs.map +1 -1
  20. package/dist/catalog/index.json +68 -51
  21. package/dist/cliApp.mjs +1 -2
  22. package/dist/codex.mjs +1 -2
  23. package/dist/compatibilityCommand.mjs +1 -2
  24. package/dist/compatibilityContext.mjs +1 -2
  25. package/dist/compatibilityOptions.mjs +1 -2
  26. package/dist/config.cjs +57 -12
  27. package/dist/config.d.mts +3 -3
  28. package/dist/config.mjs +3 -3
  29. package/dist/doctorCommand.mjs +1 -2
  30. package/dist/emitMcpCommand.mjs +1 -2
  31. package/dist/explainCommand.mjs +1 -2
  32. package/dist/extensions/server.cjs +11 -7
  33. package/dist/extensions/server.cjs.map +1 -1
  34. package/dist/extensions/server.d.mts +2 -2
  35. package/dist/extensions/server.d.mts.map +1 -1
  36. package/dist/extensions/server.mjs +12 -8
  37. package/dist/extensions/server.mjs.map +1 -1
  38. package/dist/harnessContext.mjs +1 -2
  39. package/dist/harnessState.cjs +66 -11
  40. package/dist/harnessState.d.mts +2 -2
  41. package/dist/harnessState.mjs +1 -2
  42. package/dist/index.cjs +60 -15
  43. package/dist/index.d.mts +3 -3
  44. package/dist/index.mjs +3 -3
  45. package/dist/initCommand.mjs +1 -2
  46. package/dist/matrixOptions.mjs +1 -2
  47. package/dist/options.mjs +1 -2
  48. package/dist/process.mjs +1 -2
  49. package/dist/projectTrust.cjs +2 -2
  50. package/dist/projectTrust.d.mts +2 -2
  51. package/dist/projectTrust.mjs +1 -2
  52. package/dist/repository.cjs +1 -1
  53. package/dist/repository.d.mts +2 -2
  54. package/dist/repository.mjs +1 -2
  55. package/dist/router.mjs +1 -2
  56. package/dist/shared.mjs +1 -2
  57. package/dist/src/bin/agentDirectory.cjs +18 -12
  58. package/dist/src/bin/agentDirectory.cjs.map +1 -1
  59. package/dist/src/bin/agentDirectory.mjs +15 -12
  60. package/dist/src/bin/agentDirectory.mjs.map +1 -1
  61. package/dist/src/builders/apiContractExport/index.cjs +6 -6
  62. package/dist/src/builders/apiContractExport/index.cjs.map +1 -1
  63. package/dist/src/builders/apiContractExport/index.mjs +9 -9
  64. package/dist/src/builders/apiContractExport/index.mjs.map +1 -1
  65. package/dist/src/builders/cli/entryResolution.cjs +3 -3
  66. package/dist/src/builders/cli/entryResolution.cjs.map +1 -1
  67. package/dist/src/builders/cli/entryResolution.mjs +3 -3
  68. package/dist/src/builders/cli/entryResolution.mjs.map +1 -1
  69. package/dist/src/builders/cli/harnessContext.cjs +5 -5
  70. package/dist/src/builders/cli/harnessContext.cjs.map +1 -1
  71. package/dist/src/builders/cli/harnessContext.mjs +7 -7
  72. package/dist/src/builders/cli/harnessContext.mjs.map +1 -1
  73. package/dist/src/builders/hooks/index.cjs +1 -1
  74. package/dist/src/builders/hooks/index.cjs.map +1 -1
  75. package/dist/src/builders/hooks/index.mjs +2 -2
  76. package/dist/src/builders/hooks/index.mjs.map +1 -1
  77. package/dist/src/builders/server/backgroundSync.cjs +13 -1
  78. package/dist/src/builders/server/backgroundSync.cjs.map +1 -1
  79. package/dist/src/builders/server/backgroundSync.mjs +13 -1
  80. package/dist/src/builders/server/backgroundSync.mjs.map +1 -1
  81. package/dist/src/builders/server/bundlerService.cjs +151 -0
  82. package/dist/src/builders/server/bundlerService.cjs.map +1 -0
  83. package/dist/src/builders/server/bundlerService.mjs +151 -0
  84. package/dist/src/builders/server/bundlerService.mjs.map +1 -0
  85. package/dist/src/builders/server/computerUseBinding.cjs +2 -2
  86. package/dist/src/builders/server/computerUseBinding.cjs.map +1 -1
  87. package/dist/src/builders/server/computerUseBinding.mjs +3 -3
  88. package/dist/src/builders/server/computerUseBinding.mjs.map +1 -1
  89. package/dist/src/builders/server/defaultWorkspace.cjs +1 -1
  90. package/dist/src/builders/server/defaultWorkspace.cjs.map +1 -1
  91. package/dist/src/builders/server/defaultWorkspace.mjs +2 -2
  92. package/dist/src/builders/server/defaultWorkspace.mjs.map +1 -1
  93. package/dist/src/builders/server/idleRestart.cjs +3 -3
  94. package/dist/src/builders/server/idleRestart.cjs.map +1 -1
  95. package/dist/src/builders/server/idleRestart.mjs +3 -3
  96. package/dist/src/builders/server/idleRestart.mjs.map +1 -1
  97. package/dist/src/builders/server/index.cjs +6 -6
  98. package/dist/src/builders/server/index.cjs.map +1 -1
  99. package/dist/src/builders/server/index.mjs +6 -6
  100. package/dist/src/builders/server/index.mjs.map +1 -1
  101. package/dist/src/builders/server/logSink.cjs +3 -3
  102. package/dist/src/builders/server/logSink.cjs.map +1 -1
  103. package/dist/src/builders/server/logSink.mjs +2 -2
  104. package/dist/src/builders/server/logSink.mjs.map +1 -1
  105. package/dist/src/builders/server/mcpBundle.cjs.map +1 -1
  106. package/dist/src/builders/server/mcpBundle.d.mts +2 -2
  107. package/dist/src/builders/server/mcpBundle.mjs.map +1 -1
  108. package/dist/src/builders/server/packageUrl.cjs +25 -18
  109. package/dist/src/builders/server/packageUrl.cjs.map +1 -1
  110. package/dist/src/builders/server/packageUrl.mjs +25 -18
  111. package/dist/src/builders/server/packageUrl.mjs.map +1 -1
  112. package/dist/src/builders/server/runtime.cjs +157 -168
  113. package/dist/src/builders/server/runtime.cjs.map +1 -1
  114. package/dist/src/builders/server/runtime.mjs +161 -171
  115. package/dist/src/builders/server/runtime.mjs.map +1 -1
  116. package/dist/src/builders/server/selectionStatus.cjs +3 -3
  117. package/dist/src/builders/server/selectionStatus.cjs.map +1 -1
  118. package/dist/src/builders/server/selectionStatus.mjs +3 -3
  119. package/dist/src/builders/server/selectionStatus.mjs.map +1 -1
  120. package/dist/src/builders/server/sessionArguments.cjs.map +1 -1
  121. package/dist/src/builders/server/sessionArguments.mjs.map +1 -1
  122. package/dist/src/builders/server/watcherService.cjs +65 -0
  123. package/dist/src/builders/server/watcherService.cjs.map +1 -0
  124. package/dist/src/builders/server/watcherService.mjs +61 -0
  125. package/dist/src/builders/server/watcherService.mjs.map +1 -0
  126. package/dist/src/builders/server/webTemplateDecision.cjs +1 -1
  127. package/dist/src/builders/server/webTemplateDecision.cjs.map +1 -1
  128. package/dist/src/builders/server/webTemplateDecision.mjs +2 -2
  129. package/dist/src/builders/server/webTemplateDecision.mjs.map +1 -1
  130. package/dist/src/builders/web/bundle.cjs.map +1 -1
  131. package/dist/src/builders/web/bundle.d.mts +4 -3
  132. package/dist/src/builders/web/bundle.mjs.map +1 -1
  133. package/dist/src/builders/web/bundleAssetPolicy.d.mts +1 -0
  134. package/dist/src/builders/web/index.cjs +1 -1
  135. package/dist/src/builders/web/index.cjs.map +1 -1
  136. package/dist/src/builders/web/index.d.mts +1 -0
  137. package/dist/src/builders/web/index.mjs +1 -1
  138. package/dist/src/builders/web/index.mjs.map +1 -1
  139. package/dist/src/builders/web/webPluginGenerate.cjs +4 -15
  140. package/dist/src/builders/web/webPluginGenerate.cjs.map +1 -1
  141. package/dist/src/builders/web/webPluginGenerate.d.mts +5 -9
  142. package/dist/src/builders/web/webPluginGenerate.d.mts.map +1 -1
  143. package/dist/src/builders/web/webPluginGenerate.mjs +4 -15
  144. package/dist/src/builders/web/webPluginGenerate.mjs.map +1 -1
  145. package/dist/src/builders/web/webPluginVite.d.mts +1 -0
  146. package/dist/src/cli/cliApp.cjs +1 -1
  147. package/dist/src/cli/cliApp.cjs.map +1 -1
  148. package/dist/src/cli/cliApp.mjs +1 -1
  149. package/dist/src/cli/cliApp.mjs.map +1 -1
  150. package/dist/src/cli/commands/compat/index.cjs +1 -1
  151. package/dist/src/cli/commands/compat/index.cjs.map +1 -1
  152. package/dist/src/cli/commands/compat/index.mjs +1 -1
  153. package/dist/src/cli/commands/compat/index.mjs.map +1 -1
  154. package/dist/src/cli/commands/doctor/index.cjs +2 -2
  155. package/dist/src/cli/commands/doctor/index.cjs.map +1 -1
  156. package/dist/src/cli/commands/doctor/index.d.mts +1 -0
  157. package/dist/src/cli/commands/doctor/index.d.mts.map +1 -1
  158. package/dist/src/cli/commands/doctor/index.mjs +4 -4
  159. package/dist/src/cli/commands/doctor/index.mjs.map +1 -1
  160. package/dist/src/cli/commands/explain/index.cjs +3 -1
  161. package/dist/src/cli/commands/explain/index.cjs.map +1 -1
  162. package/dist/src/cli/commands/explain/index.d.mts.map +1 -1
  163. package/dist/src/cli/commands/explain/index.mjs +4 -2
  164. package/dist/src/cli/commands/explain/index.mjs.map +1 -1
  165. package/dist/src/cli/commands/init/index.cjs +2 -2
  166. package/dist/src/cli/commands/init/index.cjs.map +1 -1
  167. package/dist/src/cli/commands/init/index.mjs +3 -3
  168. package/dist/src/cli/commands/init/index.mjs.map +1 -1
  169. package/dist/src/cli/commands/init/presenter.cjs +1 -1
  170. package/dist/src/cli/commands/init/presenter.cjs.map +1 -1
  171. package/dist/src/cli/commands/init/presenter.mjs +2 -2
  172. package/dist/src/cli/commands/init/presenter.mjs.map +1 -1
  173. package/dist/src/cli/commands/sync/index.cjs +4 -4
  174. package/dist/src/cli/commands/sync/index.cjs.map +1 -1
  175. package/dist/src/cli/commands/sync/index.d.mts +1 -0
  176. package/dist/src/cli/commands/sync/index.mjs +7 -7
  177. package/dist/src/cli/commands/sync/index.mjs.map +1 -1
  178. package/dist/src/cli/commands/sync/presenter.cjs +1 -1
  179. package/dist/src/cli/commands/sync/presenter.cjs.map +1 -1
  180. package/dist/src/cli/commands/sync/presenter.d.mts +1 -1
  181. package/dist/src/cli/commands/sync/presenter.mjs +1 -1
  182. package/dist/src/cli/commands/sync/presenter.mjs.map +1 -1
  183. package/dist/src/cli/commands/web/index.cjs +2 -1
  184. package/dist/src/cli/commands/web/index.cjs.map +1 -1
  185. package/dist/src/cli/commands/web/index.mjs +2 -1
  186. package/dist/src/cli/commands/web/index.mjs.map +1 -1
  187. package/dist/src/cli/harnessOptions.cjs +1 -1
  188. package/dist/src/cli/harnessOptions.cjs.map +1 -1
  189. package/dist/src/cli/harnessOptions.mjs +2 -2
  190. package/dist/src/cli/harnessOptions.mjs.map +1 -1
  191. package/dist/src/cli/help.cjs +2 -0
  192. package/dist/src/cli/help.cjs.map +1 -1
  193. package/dist/src/cli/help.mjs +2 -0
  194. package/dist/src/cli/help.mjs.map +1 -1
  195. package/dist/src/cli/matrixOptions.cjs +1 -1
  196. package/dist/src/cli/matrixOptions.cjs.map +1 -1
  197. package/dist/src/cli/matrixOptions.d.mts +1 -1
  198. package/dist/src/cli/matrixOptions.mjs +1 -1
  199. package/dist/src/cli/matrixOptions.mjs.map +1 -1
  200. package/dist/src/cli/server/run.cjs +1 -1
  201. package/dist/src/cli/server/run.cjs.map +1 -1
  202. package/dist/src/cli/server/run.mjs +2 -2
  203. package/dist/src/cli/server/run.mjs.map +1 -1
  204. package/dist/src/composition/harnessState/index.cjs +66 -11
  205. package/dist/src/composition/harnessState/index.cjs.map +1 -1
  206. package/dist/src/composition/harnessState/index.d.mts +3 -3
  207. package/dist/src/composition/harnessState/index.mjs +2 -2
  208. package/dist/src/composition/harnessState/index.mjs.map +1 -1
  209. package/dist/src/composition/layerPackageInstaller/index.cjs +5 -4
  210. package/dist/src/composition/layerPackageInstaller/index.cjs.map +1 -1
  211. package/dist/src/composition/layerPackageInstaller/index.mjs +6 -5
  212. package/dist/src/composition/layerPackageInstaller/index.mjs.map +1 -1
  213. package/dist/src/composition/poHomeMigration/index.cjs +1 -1
  214. package/dist/src/composition/poHomeMigration/index.cjs.map +1 -1
  215. package/dist/src/composition/poHomeMigration/index.mjs +1 -1
  216. package/dist/src/composition/poHomeMigration/index.mjs.map +1 -1
  217. package/dist/src/composition/projectTrust/index.cjs +6 -6
  218. package/dist/src/composition/projectTrust/index.cjs.map +1 -1
  219. package/dist/src/composition/projectTrust/index.d.mts +7 -7
  220. package/dist/src/composition/projectTrust/index.d.mts.map +1 -1
  221. package/dist/src/composition/projectTrust/index.mjs +6 -6
  222. package/dist/src/composition/projectTrust/index.mjs.map +1 -1
  223. package/dist/src/composition/repository/index.cjs +8 -8
  224. package/dist/src/composition/repository/index.cjs.map +1 -1
  225. package/dist/src/composition/repository/index.d.mts +5 -5
  226. package/dist/src/composition/repository/index.d.mts.map +1 -1
  227. package/dist/src/composition/repository/index.mjs +10 -10
  228. package/dist/src/composition/repository/index.mjs.map +1 -1
  229. package/dist/src/composition/syncService/index.cjs +29 -9
  230. package/dist/src/composition/syncService/index.cjs.map +1 -1
  231. package/dist/src/composition/syncService/index.d.mts.map +1 -1
  232. package/dist/src/composition/syncService/index.mjs +31 -11
  233. package/dist/src/composition/syncService/index.mjs.map +1 -1
  234. package/dist/src/composition/syncService/localBuilds.cjs +7 -2
  235. package/dist/src/composition/syncService/localBuilds.cjs.map +1 -1
  236. package/dist/src/composition/syncService/localBuilds.mjs +7 -2
  237. package/dist/src/composition/syncService/localBuilds.mjs.map +1 -1
  238. package/dist/src/extensions/setupDiagnostics.cjs +3 -3
  239. package/dist/src/extensions/setupDiagnostics.cjs.map +1 -1
  240. package/dist/src/extensions/setupDiagnostics.mjs +3 -3
  241. package/dist/src/extensions/setupDiagnostics.mjs.map +1 -1
  242. package/dist/utils.mjs +1 -2
  243. package/docs/server/api-export.md +3 -3
  244. package/docs/server/api.md +23 -22
  245. package/docs/server/getting-started.md +7 -7
  246. package/docs/server/index.md +4 -4
  247. package/docs/server/ipc.md +7 -11
  248. package/docs/server/lifecycle.md +17 -17
  249. package/docs/server/security.md +8 -8
  250. package/package.json +42 -45
  251. package/src/prompts/po-author-extension/SKILL.md +1 -1
  252. package/src/prompts/po-author-extension/references/extension-contract.md +4 -4
  253. package/dist/bin/doomRunner.cjs.map +0 -1
  254. package/dist/bin/doomRunner.d.mts.map +0 -1
  255. package/dist/bin/doomRunner.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import "../../../builders/cli/extensionAssembler/index.mjs";
2
- import { DoomServerBundleOwner } from "@agimon-ai/po-core/serverFacet";
2
+ import { PoServerBundleOwner } from "@agimon-ai/po-core/serverPlugin";
3
3
  //#region src/builders/server/mcpBundle.d.ts
4
4
  export interface DeclaredMcpPlugin {
5
5
  readonly packageName: string;
@@ -17,7 +17,7 @@ export interface McpPluginCandidate {
17
17
  /** Absolute, symlink-resolved path of the package's built `dist` entry. */
18
18
  readonly module: string;
19
19
  /** Every major mode and layer that admitted the package. */
20
- readonly owners: readonly DoomServerBundleOwner[];
20
+ readonly owners: readonly PoServerBundleOwner[];
21
21
  }
22
22
  //#endregion
23
23
  //# sourceMappingURL=mcpBundle.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcpBundle.mjs","names":[],"sources":["../../../../src/builders/server/mcpBundle.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { DoomServerBundleOwner } from '@agimon-ai/po-core/serverFacet';\n\nimport type { ExtensionComposition } from '../cli/extensionAssembler';\n\nexport interface DeclaredMcpPlugin {\n readonly packageName: string;\n readonly packageDir: string;\n readonly entry: string;\n readonly dist: string;\n readonly ui?: { readonly dist: string; readonly widgets: readonly string[] };\n}\n\nfunction packageRootOf(entry: string): string {\n let directory = path.dirname(fs.realpathSync(entry));\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) throw new Error(`No package manifest owns ${entry}`);\n directory = parent;\n }\n}\n\nfunction packagePath(packageDir: string, field: string, value: unknown): string {\n if (typeof value !== 'string' || !value.startsWith('./') || value.includes('..'))\n throw new Error(`poMcp ${field} in ${packageDir} must be a package-relative ./path with no '..'.`);\n return value;\n}\n\nfunction declaredMcpPlugin(packageDir: string, manifest: Record<string, unknown>): DeclaredMcpPlugin | undefined {\n const value = manifest.poMcp;\n if (value === undefined) return undefined;\n if (typeof value !== 'object' || value === null || Array.isArray(value))\n throw new Error(`poMcp manifest in ${packageDir} must be an object.`);\n const declaration = value as Record<string, unknown>;\n if (!Array.isArray(declaration.scopes) || declaration.scopes.length !== 1 || declaration.scopes[0] !== 'session')\n throw new Error(`poMcp scopes in ${packageDir} must be exactly ['session'].`);\n const packageName = manifest.name;\n if (typeof packageName !== 'string' || packageName === '') throw new Error(`Package in ${packageDir} has no name.`);\n let ui: DeclaredMcpPlugin['ui'];\n if (declaration.ui !== undefined) {\n const value = declaration.ui as { dist?: unknown; widgets?: unknown } | null;\n if (\n typeof value !== 'object' ||\n value === null ||\n !Array.isArray(value.widgets) ||\n value.widgets.some((key: unknown) => typeof key !== 'string' || !key.startsWith(`${packageName}/`)) ||\n new Set(value.widgets).size !== value.widgets.length\n )\n throw new Error(`Invalid MCP widget manifest in ${packageDir}`);\n ui = { dist: packagePath(packageDir, 'ui.dist', value.dist), widgets: value.widgets as string[] };\n }\n return {\n packageName,\n packageDir,\n ...(ui === undefined ? {} : { ui }),\n entry: packagePath(packageDir, 'entry', declaration.entry),\n dist: packagePath(packageDir, 'dist', declaration.dist),\n };\n}\n\n/** One MCP plugin a composition set selects, with the built entry a host imports. */\nexport interface McpPluginCandidate {\n readonly declaration: DeclaredMcpPlugin;\n /** Absolute, symlink-resolved path of the package's built `dist` entry. */\n readonly module: string;\n /** Every major mode and layer that admitted the package. */\n readonly owners: readonly DoomServerBundleOwner[];\n}\n\n/**\n * The MCP plugins the given compositions select, in first-selection order.\n *\n * A package that two different directories claim is ambiguous, and a built\n * entry that resolves outside its package is refused.\n */\nexport function mcpPluginCandidates(compositions: readonly ExtensionComposition[]): McpPluginCandidate[] {\n const packages = new Map<string, { declaration: DeclaredMcpPlugin; owners: DoomServerBundleOwner[] }>();\n for (const composition of compositions) {\n const majorMode = composition.majorMode?.name;\n if (!majorMode) throw new Error('An MCP bundle composition needs its major mode');\n for (const root of new Set(composition.packageEntries.map(packageRootOf))) {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const declaration = declaredMcpPlugin(root, manifest);\n if (declaration === undefined) continue;\n const previous = packages.get(declaration.packageName);\n if (previous && previous.declaration.packageDir !== root)\n throw new Error(`Ambiguous MCP bundle package: ${declaration.packageName}`);\n const candidate = previous ?? { declaration, owners: [] };\n const layers = composition.selections\n .filter(\n (selection) => selection.outcome === 'resolved' && selection.path && packageRootOf(selection.path) === root,\n )\n .map((selection) => selection.layer);\n for (const layer of new Set(layers.length > 0 ? layers : ['default'])) {\n if (!candidate.owners.some((owner) => owner.majorMode === majorMode && owner.layer === layer))\n candidate.owners.push({ majorMode, layer });\n }\n packages.set(declaration.packageName, candidate);\n }\n }\n return [...packages.values()].map(({ declaration, owners }) => {\n const module = fs.realpathSync(path.resolve(declaration.packageDir, declaration.dist));\n const relative = path.relative(declaration.packageDir, module);\n if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))\n throw new Error(`MCP entry escapes package: ${declaration.packageName}`);\n return { declaration, module, owners };\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcpBundle.mjs","names":[],"sources":["../../../../src/builders/server/mcpBundle.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { PoServerBundleOwner } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { ExtensionComposition } from '../cli/extensionAssembler';\n\nexport interface DeclaredMcpPlugin {\n readonly packageName: string;\n readonly packageDir: string;\n readonly entry: string;\n readonly dist: string;\n readonly ui?: { readonly dist: string; readonly widgets: readonly string[] };\n}\n\nfunction packageRootOf(entry: string): string {\n let directory = path.dirname(fs.realpathSync(entry));\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) throw new Error(`No package manifest owns ${entry}`);\n directory = parent;\n }\n}\n\nfunction packagePath(packageDir: string, field: string, value: unknown): string {\n if (typeof value !== 'string' || !value.startsWith('./') || value.includes('..'))\n throw new Error(`poMcp ${field} in ${packageDir} must be a package-relative ./path with no '..'.`);\n return value;\n}\n\nfunction declaredMcpPlugin(packageDir: string, manifest: Record<string, unknown>): DeclaredMcpPlugin | undefined {\n const value = manifest.poMcp;\n if (value === undefined) return undefined;\n if (typeof value !== 'object' || value === null || Array.isArray(value))\n throw new Error(`poMcp manifest in ${packageDir} must be an object.`);\n const declaration = value as Record<string, unknown>;\n if (!Array.isArray(declaration.scopes) || declaration.scopes.length !== 1 || declaration.scopes[0] !== 'session')\n throw new Error(`poMcp scopes in ${packageDir} must be exactly ['session'].`);\n const packageName = manifest.name;\n if (typeof packageName !== 'string' || packageName === '') throw new Error(`Package in ${packageDir} has no name.`);\n let ui: DeclaredMcpPlugin['ui'];\n if (declaration.ui !== undefined) {\n const value = declaration.ui as { dist?: unknown; widgets?: unknown } | null;\n if (\n typeof value !== 'object' ||\n value === null ||\n !Array.isArray(value.widgets) ||\n value.widgets.some((key: unknown) => typeof key !== 'string' || !key.startsWith(`${packageName}/`)) ||\n new Set(value.widgets).size !== value.widgets.length\n )\n throw new Error(`Invalid MCP widget manifest in ${packageDir}`);\n ui = { dist: packagePath(packageDir, 'ui.dist', value.dist), widgets: value.widgets as string[] };\n }\n return {\n packageName,\n packageDir,\n ...(ui === undefined ? {} : { ui }),\n entry: packagePath(packageDir, 'entry', declaration.entry),\n dist: packagePath(packageDir, 'dist', declaration.dist),\n };\n}\n\n/** One MCP plugin a composition set selects, with the built entry a host imports. */\nexport interface McpPluginCandidate {\n readonly declaration: DeclaredMcpPlugin;\n /** Absolute, symlink-resolved path of the package's built `dist` entry. */\n readonly module: string;\n /** Every major mode and layer that admitted the package. */\n readonly owners: readonly PoServerBundleOwner[];\n}\n\n/**\n * The MCP plugins the given compositions select, in first-selection order.\n *\n * A package that two different directories claim is ambiguous, and a built\n * entry that resolves outside its package is refused.\n */\nexport function mcpPluginCandidates(compositions: readonly ExtensionComposition[]): McpPluginCandidate[] {\n const packages = new Map<string, { declaration: DeclaredMcpPlugin; owners: PoServerBundleOwner[] }>();\n for (const composition of compositions) {\n const majorMode = composition.majorMode?.name;\n if (!majorMode) throw new Error('An MCP bundle composition needs its major mode');\n for (const root of new Set(composition.packageEntries.map(packageRootOf))) {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const declaration = declaredMcpPlugin(root, manifest);\n if (declaration === undefined) continue;\n const previous = packages.get(declaration.packageName);\n if (previous && previous.declaration.packageDir !== root)\n throw new Error(`Ambiguous MCP bundle package: ${declaration.packageName}`);\n const candidate = previous ?? { declaration, owners: [] };\n const layers = composition.selections\n .filter(\n (selection) => selection.outcome === 'resolved' && selection.path && packageRootOf(selection.path) === root,\n )\n .map((selection) => selection.layer);\n for (const layer of new Set(layers.length > 0 ? layers : ['default'])) {\n if (!candidate.owners.some((owner) => owner.majorMode === majorMode && owner.layer === layer))\n candidate.owners.push({ majorMode, layer });\n }\n packages.set(declaration.packageName, candidate);\n }\n }\n return [...packages.values()].map(({ declaration, owners }) => {\n const module = fs.realpathSync(path.resolve(declaration.packageDir, declaration.dist));\n const relative = path.relative(declaration.packageDir, module);\n if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))\n throw new Error(`MCP entry escapes package: ${declaration.packageName}`);\n return { declaration, module, owners };\n });\n}\n"],"mappings":"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"}
@@ -70,31 +70,38 @@ function inside(relative) {
70
70
  *
71
71
  * A target's whole top-level directory goes with it: bundlers split entries into
72
72
  * sibling chunks the entry imports relatively, so copying only the named file would
73
- * break the import graph.
73
+ * break the import graph. The manifest's `files` entries go too, because a module
74
+ * running from the snapshot reads its shipped resources (`src/prompts`, `README.md`)
75
+ * relative to the snapshot's `package.json`, not the source package.
74
76
  */
75
77
  function snapshotFiles(root, entry) {
76
78
  const manifest = JSON.parse(node_fs.default.readFileSync(node_path.default.join(root, "package.json"), "utf8"));
77
79
  const targets = [.../* @__PURE__ */ new Set([...declaredTargets(manifest), node_path.default.relative(root, entry)])].map((target) => node_path.default.normalize(target));
78
80
  const files = /* @__PURE__ */ new Set(["package.json"]);
81
+ const collect = (directory) => {
82
+ for (const dirent of node_fs.default.readdirSync(directory, { withFileTypes: true })) {
83
+ const file = node_path.default.join(directory, dirent.name);
84
+ if (dirent.isDirectory()) {
85
+ if (dirent.name !== "node_modules") collect(file);
86
+ } else if ((dirent.isFile() || dirent.isSymbolicLink()) && !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))) files.add(node_path.default.relative(root, file));
87
+ }
88
+ };
89
+ const add = (relative) => {
90
+ const absolute = node_path.default.join(root, relative);
91
+ if (node_fs.default.statSync(absolute).isDirectory()) collect(absolute);
92
+ else files.add(relative);
93
+ };
79
94
  for (const target of targets) {
80
95
  if (!inside(target) || target.split(node_path.default.sep)[0] === "node_modules") continue;
81
- const absolute = node_path.default.join(root, target);
82
- if (!node_fs.default.existsSync(absolute)) throw new Error(`declared entry is missing: ${target}`);
83
- const top = target.split(node_path.default.sep)[0];
84
- const topPath = node_path.default.join(root, top);
85
- if (top === target || !node_fs.default.statSync(topPath).isDirectory()) {
86
- files.add(target);
87
- continue;
88
- }
89
- const collect = (directory) => {
90
- for (const dirent of node_fs.default.readdirSync(directory, { withFileTypes: true })) {
91
- const file = node_path.default.join(directory, dirent.name);
92
- if (dirent.isDirectory()) {
93
- if (dirent.name !== "node_modules") collect(file);
94
- } else if ((dirent.isFile() || dirent.isSymbolicLink()) && !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))) files.add(node_path.default.relative(root, file));
95
- }
96
- };
97
- collect(topPath);
96
+ if (!node_fs.default.existsSync(node_path.default.join(root, target))) throw new Error(`declared entry is missing: ${target}`);
97
+ add(target.split(node_path.default.sep)[0]);
98
+ }
99
+ const shipped = Array.isArray(manifest.files) ? manifest.files : [];
100
+ for (const item of shipped) {
101
+ if (typeof item !== "string" || /[*?!]/.test(item)) continue;
102
+ const relative = node_path.default.normalize(item);
103
+ if (!inside(relative) || relative.split(node_path.default.sep)[0] === "node_modules") continue;
104
+ if (node_fs.default.existsSync(node_path.default.join(root, relative))) add(relative);
98
105
  }
99
106
  return [...files].sort();
100
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"packageUrl.cjs","names":["path","fs","crypto","pathToFileURL"],"sources":["../../../../src/builders/server/packageUrl.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/** Realpath fragments of version-scoped package stores: a new version is a new path. */\nconst VERSIONED_STORES = ['.upm', '.pnpm'].map((store) => `${path.sep}node_modules${path.sep}${store}${path.sep}`);\nexport const SNAPSHOT_DIRECTORY = path.join('node_modules', '.po-snapshots');\nconst SETTLE_MS = 300;\nconst STABLE_ATTEMPTS = 5;\n/** Build outputs a host never imports. */\nconst SKIPPED_SUFFIXES = ['.map', '.d.ts', '.d.mts', '.d.cts', '.tsbuildinfo'];\n\nexport interface PackageUrlOptions {\n /** Delay between the two content reads that prove a build is not in progress. */\n readonly settleMs?: number;\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface PackageUrls {\n /** The URL to import for a resolved entry file. Stable until the package content changes. */\n urlFor(entry: string): Promise<string>;\n /** Same as `urlFor`, as a file path, for loaders that take paths (po-hook). */\n pathFor(entry: string): Promise<string>;\n}\n\ninterface PackageState {\n signature: string;\n hash: string;\n pruned: boolean;\n}\n\nfunction packageRootOf(file: string): string | undefined {\n let directory = path.dirname(file);\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\nfunction isVersioned(root: string): boolean {\n return VERSIONED_STORES.some((store) => `${root}${path.sep}`.includes(store));\n}\n\nfunction exportTargets(value: unknown, condition: string | undefined, into: string[]): void {\n if (condition === 'types') return;\n if (typeof value === 'string') {\n if (!value.includes('*')) into.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) exportTargets(item, condition, into);\n return;\n }\n if (typeof value === 'object' && value !== null)\n for (const [key, item] of Object.entries(value)) exportTargets(item, key, into);\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Package-relative entry targets the manifest declares for a server-side host. */\nfunction declaredTargets(manifest: Record<string, unknown>): string[] {\n const targets: string[] = [];\n exportTargets(manifest.exports, undefined, targets);\n if (typeof manifest.main === 'string') targets.push(manifest.main);\n const pi = record(manifest.pi);\n if (Array.isArray(pi?.extensions))\n for (const entry of pi.extensions) if (typeof entry === 'string') targets.push(entry);\n const server = record(manifest.poServer);\n if (typeof server?.dist === 'string') targets.push(server.dist);\n const mcp = record(manifest.poMcp);\n if (typeof mcp?.dist === 'string') targets.push(mcp.dist);\n return targets;\n}\n\nfunction inside(relative: string): boolean {\n return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * The files a snapshot carries, package-relative and sorted.\n *\n * A target's whole top-level directory goes with it: bundlers split entries into\n * sibling chunks the entry imports relatively, so copying only the named file would\n * break the import graph.\n */\nexport function snapshotFiles(root: string, entry: string): string[] {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const targets = [...new Set([...declaredTargets(manifest), path.relative(root, entry)])].map((target) =>\n path.normalize(target),\n );\n const files = new Set<string>(['package.json']);\n for (const target of targets) {\n if (!inside(target) || target.split(path.sep)[0] === 'node_modules') continue;\n const absolute = path.join(root, target);\n if (!fs.existsSync(absolute)) throw new Error(`declared entry is missing: ${target}`);\n const top = target.split(path.sep)[0]!;\n const topPath = path.join(root, top);\n if (top === target || !fs.statSync(topPath).isDirectory()) {\n files.add(target);\n continue;\n }\n const collect = (directory: string): void => {\n for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, dirent.name);\n if (dirent.isDirectory()) {\n if (dirent.name !== 'node_modules') collect(file);\n } else if (\n (dirent.isFile() || dirent.isSymbolicLink()) &&\n !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))\n )\n files.add(path.relative(root, file));\n }\n };\n collect(topPath);\n }\n return [...files].sort();\n}\n\nexport function statSignature(root: string, files: readonly string[]): string {\n return files\n .map((file) => {\n const stat = fs.statSync(path.join(root, file));\n return `${file}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}`;\n })\n .join('\\n');\n}\n\nfunction contentHash(root: string, files: readonly string[]): string {\n const hash = crypto.createHash('sha256');\n for (const file of files) {\n hash.update(file).update('\\0');\n hash.update(fs.readFileSync(path.join(root, file))).update('\\0');\n }\n return hash.digest('hex').slice(0, 32);\n}\n\nfunction pruneOthers(snapshots: string, keep: string): void {\n if (!fs.existsSync(snapshots)) return;\n for (const name of fs.readdirSync(snapshots))\n if (name !== keep) fs.rmSync(path.join(snapshots, name), { recursive: true, force: true });\n}\n\n/**\n * Maps resolved package entries to import URLs that change only when content changes.\n *\n * A package under a versioned store imports in place: an upgrade is already a new path.\n * Any other package (repo-local, or npm-installed) is snapshotted by content into\n * `<package>/node_modules/.po-snapshots/<hash>/`, with its `package.json` so a\n * self-import by name resolves to the snapshot, while dependencies still resolve\n * from `<package>/node_modules`. A snapshot is taken only when every declared entry\n * exists and two reads `settleMs` apart agree, so a build in progress is never\n * captured. The first snapshot of a package in this process prunes its older ones;\n * later ones keep them, because live sessions may still lazily import from them.\n */\nexport function createPackageUrls(options: PackageUrlOptions = {}): PackageUrls {\n const settleMs = options.settleMs ?? SETTLE_MS;\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const states = new Map<string, PackageState>();\n const pending = new Map<string, Promise<string>>();\n\n const snapshot = async (root: string, entry: string): Promise<string> => {\n const snapshots = path.join(root, SNAPSHOT_DIRECTORY);\n for (let attempt = 0; attempt < STABLE_ATTEMPTS; attempt++) {\n const files = snapshotFiles(root, entry);\n const signature = statSignature(root, files);\n const previous = states.get(root);\n if (previous?.signature === signature && fs.existsSync(path.join(snapshots, previous.hash))) return previous.hash;\n const hash = contentHash(root, files);\n const target = path.join(snapshots, hash);\n if (!fs.existsSync(target)) {\n await sleep(settleMs);\n const settled = snapshotFiles(root, entry);\n if (settled.join('\\n') !== files.join('\\n') || contentHash(root, settled) !== hash) continue;\n const staging = path.join(snapshots, `.${hash}.${String(process.pid)}.${crypto.randomUUID()}`);\n for (const file of files) {\n fs.mkdirSync(path.dirname(path.join(staging, file)), { recursive: true });\n fs.copyFileSync(path.join(root, file), path.join(staging, file));\n }\n if (contentHash(staging, files) !== hash) {\n fs.rmSync(staging, { recursive: true, force: true });\n continue;\n }\n try {\n fs.renameSync(staging, target);\n } catch (error) {\n fs.rmSync(staging, { recursive: true, force: true });\n if (!fs.existsSync(target)) throw error;\n }\n }\n if (!previous?.pruned) pruneOthers(snapshots, hash);\n states.set(root, { signature, hash, pruned: true });\n return hash;\n }\n throw new Error(`package content kept changing while it was read: ${root}`);\n };\n\n const pathFor = async (entry: string): Promise<string> => {\n const real = fs.realpathSync(entry);\n const root = packageRootOf(real);\n // A file no package owns (a loose repository hook) has nothing to snapshot.\n if (root === undefined || isVersioned(root)) return real;\n const relative = path.relative(root, real);\n if (relative.split(path.sep)[0] === 'node_modules') return real;\n const key = `${root}\\0${relative}`;\n let running = pending.get(key);\n if (!running) {\n running = snapshot(root, real).finally(() => pending.delete(key));\n pending.set(key, running);\n }\n const hash = await running;\n return path.join(root, SNAPSHOT_DIRECTORY, hash, relative);\n };\n\n return { pathFor, urlFor: async (entry) => pathToFileURL(await pathFor(entry)).href };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"packageUrl.cjs","names":["path","fs","crypto","pathToFileURL"],"sources":["../../../../src/builders/server/packageUrl.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/** Realpath fragments of version-scoped package stores: a new version is a new path. */\nconst VERSIONED_STORES = ['.upm', '.pnpm'].map((store) => `${path.sep}node_modules${path.sep}${store}${path.sep}`);\nexport const SNAPSHOT_DIRECTORY = path.join('node_modules', '.po-snapshots');\nconst SETTLE_MS = 300;\nconst STABLE_ATTEMPTS = 5;\n/** Build outputs a host never imports. */\nconst SKIPPED_SUFFIXES = ['.map', '.d.ts', '.d.mts', '.d.cts', '.tsbuildinfo'];\n\nexport interface PackageUrlOptions {\n /** Delay between the two content reads that prove a build is not in progress. */\n readonly settleMs?: number;\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface PackageUrls {\n /** The URL to import for a resolved entry file. Stable until the package content changes. */\n urlFor(entry: string): Promise<string>;\n /** Same as `urlFor`, as a file path, for loaders that take paths (po-hook). */\n pathFor(entry: string): Promise<string>;\n}\n\ninterface PackageState {\n signature: string;\n hash: string;\n pruned: boolean;\n}\n\nfunction packageRootOf(file: string): string | undefined {\n let directory = path.dirname(file);\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\nfunction isVersioned(root: string): boolean {\n return VERSIONED_STORES.some((store) => `${root}${path.sep}`.includes(store));\n}\n\nfunction exportTargets(value: unknown, condition: string | undefined, into: string[]): void {\n if (condition === 'types') return;\n if (typeof value === 'string') {\n if (!value.includes('*')) into.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) exportTargets(item, condition, into);\n return;\n }\n if (typeof value === 'object' && value !== null)\n for (const [key, item] of Object.entries(value)) exportTargets(item, key, into);\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Package-relative entry targets the manifest declares for a server-side host. */\nfunction declaredTargets(manifest: Record<string, unknown>): string[] {\n const targets: string[] = [];\n exportTargets(manifest.exports, undefined, targets);\n if (typeof manifest.main === 'string') targets.push(manifest.main);\n const pi = record(manifest.pi);\n if (Array.isArray(pi?.extensions))\n for (const entry of pi.extensions) if (typeof entry === 'string') targets.push(entry);\n const server = record(manifest.poServer);\n if (typeof server?.dist === 'string') targets.push(server.dist);\n const mcp = record(manifest.poMcp);\n if (typeof mcp?.dist === 'string') targets.push(mcp.dist);\n return targets;\n}\n\nfunction inside(relative: string): boolean {\n return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * The files a snapshot carries, package-relative and sorted.\n *\n * A target's whole top-level directory goes with it: bundlers split entries into\n * sibling chunks the entry imports relatively, so copying only the named file would\n * break the import graph. The manifest's `files` entries go too, because a module\n * running from the snapshot reads its shipped resources (`src/prompts`, `README.md`)\n * relative to the snapshot's `package.json`, not the source package.\n */\nexport function snapshotFiles(root: string, entry: string): string[] {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const targets = [...new Set([...declaredTargets(manifest), path.relative(root, entry)])].map((target) =>\n path.normalize(target),\n );\n const files = new Set<string>(['package.json']);\n const collect = (directory: string): void => {\n for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, dirent.name);\n if (dirent.isDirectory()) {\n if (dirent.name !== 'node_modules') collect(file);\n } else if (\n (dirent.isFile() || dirent.isSymbolicLink()) &&\n !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))\n )\n files.add(path.relative(root, file));\n }\n };\n const add = (relative: string): void => {\n const absolute = path.join(root, relative);\n if (fs.statSync(absolute).isDirectory()) collect(absolute);\n else files.add(relative);\n };\n for (const target of targets) {\n if (!inside(target) || target.split(path.sep)[0] === 'node_modules') continue;\n if (!fs.existsSync(path.join(root, target))) throw new Error(`declared entry is missing: ${target}`);\n add(target.split(path.sep)[0]!);\n }\n // ponytail: plain `files` paths only; globs and negations are skipped, add a glob matcher if a package needs one.\n const shipped = Array.isArray(manifest.files) ? manifest.files : [];\n for (const item of shipped) {\n if (typeof item !== 'string' || /[*?!]/.test(item)) continue;\n const relative = path.normalize(item);\n if (!inside(relative) || relative.split(path.sep)[0] === 'node_modules') continue;\n if (fs.existsSync(path.join(root, relative))) add(relative);\n }\n return [...files].sort();\n}\n\nexport function statSignature(root: string, files: readonly string[]): string {\n return files\n .map((file) => {\n const stat = fs.statSync(path.join(root, file));\n return `${file}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}`;\n })\n .join('\\n');\n}\n\nfunction contentHash(root: string, files: readonly string[]): string {\n const hash = crypto.createHash('sha256');\n for (const file of files) {\n hash.update(file).update('\\0');\n hash.update(fs.readFileSync(path.join(root, file))).update('\\0');\n }\n return hash.digest('hex').slice(0, 32);\n}\n\nfunction pruneOthers(snapshots: string, keep: string): void {\n if (!fs.existsSync(snapshots)) return;\n for (const name of fs.readdirSync(snapshots))\n if (name !== keep) fs.rmSync(path.join(snapshots, name), { recursive: true, force: true });\n}\n\n/**\n * Maps resolved package entries to import URLs that change only when content changes.\n *\n * A package under a versioned store imports in place: an upgrade is already a new path.\n * Any other package (repo-local, or npm-installed) is snapshotted by content into\n * `<package>/node_modules/.po-snapshots/<hash>/`, with its `package.json` so a\n * self-import by name resolves to the snapshot, while dependencies still resolve\n * from `<package>/node_modules`. A snapshot is taken only when every declared entry\n * exists and two reads `settleMs` apart agree, so a build in progress is never\n * captured. The first snapshot of a package in this process prunes its older ones;\n * later ones keep them, because live sessions may still lazily import from them.\n */\nexport function createPackageUrls(options: PackageUrlOptions = {}): PackageUrls {\n const settleMs = options.settleMs ?? SETTLE_MS;\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const states = new Map<string, PackageState>();\n const pending = new Map<string, Promise<string>>();\n\n const snapshot = async (root: string, entry: string): Promise<string> => {\n const snapshots = path.join(root, SNAPSHOT_DIRECTORY);\n for (let attempt = 0; attempt < STABLE_ATTEMPTS; attempt++) {\n const files = snapshotFiles(root, entry);\n const signature = statSignature(root, files);\n const previous = states.get(root);\n if (previous?.signature === signature && fs.existsSync(path.join(snapshots, previous.hash))) return previous.hash;\n const hash = contentHash(root, files);\n const target = path.join(snapshots, hash);\n if (!fs.existsSync(target)) {\n await sleep(settleMs);\n const settled = snapshotFiles(root, entry);\n if (settled.join('\\n') !== files.join('\\n') || contentHash(root, settled) !== hash) continue;\n const staging = path.join(snapshots, `.${hash}.${String(process.pid)}.${crypto.randomUUID()}`);\n for (const file of files) {\n fs.mkdirSync(path.dirname(path.join(staging, file)), { recursive: true });\n fs.copyFileSync(path.join(root, file), path.join(staging, file));\n }\n if (contentHash(staging, files) !== hash) {\n fs.rmSync(staging, { recursive: true, force: true });\n continue;\n }\n try {\n fs.renameSync(staging, target);\n } catch (error) {\n fs.rmSync(staging, { recursive: true, force: true });\n if (!fs.existsSync(target)) throw error;\n }\n }\n if (!previous?.pruned) pruneOthers(snapshots, hash);\n states.set(root, { signature, hash, pruned: true });\n return hash;\n }\n throw new Error(`package content kept changing while it was read: ${root}`);\n };\n\n const pathFor = async (entry: string): Promise<string> => {\n const real = fs.realpathSync(entry);\n const root = packageRootOf(real);\n // A file no package owns (a loose repository hook) has nothing to snapshot.\n if (root === undefined || isVersioned(root)) return real;\n const relative = path.relative(root, real);\n if (relative.split(path.sep)[0] === 'node_modules') return real;\n const key = `${root}\\0${relative}`;\n let running = pending.get(key);\n if (!running) {\n running = snapshot(root, real).finally(() => pending.delete(key));\n pending.set(key, running);\n }\n const hash = await running;\n return path.join(root, SNAPSHOT_DIRECTORY, hash, relative);\n };\n\n return { pathFor, urlFor: async (entry) => pathToFileURL(await pathFor(entry)).href };\n}\n"],"mappings":"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"}
@@ -66,31 +66,38 @@ function inside(relative) {
66
66
  *
67
67
  * A target's whole top-level directory goes with it: bundlers split entries into
68
68
  * sibling chunks the entry imports relatively, so copying only the named file would
69
- * break the import graph.
69
+ * break the import graph. The manifest's `files` entries go too, because a module
70
+ * running from the snapshot reads its shipped resources (`src/prompts`, `README.md`)
71
+ * relative to the snapshot's `package.json`, not the source package.
70
72
  */
71
73
  function snapshotFiles(root, entry) {
72
74
  const manifest = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
73
75
  const targets = [.../* @__PURE__ */ new Set([...declaredTargets(manifest), path.relative(root, entry)])].map((target) => path.normalize(target));
74
76
  const files = /* @__PURE__ */ new Set(["package.json"]);
77
+ const collect = (directory) => {
78
+ for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {
79
+ const file = path.join(directory, dirent.name);
80
+ if (dirent.isDirectory()) {
81
+ if (dirent.name !== "node_modules") collect(file);
82
+ } else if ((dirent.isFile() || dirent.isSymbolicLink()) && !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))) files.add(path.relative(root, file));
83
+ }
84
+ };
85
+ const add = (relative) => {
86
+ const absolute = path.join(root, relative);
87
+ if (fs.statSync(absolute).isDirectory()) collect(absolute);
88
+ else files.add(relative);
89
+ };
75
90
  for (const target of targets) {
76
91
  if (!inside(target) || target.split(path.sep)[0] === "node_modules") continue;
77
- const absolute = path.join(root, target);
78
- if (!fs.existsSync(absolute)) throw new Error(`declared entry is missing: ${target}`);
79
- const top = target.split(path.sep)[0];
80
- const topPath = path.join(root, top);
81
- if (top === target || !fs.statSync(topPath).isDirectory()) {
82
- files.add(target);
83
- continue;
84
- }
85
- const collect = (directory) => {
86
- for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {
87
- const file = path.join(directory, dirent.name);
88
- if (dirent.isDirectory()) {
89
- if (dirent.name !== "node_modules") collect(file);
90
- } else if ((dirent.isFile() || dirent.isSymbolicLink()) && !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))) files.add(path.relative(root, file));
91
- }
92
- };
93
- collect(topPath);
92
+ if (!fs.existsSync(path.join(root, target))) throw new Error(`declared entry is missing: ${target}`);
93
+ add(target.split(path.sep)[0]);
94
+ }
95
+ const shipped = Array.isArray(manifest.files) ? manifest.files : [];
96
+ for (const item of shipped) {
97
+ if (typeof item !== "string" || /[*?!]/.test(item)) continue;
98
+ const relative = path.normalize(item);
99
+ if (!inside(relative) || relative.split(path.sep)[0] === "node_modules") continue;
100
+ if (fs.existsSync(path.join(root, relative))) add(relative);
94
101
  }
95
102
  return [...files].sort();
96
103
  }
@@ -1 +1 @@
1
- {"version":3,"file":"packageUrl.mjs","names":[],"sources":["../../../../src/builders/server/packageUrl.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/** Realpath fragments of version-scoped package stores: a new version is a new path. */\nconst VERSIONED_STORES = ['.upm', '.pnpm'].map((store) => `${path.sep}node_modules${path.sep}${store}${path.sep}`);\nexport const SNAPSHOT_DIRECTORY = path.join('node_modules', '.po-snapshots');\nconst SETTLE_MS = 300;\nconst STABLE_ATTEMPTS = 5;\n/** Build outputs a host never imports. */\nconst SKIPPED_SUFFIXES = ['.map', '.d.ts', '.d.mts', '.d.cts', '.tsbuildinfo'];\n\nexport interface PackageUrlOptions {\n /** Delay between the two content reads that prove a build is not in progress. */\n readonly settleMs?: number;\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface PackageUrls {\n /** The URL to import for a resolved entry file. Stable until the package content changes. */\n urlFor(entry: string): Promise<string>;\n /** Same as `urlFor`, as a file path, for loaders that take paths (po-hook). */\n pathFor(entry: string): Promise<string>;\n}\n\ninterface PackageState {\n signature: string;\n hash: string;\n pruned: boolean;\n}\n\nfunction packageRootOf(file: string): string | undefined {\n let directory = path.dirname(file);\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\nfunction isVersioned(root: string): boolean {\n return VERSIONED_STORES.some((store) => `${root}${path.sep}`.includes(store));\n}\n\nfunction exportTargets(value: unknown, condition: string | undefined, into: string[]): void {\n if (condition === 'types') return;\n if (typeof value === 'string') {\n if (!value.includes('*')) into.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) exportTargets(item, condition, into);\n return;\n }\n if (typeof value === 'object' && value !== null)\n for (const [key, item] of Object.entries(value)) exportTargets(item, key, into);\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Package-relative entry targets the manifest declares for a server-side host. */\nfunction declaredTargets(manifest: Record<string, unknown>): string[] {\n const targets: string[] = [];\n exportTargets(manifest.exports, undefined, targets);\n if (typeof manifest.main === 'string') targets.push(manifest.main);\n const pi = record(manifest.pi);\n if (Array.isArray(pi?.extensions))\n for (const entry of pi.extensions) if (typeof entry === 'string') targets.push(entry);\n const server = record(manifest.poServer);\n if (typeof server?.dist === 'string') targets.push(server.dist);\n const mcp = record(manifest.poMcp);\n if (typeof mcp?.dist === 'string') targets.push(mcp.dist);\n return targets;\n}\n\nfunction inside(relative: string): boolean {\n return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * The files a snapshot carries, package-relative and sorted.\n *\n * A target's whole top-level directory goes with it: bundlers split entries into\n * sibling chunks the entry imports relatively, so copying only the named file would\n * break the import graph.\n */\nexport function snapshotFiles(root: string, entry: string): string[] {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const targets = [...new Set([...declaredTargets(manifest), path.relative(root, entry)])].map((target) =>\n path.normalize(target),\n );\n const files = new Set<string>(['package.json']);\n for (const target of targets) {\n if (!inside(target) || target.split(path.sep)[0] === 'node_modules') continue;\n const absolute = path.join(root, target);\n if (!fs.existsSync(absolute)) throw new Error(`declared entry is missing: ${target}`);\n const top = target.split(path.sep)[0]!;\n const topPath = path.join(root, top);\n if (top === target || !fs.statSync(topPath).isDirectory()) {\n files.add(target);\n continue;\n }\n const collect = (directory: string): void => {\n for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, dirent.name);\n if (dirent.isDirectory()) {\n if (dirent.name !== 'node_modules') collect(file);\n } else if (\n (dirent.isFile() || dirent.isSymbolicLink()) &&\n !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))\n )\n files.add(path.relative(root, file));\n }\n };\n collect(topPath);\n }\n return [...files].sort();\n}\n\nexport function statSignature(root: string, files: readonly string[]): string {\n return files\n .map((file) => {\n const stat = fs.statSync(path.join(root, file));\n return `${file}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}`;\n })\n .join('\\n');\n}\n\nfunction contentHash(root: string, files: readonly string[]): string {\n const hash = crypto.createHash('sha256');\n for (const file of files) {\n hash.update(file).update('\\0');\n hash.update(fs.readFileSync(path.join(root, file))).update('\\0');\n }\n return hash.digest('hex').slice(0, 32);\n}\n\nfunction pruneOthers(snapshots: string, keep: string): void {\n if (!fs.existsSync(snapshots)) return;\n for (const name of fs.readdirSync(snapshots))\n if (name !== keep) fs.rmSync(path.join(snapshots, name), { recursive: true, force: true });\n}\n\n/**\n * Maps resolved package entries to import URLs that change only when content changes.\n *\n * A package under a versioned store imports in place: an upgrade is already a new path.\n * Any other package (repo-local, or npm-installed) is snapshotted by content into\n * `<package>/node_modules/.po-snapshots/<hash>/`, with its `package.json` so a\n * self-import by name resolves to the snapshot, while dependencies still resolve\n * from `<package>/node_modules`. A snapshot is taken only when every declared entry\n * exists and two reads `settleMs` apart agree, so a build in progress is never\n * captured. The first snapshot of a package in this process prunes its older ones;\n * later ones keep them, because live sessions may still lazily import from them.\n */\nexport function createPackageUrls(options: PackageUrlOptions = {}): PackageUrls {\n const settleMs = options.settleMs ?? SETTLE_MS;\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const states = new Map<string, PackageState>();\n const pending = new Map<string, Promise<string>>();\n\n const snapshot = async (root: string, entry: string): Promise<string> => {\n const snapshots = path.join(root, SNAPSHOT_DIRECTORY);\n for (let attempt = 0; attempt < STABLE_ATTEMPTS; attempt++) {\n const files = snapshotFiles(root, entry);\n const signature = statSignature(root, files);\n const previous = states.get(root);\n if (previous?.signature === signature && fs.existsSync(path.join(snapshots, previous.hash))) return previous.hash;\n const hash = contentHash(root, files);\n const target = path.join(snapshots, hash);\n if (!fs.existsSync(target)) {\n await sleep(settleMs);\n const settled = snapshotFiles(root, entry);\n if (settled.join('\\n') !== files.join('\\n') || contentHash(root, settled) !== hash) continue;\n const staging = path.join(snapshots, `.${hash}.${String(process.pid)}.${crypto.randomUUID()}`);\n for (const file of files) {\n fs.mkdirSync(path.dirname(path.join(staging, file)), { recursive: true });\n fs.copyFileSync(path.join(root, file), path.join(staging, file));\n }\n if (contentHash(staging, files) !== hash) {\n fs.rmSync(staging, { recursive: true, force: true });\n continue;\n }\n try {\n fs.renameSync(staging, target);\n } catch (error) {\n fs.rmSync(staging, { recursive: true, force: true });\n if (!fs.existsSync(target)) throw error;\n }\n }\n if (!previous?.pruned) pruneOthers(snapshots, hash);\n states.set(root, { signature, hash, pruned: true });\n return hash;\n }\n throw new Error(`package content kept changing while it was read: ${root}`);\n };\n\n const pathFor = async (entry: string): Promise<string> => {\n const real = fs.realpathSync(entry);\n const root = packageRootOf(real);\n // A file no package owns (a loose repository hook) has nothing to snapshot.\n if (root === undefined || isVersioned(root)) return real;\n const relative = path.relative(root, real);\n if (relative.split(path.sep)[0] === 'node_modules') return real;\n const key = `${root}\\0${relative}`;\n let running = pending.get(key);\n if (!running) {\n running = snapshot(root, real).finally(() => pending.delete(key));\n pending.set(key, running);\n }\n const hash = await running;\n return path.join(root, SNAPSHOT_DIRECTORY, hash, relative);\n };\n\n return { pathFor, urlFor: async (entry) => pathToFileURL(await pathFor(entry)).href };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"packageUrl.mjs","names":[],"sources":["../../../../src/builders/server/packageUrl.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/** Realpath fragments of version-scoped package stores: a new version is a new path. */\nconst VERSIONED_STORES = ['.upm', '.pnpm'].map((store) => `${path.sep}node_modules${path.sep}${store}${path.sep}`);\nexport const SNAPSHOT_DIRECTORY = path.join('node_modules', '.po-snapshots');\nconst SETTLE_MS = 300;\nconst STABLE_ATTEMPTS = 5;\n/** Build outputs a host never imports. */\nconst SKIPPED_SUFFIXES = ['.map', '.d.ts', '.d.mts', '.d.cts', '.tsbuildinfo'];\n\nexport interface PackageUrlOptions {\n /** Delay between the two content reads that prove a build is not in progress. */\n readonly settleMs?: number;\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface PackageUrls {\n /** The URL to import for a resolved entry file. Stable until the package content changes. */\n urlFor(entry: string): Promise<string>;\n /** Same as `urlFor`, as a file path, for loaders that take paths (po-hook). */\n pathFor(entry: string): Promise<string>;\n}\n\ninterface PackageState {\n signature: string;\n hash: string;\n pruned: boolean;\n}\n\nfunction packageRootOf(file: string): string | undefined {\n let directory = path.dirname(file);\n for (;;) {\n if (fs.existsSync(path.join(directory, 'package.json'))) return directory;\n const parent = path.dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n\nfunction isVersioned(root: string): boolean {\n return VERSIONED_STORES.some((store) => `${root}${path.sep}`.includes(store));\n}\n\nfunction exportTargets(value: unknown, condition: string | undefined, into: string[]): void {\n if (condition === 'types') return;\n if (typeof value === 'string') {\n if (!value.includes('*')) into.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) exportTargets(item, condition, into);\n return;\n }\n if (typeof value === 'object' && value !== null)\n for (const [key, item] of Object.entries(value)) exportTargets(item, key, into);\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Package-relative entry targets the manifest declares for a server-side host. */\nfunction declaredTargets(manifest: Record<string, unknown>): string[] {\n const targets: string[] = [];\n exportTargets(manifest.exports, undefined, targets);\n if (typeof manifest.main === 'string') targets.push(manifest.main);\n const pi = record(manifest.pi);\n if (Array.isArray(pi?.extensions))\n for (const entry of pi.extensions) if (typeof entry === 'string') targets.push(entry);\n const server = record(manifest.poServer);\n if (typeof server?.dist === 'string') targets.push(server.dist);\n const mcp = record(manifest.poMcp);\n if (typeof mcp?.dist === 'string') targets.push(mcp.dist);\n return targets;\n}\n\nfunction inside(relative: string): boolean {\n return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * The files a snapshot carries, package-relative and sorted.\n *\n * A target's whole top-level directory goes with it: bundlers split entries into\n * sibling chunks the entry imports relatively, so copying only the named file would\n * break the import graph. The manifest's `files` entries go too, because a module\n * running from the snapshot reads its shipped resources (`src/prompts`, `README.md`)\n * relative to the snapshot's `package.json`, not the source package.\n */\nexport function snapshotFiles(root: string, entry: string): string[] {\n const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as Record<string, unknown>;\n const targets = [...new Set([...declaredTargets(manifest), path.relative(root, entry)])].map((target) =>\n path.normalize(target),\n );\n const files = new Set<string>(['package.json']);\n const collect = (directory: string): void => {\n for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, dirent.name);\n if (dirent.isDirectory()) {\n if (dirent.name !== 'node_modules') collect(file);\n } else if (\n (dirent.isFile() || dirent.isSymbolicLink()) &&\n !SKIPPED_SUFFIXES.some((suffix) => dirent.name.endsWith(suffix))\n )\n files.add(path.relative(root, file));\n }\n };\n const add = (relative: string): void => {\n const absolute = path.join(root, relative);\n if (fs.statSync(absolute).isDirectory()) collect(absolute);\n else files.add(relative);\n };\n for (const target of targets) {\n if (!inside(target) || target.split(path.sep)[0] === 'node_modules') continue;\n if (!fs.existsSync(path.join(root, target))) throw new Error(`declared entry is missing: ${target}`);\n add(target.split(path.sep)[0]!);\n }\n // ponytail: plain `files` paths only; globs and negations are skipped, add a glob matcher if a package needs one.\n const shipped = Array.isArray(manifest.files) ? manifest.files : [];\n for (const item of shipped) {\n if (typeof item !== 'string' || /[*?!]/.test(item)) continue;\n const relative = path.normalize(item);\n if (!inside(relative) || relative.split(path.sep)[0] === 'node_modules') continue;\n if (fs.existsSync(path.join(root, relative))) add(relative);\n }\n return [...files].sort();\n}\n\nexport function statSignature(root: string, files: readonly string[]): string {\n return files\n .map((file) => {\n const stat = fs.statSync(path.join(root, file));\n return `${file}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}`;\n })\n .join('\\n');\n}\n\nfunction contentHash(root: string, files: readonly string[]): string {\n const hash = crypto.createHash('sha256');\n for (const file of files) {\n hash.update(file).update('\\0');\n hash.update(fs.readFileSync(path.join(root, file))).update('\\0');\n }\n return hash.digest('hex').slice(0, 32);\n}\n\nfunction pruneOthers(snapshots: string, keep: string): void {\n if (!fs.existsSync(snapshots)) return;\n for (const name of fs.readdirSync(snapshots))\n if (name !== keep) fs.rmSync(path.join(snapshots, name), { recursive: true, force: true });\n}\n\n/**\n * Maps resolved package entries to import URLs that change only when content changes.\n *\n * A package under a versioned store imports in place: an upgrade is already a new path.\n * Any other package (repo-local, or npm-installed) is snapshotted by content into\n * `<package>/node_modules/.po-snapshots/<hash>/`, with its `package.json` so a\n * self-import by name resolves to the snapshot, while dependencies still resolve\n * from `<package>/node_modules`. A snapshot is taken only when every declared entry\n * exists and two reads `settleMs` apart agree, so a build in progress is never\n * captured. The first snapshot of a package in this process prunes its older ones;\n * later ones keep them, because live sessions may still lazily import from them.\n */\nexport function createPackageUrls(options: PackageUrlOptions = {}): PackageUrls {\n const settleMs = options.settleMs ?? SETTLE_MS;\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const states = new Map<string, PackageState>();\n const pending = new Map<string, Promise<string>>();\n\n const snapshot = async (root: string, entry: string): Promise<string> => {\n const snapshots = path.join(root, SNAPSHOT_DIRECTORY);\n for (let attempt = 0; attempt < STABLE_ATTEMPTS; attempt++) {\n const files = snapshotFiles(root, entry);\n const signature = statSignature(root, files);\n const previous = states.get(root);\n if (previous?.signature === signature && fs.existsSync(path.join(snapshots, previous.hash))) return previous.hash;\n const hash = contentHash(root, files);\n const target = path.join(snapshots, hash);\n if (!fs.existsSync(target)) {\n await sleep(settleMs);\n const settled = snapshotFiles(root, entry);\n if (settled.join('\\n') !== files.join('\\n') || contentHash(root, settled) !== hash) continue;\n const staging = path.join(snapshots, `.${hash}.${String(process.pid)}.${crypto.randomUUID()}`);\n for (const file of files) {\n fs.mkdirSync(path.dirname(path.join(staging, file)), { recursive: true });\n fs.copyFileSync(path.join(root, file), path.join(staging, file));\n }\n if (contentHash(staging, files) !== hash) {\n fs.rmSync(staging, { recursive: true, force: true });\n continue;\n }\n try {\n fs.renameSync(staging, target);\n } catch (error) {\n fs.rmSync(staging, { recursive: true, force: true });\n if (!fs.existsSync(target)) throw error;\n }\n }\n if (!previous?.pruned) pruneOthers(snapshots, hash);\n states.set(root, { signature, hash, pruned: true });\n return hash;\n }\n throw new Error(`package content kept changing while it was read: ${root}`);\n };\n\n const pathFor = async (entry: string): Promise<string> => {\n const real = fs.realpathSync(entry);\n const root = packageRootOf(real);\n // A file no package owns (a loose repository hook) has nothing to snapshot.\n if (root === undefined || isVersioned(root)) return real;\n const relative = path.relative(root, real);\n if (relative.split(path.sep)[0] === 'node_modules') return real;\n const key = `${root}\\0${relative}`;\n let running = pending.get(key);\n if (!running) {\n running = snapshot(root, real).finally(() => pending.delete(key));\n pending.set(key, running);\n }\n const hash = await running;\n return path.join(root, SNAPSHOT_DIRECTORY, hash, relative);\n };\n\n return { pathFor, urlFor: async (entry) => pathToFileURL(await pathFor(entry)).href };\n}\n"],"mappings":"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"}