@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 +1 @@
1
- {"version":3,"file":"localBuilds.mjs","names":[],"sources":["../../../../src/composition/syncService/localBuilds.ts"],"sourcesContent":["import { type ChildProcess, spawn, spawnSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { writeFileAtomic } from '@agimon-ai/po-core/runtimeJson';\n\n/**\n * Builds the packages sync roots name by local path, so the web, native and MCP builds read\n * current output. Each package builds at most once per sync, in dependency order within the\n * local set, with the package manager its nearest lockfile names. Install never runs.\n */\n\nconst LOCAL_SOURCE_DIRECTORY = 'src';\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst LOCAL_BUILDS_FILE = path.join('build', 'local-builds.json');\nconst BUILD_SCRIPT = 'build';\nconst STDERR_TAIL_LINES = 20;\n/** Bytes of stderr kept per build while it runs; older output is dropped as it arrives. */\nconst STDERR_TAIL_BYTES = 64 * 1024;\n/**\n * A local build that runs longer than this is stopped and reported as failed. Sync holds its\n * lock while a build runs, so a hung build must not hold it forever.\n */\nexport const LOCAL_BUILD_TIMEOUT_MS = 10 * 60 * 1000;\n/** How long a build's stderr may stay open after it exits, held by a process it left running. */\nconst STDERR_CLOSE_GRACE_MS = 1000;\nconst MILLISECONDS_PER_SECOND = 1000;\nconst LOGIN_SHELL_TIMEOUT_MS = 10_000;\nconst DEFAULT_PACKAGE_MANAGER = 'npm';\nconst NO_SUCH_PROCESS = 'ESRCH';\n/** Checked nearest-first in each folder; the first lockfile found names the package manager. */\nconst LOCKFILES: readonly (readonly [string, string])[] = [\n ['pnpm-lock.yaml', 'pnpm'],\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n/** Variables a Po session or another harness exports; a package build must not see them. */\nconst HARNESS_PREFIXES = ['PO_', 'PI_', 'CLAUDE_', 'CODEX_'];\nconst HARNESS_VARIABLES = new Set(['CLAUDECODE', 'MCP_UI_VIEWER', 'npm_config_user_agent']);\nconst DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];\n\nexport interface LocalPackage {\n /** The selector as a root's configuration names it. */\n selector: string;\n directory: string;\n}\n\nexport type LocalBuildOutcome =\n | { status: 'built' | 'cached' }\n | { status: 'failed'; reason: string; stderr?: string[] };\n\nexport interface LocalBuildInput {\n globalRoot: string;\n environment: NodeJS.ProcessEnv;\n directories: readonly string[];\n /** Receives each command line as it starts. */\n onCommand: (command: string) => void;\n onNotice: (message: string) => void;\n /** Overrides `LOCAL_BUILD_TIMEOUT_MS`. */\n timeoutMs?: number;\n}\n\ninterface Manifest {\n name?: string;\n main?: unknown;\n module?: unknown;\n exports?: unknown;\n scripts?: Record<string, unknown>;\n [field: string]: unknown;\n}\n\nfunction sourceFiles(directory: string): string[] {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(directory, { withFileTypes: true });\n } catch {\n // A package without a source folder has only its manifest to stamp.\n return [];\n }\n return entries.flatMap((entry) => {\n const full = path.join(directory, entry.name);\n if (entry.isDirectory()) return entry.name === NODE_MODULES ? [] : sourceFiles(full);\n return entry.isFile() ? [full] : [];\n });\n}\n\n/**\n * The build stamp of a local package: an mtime and size signature over its `package.json`\n * and every file under `src/`.\n * ponytail: it misses edits to dependencies outside the package; a content hash is the upgrade.\n */\nexport function localBuildStamp(packageDirectory: string): string {\n const files = [\n path.join(packageDirectory, PACKAGE_MANIFEST),\n ...sourceFiles(path.join(packageDirectory, LOCAL_SOURCE_DIRECTORY)),\n ];\n const hash = crypto.createHash('sha256');\n for (const file of files.sort()) {\n const relative = path.relative(packageDirectory, file);\n try {\n const stat = fs.statSync(file);\n hash.update(`${relative}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}\\n`);\n } catch {\n // Recorded as missing, so the stamp moves when the file appears.\n hash.update(`${relative}\\0missing\\n`);\n }\n }\n return hash.digest('hex');\n}\n\nexport function localBuildsPath(globalRoot: string): string {\n return path.join(globalRoot, LOCAL_BUILDS_FILE);\n}\n\nfunction readStamps(globalRoot: string): Record<string, string> {\n try {\n const parsed = JSON.parse(fs.readFileSync(localBuildsPath(globalRoot), 'utf8')) as unknown;\n return typeof parsed === 'object' && parsed !== null ? (parsed as Record<string, string>) : {};\n } catch {\n // Missing or unreadable: every package builds once.\n return {};\n }\n}\n\nfunction readManifest(directory: string): Manifest | undefined {\n try {\n return JSON.parse(fs.readFileSync(path.join(directory, PACKAGE_MANIFEST), 'utf8')) as Manifest;\n } catch {\n return undefined;\n }\n}\n\n/** The package manager the nearest lockfile names, walking up from the package. */\nexport function packageManagerFor(directory: string): string {\n let current = path.resolve(directory);\n for (;;) {\n for (const [lockfile, manager] of LOCKFILES) if (fs.existsSync(path.join(current, lockfile))) return manager;\n const parent = path.dirname(current);\n if (parent === current) return DEFAULT_PACKAGE_MANAGER;\n current = parent;\n }\n}\n\nfunction findOnPath(binary: string, searchPath: string | undefined): string | undefined {\n for (const directory of (searchPath ?? '').split(path.delimiter).filter(Boolean)) {\n const candidate = path.join(directory, binary);\n try {\n fs.accessSync(candidate, fs.constants.X_OK);\n if (fs.statSync(candidate).isFile()) return candidate;\n } catch {\n // Not in this folder.\n }\n }\n return undefined;\n}\n\n/**\n * The login shell's PATH. Desktop apps launched from Finder get a minimal PATH (inferred,\n * not checked here), so a package manager installed through a shell profile is missing.\n */\nfunction loginShellPath(environment: NodeJS.ProcessEnv): string | undefined {\n const shell = environment.SHELL ?? '/bin/zsh';\n const result = spawnSync(shell, ['-ilc', 'printf %s \"$PATH\"'], {\n encoding: 'utf8',\n timeout: LOGIN_SHELL_TIMEOUT_MS,\n });\n return result.status === 0 && result.stdout.trim() !== '' ? result.stdout.trim() : undefined;\n}\n\n/** The build environment: the caller's minus every `PO_*` and harness variable. */\nexport function buildEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n return Object.fromEntries(\n Object.entries(environment).filter(\n ([name]) => !HARNESS_VARIABLES.has(name) && !HARNESS_PREFIXES.some((prefix) => name.startsWith(prefix)),\n ),\n );\n}\n\nfunction entryPaths(value: unknown): string[] {\n if (typeof value === 'string') return [value];\n if (Array.isArray(value)) return value.flatMap(entryPaths);\n if (typeof value === 'object' && value !== null) return Object.values(value).flatMap(entryPaths);\n return [];\n}\n\n/** Whether every file `main`, `module` and `exports` name exists; false when they name none. */\nfunction builtEntriesPresent(directory: string, manifest: Manifest): boolean {\n const entries = [manifest.main, manifest.module, manifest.exports]\n .flatMap(entryPaths)\n .filter((entry) => !entry.includes('*'));\n return entries.length > 0 && entries.every((entry) => fs.existsSync(path.resolve(directory, entry)));\n}\n\n/** The directories ordered so each local package builds after the local packages it depends on. */\nfunction dependencyOrder(directories: readonly string[], manifests: Map<string, Manifest | undefined>): string[] {\n const byName = new Map<string, string>();\n for (const directory of directories) {\n const name = manifests.get(directory)?.name;\n if (name !== undefined) byName.set(name, directory);\n }\n const ordered: string[] = [];\n const visiting = new Set<string>();\n const visit = (directory: string): void => {\n if (ordered.includes(directory) || visiting.has(directory)) return;\n visiting.add(directory);\n const manifest = manifests.get(directory);\n for (const field of DEPENDENCY_FIELDS) {\n const dependencies = manifest?.[field];\n if (typeof dependencies !== 'object' || dependencies === null) continue;\n for (const name of Object.keys(dependencies)) {\n const dependency = byName.get(name);\n if (dependency !== undefined) visit(dependency);\n }\n }\n visiting.delete(directory);\n ordered.push(directory);\n };\n for (const directory of directories) visit(directory);\n return ordered;\n}\n\nfunction stderrTail(stderr: string): string[] {\n return stderr.trimEnd().split('\\n').filter(Boolean).slice(-STDERR_TAIL_LINES);\n}\n\ninterface BuildRun {\n status: number | null;\n signal: NodeJS.Signals | null;\n error?: Error;\n timedOut: boolean;\n /** It exited while a process it started still held stderr open; that process was stopped. */\n leftRunning: boolean;\n /** The last `STDERR_TAIL_BYTES` of stderr. */\n stderr: string;\n}\n\n/** Signals that end this process; a build in its own process group would not receive them. */\nconst FORWARDED_SIGNALS: readonly NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGHUP'];\nconst SEPARATE_PROCESS_GROUPS = process.platform !== 'win32';\n\n/**\n * Kills the build and everything it started. The build leads its own process group, so the\n * package manager's tsc or vite children die with it.\n * ponytail: Windows has no process groups here, so only the package manager is killed there;\n * `taskkill /T /F` is the upgrade if Windows builds must stop their children too.\n */\nfunction killBuild(child: ChildProcess): void {\n if (!SEPARATE_PROCESS_GROUPS || child.pid === undefined) {\n child.kill('SIGKILL');\n return;\n }\n try {\n process.kill(-child.pid, 'SIGKILL');\n } catch (error) {\n // ESRCH: every process of the group has exited already, which is the goal. Anything else\n // (EPERM) falls back to the package manager alone rather than crash inside a timer.\n if ((error as NodeJS.ErrnoException).code !== NO_SUCH_PROCESS) child.kill('SIGKILL');\n }\n}\n\n/**\n * Runs one build script without buffering its output: stdout is discarded and only the stderr\n * tail is kept. A build still running after `timeoutMs` is killed with every process it started\n * and reported as timed out. A build that exits while something it started still holds stderr\n * open has that process group killed when the grace ends, so nothing writes after it returns.\n */\nfunction runBuildScript(\n binary: string,\n directory: string,\n environment: NodeJS.ProcessEnv,\n timeoutMs: number,\n): Promise<BuildRun> {\n return new Promise((resolve) => {\n let tail = Buffer.alloc(0);\n let timedOut = false;\n let leftRunning = false;\n let settled = false;\n let grace: NodeJS.Timeout | undefined;\n // Its own process group, so a kill reaches its children. Still awaited: never unref'd.\n const child = spawn(binary, ['run', BUILD_SCRIPT], {\n cwd: directory,\n env: environment,\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: SEPARATE_PROCESS_GROUPS,\n });\n // A detached build no longer gets the terminal's Ctrl+C, so this process passes it on.\n const forward = (signal: NodeJS.Signals): void => {\n killBuild(child);\n if (process.listenerCount(signal) > 1) return;\n // Only this handler was listening: end as the signal would have without it.\n process.removeListener(signal, forward);\n process.kill(process.pid, signal);\n };\n if (SEPARATE_PROCESS_GROUPS) for (const signal of FORWARDED_SIGNALS) process.on(signal, forward);\n const finish = (result: Pick<BuildRun, 'status' | 'signal' | 'error'>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(grace);\n for (const signal of FORWARDED_SIGNALS) process.removeListener(signal, forward);\n child.stderr?.destroy();\n resolve({ ...result, timedOut, leftRunning, stderr: tail.toString('utf8') });\n };\n const timer = setTimeout(() => {\n timedOut = true;\n killBuild(child);\n }, timeoutMs);\n child.stderr?.on('data', (chunk: Buffer) => {\n tail = Buffer.concat([tail, chunk]);\n if (tail.length > STDERR_TAIL_BYTES) tail = tail.subarray(tail.length - STDERR_TAIL_BYTES);\n });\n child.on('error', (error) => finish({ status: null, signal: null, error }));\n child.on('close', (status, signal) => finish({ status, signal }));\n // A process the build left running can hold stderr open, so 'close' may never come.\n child.on('exit', (status, signal) => {\n grace = setTimeout(\n () => {\n if (!timedOut) leftRunning = true;\n killBuild(child);\n finish({ status, signal });\n },\n timedOut ? 0 : STDERR_CLOSE_GRACE_MS,\n );\n });\n });\n}\n\n/**\n * Builds every local package that changed since its last successful build, and returns each\n * directory's outcome. A failure never stops the others.\n */\nexport async function buildLocalPackages(input: LocalBuildInput): Promise<Map<string, LocalBuildOutcome>> {\n const { globalRoot, environment, onCommand, onNotice } = input;\n const timeoutMs = input.timeoutMs ?? LOCAL_BUILD_TIMEOUT_MS;\n const directories = [...new Set(input.directories)];\n const manifests = new Map(directories.map((directory) => [directory, readManifest(directory)]));\n const stamps = readStamps(globalRoot);\n const outcomes = new Map<string, LocalBuildOutcome>();\n const childEnvironment = buildEnvironment(environment);\n let searchPath = environment.PATH;\n let loginPathTried = false;\n const resolveBinary = (manager: string): string | undefined => {\n const found = findOnPath(manager, searchPath);\n if (found !== undefined || loginPathTried || process.platform !== 'darwin') return found;\n loginPathTried = true;\n const loginPath = loginShellPath(environment);\n if (loginPath === undefined) return undefined;\n searchPath = loginPath;\n childEnvironment.PATH = loginPath;\n return findOnPath(manager, searchPath);\n };\n\n for (const directory of dependencyOrder(directories, manifests)) {\n const manifest = manifests.get(directory);\n if (manifest === undefined) {\n outcomes.set(directory, { status: 'failed', reason: `'${directory}' has no readable package.json` });\n continue;\n }\n const stamp = localBuildStamp(directory);\n // ponytail: an unchanged stamp skips the build even when a dependency outside the\n // package changed; a content hash over the dependency closure is the upgrade.\n if (stamps[directory] === stamp) {\n outcomes.set(directory, { status: 'cached' });\n continue;\n }\n if (typeof manifest.scripts?.[BUILD_SCRIPT] !== 'string') {\n outcomes.set(\n directory,\n builtEntriesPresent(directory, manifest)\n ? { status: 'cached' }\n : { status: 'failed', reason: 'it has no build script and no built entries' },\n );\n continue;\n }\n const manager = packageManagerFor(directory);\n const binary = resolveBinary(manager);\n if (binary === undefined) {\n outcomes.set(directory, { status: 'failed', reason: `${manager} is not on PATH` });\n continue;\n }\n const command = `${binary} run ${BUILD_SCRIPT} (in ${directory})`;\n onCommand(command);\n onNotice(`building ${manifest.name ?? directory}`);\n const result = await runBuildScript(binary, directory, childEnvironment, timeoutMs);\n if (result.status === 0 && !result.timedOut && !result.leftRunning) {\n // The stamp after the build, as the sync pointer records it: a build that writes into\n // src/ or package.json must not look changed to the next sync.\n stamps[directory] = localBuildStamp(directory);\n writeFileAtomic(localBuildsPath(globalRoot), `${JSON.stringify(stamps, null, 2)}\\n`);\n outcomes.set(directory, { status: 'built' });\n continue;\n }\n const exit = result.timedOut\n ? `timed out after ${String(timeoutMs / MILLISECONDS_PER_SECOND)} s`\n : result.status === 0 && result.leftRunning\n ? 'it exited but left processes running, which were stopped'\n : (result.error?.message ?? `exit ${String(result.status ?? result.signal)}`);\n outcomes.set(directory, {\n status: 'failed',\n reason: `${manager} run ${BUILD_SCRIPT} failed (${exit})`,\n stderr: stderrTail(result.stderr),\n });\n }\n return outcomes;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"localBuilds.mjs","names":[],"sources":["../../../../src/composition/syncService/localBuilds.ts"],"sourcesContent":["import { type ChildProcess, spawn, spawnSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { writeFileAtomic } from '@agimon-ai/po-core/runtimeJson';\nimport { getValidatedTestContext } from '@agimon-ai/po-core/testMode';\n\n/**\n * Builds the packages sync roots name by local path, so the web, native and MCP builds read\n * current output. Each package builds at most once per sync, in dependency order within the\n * local set, with the package manager its nearest lockfile names. Install never runs.\n */\n\nconst LOCAL_SOURCE_DIRECTORY = 'src';\nconst PACKAGE_MANIFEST = 'package.json';\nconst NODE_MODULES = 'node_modules';\nconst LOCAL_BUILDS_FILE = path.join('build', 'local-builds.json');\nconst BUILD_SCRIPT = 'build';\nconst STDERR_TAIL_LINES = 20;\n/** Bytes of stderr kept per build while it runs; older output is dropped as it arrives. */\nconst STDERR_TAIL_BYTES = 64 * 1024;\n/**\n * A local build that runs longer than this is stopped and reported as failed. Sync holds its\n * lock while a build runs, so a hung build must not hold it forever.\n */\nexport const LOCAL_BUILD_TIMEOUT_MS = 10 * 60 * 1000;\n/** How long a build's stderr may stay open after it exits, held by a process it left running. */\nconst STDERR_CLOSE_GRACE_MS = 1000;\nconst MILLISECONDS_PER_SECOND = 1000;\nconst LOGIN_SHELL_TIMEOUT_MS = 10_000;\nconst DEFAULT_PACKAGE_MANAGER = 'npm';\nconst NO_SUCH_PROCESS = 'ESRCH';\n/** Checked nearest-first in each folder; the first lockfile found names the package manager. */\nconst LOCKFILES: readonly (readonly [string, string])[] = [\n ['pnpm-lock.yaml', 'pnpm'],\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n/** Variables a Po session or another harness exports; a package build must not see them. */\nconst HARNESS_PREFIXES = ['PO_', 'PI_', 'CLAUDE_', 'CODEX_'];\nconst HARNESS_VARIABLES = new Set(['CLAUDECODE', 'MCP_UI_VIEWER', 'npm_config_user_agent']);\nconst DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];\n\nexport interface LocalPackage {\n /** The selector as a root's configuration names it. */\n selector: string;\n directory: string;\n}\n\nexport type LocalBuildOutcome =\n | { status: 'built' | 'cached' }\n | { status: 'failed'; reason: string; stderr?: string[] };\n\nexport interface LocalBuildInput {\n globalRoot: string;\n environment: NodeJS.ProcessEnv;\n directories: readonly string[];\n /** Receives each command line as it starts. */\n onCommand: (command: string) => void;\n onNotice: (message: string) => void;\n /** Overrides `LOCAL_BUILD_TIMEOUT_MS`. */\n timeoutMs?: number;\n}\n\ninterface Manifest {\n name?: string;\n main?: unknown;\n module?: unknown;\n exports?: unknown;\n scripts?: Record<string, unknown>;\n [field: string]: unknown;\n}\n\nfunction sourceFiles(directory: string): string[] {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(directory, { withFileTypes: true });\n } catch {\n // A package without a source folder has only its manifest to stamp.\n return [];\n }\n return entries.flatMap((entry) => {\n const full = path.join(directory, entry.name);\n if (entry.isDirectory()) return entry.name === NODE_MODULES ? [] : sourceFiles(full);\n return entry.isFile() ? [full] : [];\n });\n}\n\n/**\n * The build stamp of a local package: an mtime and size signature over its `package.json`\n * and every file under `src/`.\n * ponytail: it misses edits to dependencies outside the package; a content hash is the upgrade.\n */\nexport function localBuildStamp(packageDirectory: string): string {\n const files = [\n path.join(packageDirectory, PACKAGE_MANIFEST),\n ...sourceFiles(path.join(packageDirectory, LOCAL_SOURCE_DIRECTORY)),\n ];\n const hash = crypto.createHash('sha256');\n for (const file of files.sort()) {\n const relative = path.relative(packageDirectory, file);\n try {\n const stat = fs.statSync(file);\n hash.update(`${relative}\\0${String(stat.size)}\\0${String(stat.mtimeMs)}\\n`);\n } catch {\n // Recorded as missing, so the stamp moves when the file appears.\n hash.update(`${relative}\\0missing\\n`);\n }\n }\n return hash.digest('hex');\n}\n\nexport function localBuildsPath(globalRoot: string): string {\n return path.join(globalRoot, LOCAL_BUILDS_FILE);\n}\n\nfunction readStamps(globalRoot: string): Record<string, string> {\n try {\n const parsed = JSON.parse(fs.readFileSync(localBuildsPath(globalRoot), 'utf8')) as unknown;\n return typeof parsed === 'object' && parsed !== null ? (parsed as Record<string, string>) : {};\n } catch {\n // Missing or unreadable: every package builds once.\n return {};\n }\n}\n\nfunction readManifest(directory: string): Manifest | undefined {\n try {\n return JSON.parse(fs.readFileSync(path.join(directory, PACKAGE_MANIFEST), 'utf8')) as Manifest;\n } catch {\n return undefined;\n }\n}\n\n/** The package manager the nearest lockfile names, walking up from the package. */\nexport function packageManagerFor(directory: string): string {\n let current = path.resolve(directory);\n for (;;) {\n for (const [lockfile, manager] of LOCKFILES) if (fs.existsSync(path.join(current, lockfile))) return manager;\n const parent = path.dirname(current);\n if (parent === current) return DEFAULT_PACKAGE_MANAGER;\n current = parent;\n }\n}\n\nfunction findOnPath(binary: string, searchPath: string | undefined): string | undefined {\n for (const directory of (searchPath ?? '').split(path.delimiter).filter(Boolean)) {\n const candidate = path.join(directory, binary);\n try {\n fs.accessSync(candidate, fs.constants.X_OK);\n if (fs.statSync(candidate).isFile()) return candidate;\n } catch {\n // Not in this folder.\n }\n }\n return undefined;\n}\n\n/**\n * The login shell's PATH. Desktop apps launched from Finder get a minimal PATH (inferred,\n * not checked here), so a package manager installed through a shell profile is missing.\n */\nfunction loginShellPath(environment: NodeJS.ProcessEnv): string | undefined {\n const shell = environment.SHELL ?? '/bin/zsh';\n const result = spawnSync(shell, ['-ilc', 'printf %s \"$PATH\"'], {\n encoding: 'utf8',\n timeout: LOGIN_SHELL_TIMEOUT_MS,\n });\n return result.status === 0 && result.stdout.trim() !== '' ? result.stdout.trim() : undefined;\n}\n\n/** Strip harness state, then restore only validated test isolation for nested Po commands. */\nexport function buildEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const testContext = getValidatedTestContext(environment);\n return {\n ...Object.fromEntries(\n Object.entries(environment).filter(\n ([name]) => !HARNESS_VARIABLES.has(name) && !HARNESS_PREFIXES.some((prefix) => name.startsWith(prefix)),\n ),\n ),\n ...testContext?.env,\n };\n}\n\nfunction entryPaths(value: unknown): string[] {\n if (typeof value === 'string') return [value];\n if (Array.isArray(value)) return value.flatMap(entryPaths);\n if (typeof value === 'object' && value !== null) return Object.values(value).flatMap(entryPaths);\n return [];\n}\n\n/** Whether every file `main`, `module` and `exports` name exists; false when they name none. */\nfunction builtEntriesPresent(directory: string, manifest: Manifest): boolean {\n const entries = [manifest.main, manifest.module, manifest.exports]\n .flatMap(entryPaths)\n .filter((entry) => !entry.includes('*'));\n return entries.length > 0 && entries.every((entry) => fs.existsSync(path.resolve(directory, entry)));\n}\n\n/** The directories ordered so each local package builds after the local packages it depends on. */\nfunction dependencyOrder(directories: readonly string[], manifests: Map<string, Manifest | undefined>): string[] {\n const byName = new Map<string, string>();\n for (const directory of directories) {\n const name = manifests.get(directory)?.name;\n if (name !== undefined) byName.set(name, directory);\n }\n const ordered: string[] = [];\n const visiting = new Set<string>();\n const visit = (directory: string): void => {\n if (ordered.includes(directory) || visiting.has(directory)) return;\n visiting.add(directory);\n const manifest = manifests.get(directory);\n for (const field of DEPENDENCY_FIELDS) {\n const dependencies = manifest?.[field];\n if (typeof dependencies !== 'object' || dependencies === null) continue;\n for (const name of Object.keys(dependencies)) {\n const dependency = byName.get(name);\n if (dependency !== undefined) visit(dependency);\n }\n }\n visiting.delete(directory);\n ordered.push(directory);\n };\n for (const directory of directories) visit(directory);\n return ordered;\n}\n\nfunction stderrTail(stderr: string): string[] {\n return stderr.trimEnd().split('\\n').filter(Boolean).slice(-STDERR_TAIL_LINES);\n}\n\ninterface BuildRun {\n status: number | null;\n signal: NodeJS.Signals | null;\n error?: Error;\n timedOut: boolean;\n /** It exited while a process it started still held stderr open; that process was stopped. */\n leftRunning: boolean;\n /** The last `STDERR_TAIL_BYTES` of stderr. */\n stderr: string;\n}\n\n/** Signals that end this process; a build in its own process group would not receive them. */\nconst FORWARDED_SIGNALS: readonly NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGHUP'];\nconst SEPARATE_PROCESS_GROUPS = process.platform !== 'win32';\n\n/**\n * Kills the build and everything it started. The build leads its own process group, so the\n * package manager's tsc or vite children die with it.\n * ponytail: Windows has no process groups here, so only the package manager is killed there;\n * `taskkill /T /F` is the upgrade if Windows builds must stop their children too.\n */\nfunction killBuild(child: ChildProcess): void {\n if (!SEPARATE_PROCESS_GROUPS || child.pid === undefined) {\n child.kill('SIGKILL');\n return;\n }\n try {\n process.kill(-child.pid, 'SIGKILL');\n } catch (error) {\n // ESRCH: every process of the group has exited already, which is the goal. Anything else\n // (EPERM) falls back to the package manager alone rather than crash inside a timer.\n if ((error as NodeJS.ErrnoException).code !== NO_SUCH_PROCESS) child.kill('SIGKILL');\n }\n}\n\n/**\n * Runs one build script without buffering its output: stdout is discarded and only the stderr\n * tail is kept. A build still running after `timeoutMs` is killed with every process it started\n * and reported as timed out. A build that exits while something it started still holds stderr\n * open has that process group killed when the grace ends, so nothing writes after it returns.\n */\nfunction runBuildScript(\n binary: string,\n directory: string,\n environment: NodeJS.ProcessEnv,\n timeoutMs: number,\n): Promise<BuildRun> {\n return new Promise((resolve) => {\n let tail = Buffer.alloc(0);\n let timedOut = false;\n let leftRunning = false;\n let settled = false;\n let grace: NodeJS.Timeout | undefined;\n // Its own process group, so a kill reaches its children. Still awaited: never unref'd.\n const child = spawn(binary, ['run', BUILD_SCRIPT], {\n cwd: directory,\n env: environment,\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: SEPARATE_PROCESS_GROUPS,\n });\n // A detached build no longer gets the terminal's Ctrl+C, so this process passes it on.\n const forward = (signal: NodeJS.Signals): void => {\n killBuild(child);\n if (process.listenerCount(signal) > 1) return;\n // Only this handler was listening: end as the signal would have without it.\n process.removeListener(signal, forward);\n process.kill(process.pid, signal);\n };\n if (SEPARATE_PROCESS_GROUPS) for (const signal of FORWARDED_SIGNALS) process.on(signal, forward);\n const finish = (result: Pick<BuildRun, 'status' | 'signal' | 'error'>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(grace);\n for (const signal of FORWARDED_SIGNALS) process.removeListener(signal, forward);\n child.stderr?.destroy();\n resolve({ ...result, timedOut, leftRunning, stderr: tail.toString('utf8') });\n };\n const timer = setTimeout(() => {\n timedOut = true;\n killBuild(child);\n }, timeoutMs);\n child.stderr?.on('data', (chunk: Buffer) => {\n tail = Buffer.concat([tail, chunk]);\n if (tail.length > STDERR_TAIL_BYTES) tail = tail.subarray(tail.length - STDERR_TAIL_BYTES);\n });\n child.on('error', (error) => finish({ status: null, signal: null, error }));\n child.on('close', (status, signal) => finish({ status, signal }));\n // A process the build left running can hold stderr open, so 'close' may never come.\n child.on('exit', (status, signal) => {\n grace = setTimeout(\n () => {\n if (!timedOut) leftRunning = true;\n killBuild(child);\n finish({ status, signal });\n },\n timedOut ? 0 : STDERR_CLOSE_GRACE_MS,\n );\n });\n });\n}\n\n/**\n * Builds every local package that changed since its last successful build, and returns each\n * directory's outcome. A failure never stops the others.\n */\nexport async function buildLocalPackages(input: LocalBuildInput): Promise<Map<string, LocalBuildOutcome>> {\n const { globalRoot, environment, onCommand, onNotice } = input;\n const timeoutMs = input.timeoutMs ?? LOCAL_BUILD_TIMEOUT_MS;\n const directories = [...new Set(input.directories)];\n const manifests = new Map(directories.map((directory) => [directory, readManifest(directory)]));\n const stamps = readStamps(globalRoot);\n const outcomes = new Map<string, LocalBuildOutcome>();\n const childEnvironment = buildEnvironment(environment);\n let searchPath = environment.PATH;\n let loginPathTried = false;\n const resolveBinary = (manager: string): string | undefined => {\n const found = findOnPath(manager, searchPath);\n if (found !== undefined || loginPathTried || process.platform !== 'darwin') return found;\n loginPathTried = true;\n const loginPath = loginShellPath(environment);\n if (loginPath === undefined) return undefined;\n searchPath = loginPath;\n childEnvironment.PATH = loginPath;\n return findOnPath(manager, searchPath);\n };\n\n for (const directory of dependencyOrder(directories, manifests)) {\n const manifest = manifests.get(directory);\n if (manifest === undefined) {\n outcomes.set(directory, { status: 'failed', reason: `'${directory}' has no readable package.json` });\n continue;\n }\n const stamp = localBuildStamp(directory);\n // ponytail: an unchanged stamp skips the build even when a dependency outside the\n // package changed; a content hash over the dependency closure is the upgrade.\n if (stamps[directory] === stamp) {\n outcomes.set(directory, { status: 'cached' });\n continue;\n }\n if (typeof manifest.scripts?.[BUILD_SCRIPT] !== 'string') {\n outcomes.set(\n directory,\n builtEntriesPresent(directory, manifest)\n ? { status: 'cached' }\n : { status: 'failed', reason: 'it has no build script and no built entries' },\n );\n continue;\n }\n const manager = packageManagerFor(directory);\n const binary = resolveBinary(manager);\n if (binary === undefined) {\n outcomes.set(directory, { status: 'failed', reason: `${manager} is not on PATH` });\n continue;\n }\n const command = `${binary} run ${BUILD_SCRIPT} (in ${directory})`;\n onCommand(command);\n onNotice(`building ${manifest.name ?? directory}`);\n const result = await runBuildScript(binary, directory, childEnvironment, timeoutMs);\n if (result.status === 0 && !result.timedOut && !result.leftRunning) {\n // The stamp after the build, as the sync pointer records it: a build that writes into\n // src/ or package.json must not look changed to the next sync.\n stamps[directory] = localBuildStamp(directory);\n writeFileAtomic(localBuildsPath(globalRoot), `${JSON.stringify(stamps, null, 2)}\\n`);\n outcomes.set(directory, { status: 'built' });\n continue;\n }\n const exit = result.timedOut\n ? `timed out after ${String(timeoutMs / MILLISECONDS_PER_SECOND)} s`\n : result.status === 0 && result.leftRunning\n ? 'it exited but left processes running, which were stopped'\n : (result.error?.message ?? `exit ${String(result.status ?? result.signal)}`);\n outcomes.set(directory, {\n status: 'failed',\n reason: `${manager} run ${BUILD_SCRIPT} failed (${exit})`,\n stderr: stderrTail(result.stderr),\n });\n }\n return outcomes;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  const require_index = require("../cli/commands/doctor/index.cjs");
2
2
  let _agimon_ai_po_config_harnessState = require("@agimon-ai/po-config/harnessState");
3
- let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
3
+ let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
4
4
  let _agimon_ai_po_core_help = require("@agimon-ai/po-core/help");
5
5
  let typebox = require("typebox");
6
6
  //#region src/extensions/setupDiagnostics.ts
@@ -12,11 +12,11 @@ const guidance = {
12
12
  "profiles.yaml": "po-author-profile"
13
13
  };
14
14
  function createSetupDiagnosticsTool(readScope, authorize) {
15
- return (0, _agimon_ai_po_core_serverFacet.defineTool)({
15
+ return (0, _agimon_ai_po_core_serverPlugin.defineTool)({
16
16
  name: DIAGNOSE_SETUP_NAME,
17
17
  description: "Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.",
18
18
  parameters: typebox.Type.Object({}, { additionalProperties: false }),
19
- when: _agimon_ai_po_core_help.DOOM_HELP_WHEN,
19
+ when: _agimon_ai_po_core_help.PO_HELP_WHEN,
20
20
  executionMode: "serial",
21
21
  async execute(_input, execution) {
22
22
  const signal = authorize(execution.signal);
@@ -1 +1 @@
1
- {"version":3,"file":"setupDiagnostics.cjs","names":["defineTool","Type","HELP_WHEN","projectHarnessEnvironment","collectDoctorReport"],"sources":["../../../src/extensions/setupDiagnostics.ts"],"sourcesContent":["import { projectHarnessEnvironment } from '@agimon-ai/po-config/harnessState';\nimport type { DoomHeadlessSelection } from '@agimon-ai/po-core/headless';\nimport { DOOM_HELP_WHEN as HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { defineTool } from '@agimon-ai/po-core/serverFacet';\nimport { Type } from 'typebox';\n\nimport { collectDoctorReport } from '../cli/commands/doctor';\n\nexport const DIAGNOSE_SETUP_NAME = 'diagnose_setup';\nexport interface SetupDiagnosticScope {\n repoRoot: string;\n cwd: string;\n environment: Readonly<Record<string, string | undefined>>;\n selection: Pick<DoomHeadlessSelection, 'majorMode' | 'domains' | 'profile'>;\n}\n\nconst guidance: Readonly<Record<string, string>> = {\n 'config.yaml': 'po-author-config',\n 'modes.yaml': 'po-author-major-mode',\n 'domains.yaml': 'po-author-domain',\n 'profiles.yaml': 'po-author-profile',\n};\n\nexport function createSetupDiagnosticsTool(\n readScope: () => SetupDiagnosticScope,\n authorize: (signal?: AbortSignal) => AbortSignal,\n) {\n return defineTool({\n name: DIAGNOSE_SETUP_NAME,\n description:\n \"Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.\",\n parameters: Type.Object({}, { additionalProperties: false }),\n when: HELP_WHEN,\n executionMode: 'serial',\n async execute(_input, execution) {\n const signal = authorize(execution.signal);\n const scope = readScope();\n const environment = projectHarnessEnvironment(\n {\n root: scope.repoRoot,\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n { ...scope.environment },\n );\n const report = collectDoctorReport(environment, scope.cwd);\n signal.throwIfAborted();\n authorize(execution.signal);\n const result = {\n scope: 'current-session',\n configurationRoot: report.repoRoot,\n appliedSelection: {\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n status: report.problems === 0 && report.skipped.length === 0 ? 'checks-passed' : 'issues-found',\n checks: report.sections.map((section) => ({\n area: section.label,\n status: section.problems.length ? 'failed' : 'passed',\n problemCount: section.problems.length,\n guidance: guidance[section.label] ?? 'po-use-help',\n })),\n skipped: report.skipped,\n limitations:\n 'These are saved configuration and installation checks, not a network authentication or agent health test. Error text and configuration values are omitted to protect credentials. Inspect a failed area with its package guidance before proposing a repair.',\n };\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n });\n}\n"],"mappings":";;;;;;AAQA,MAAa,sBAAsB;AAQnC,MAAM,WAA6C;CACjD,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,iBAAiB;AACnB;AAEA,SAAgB,2BACd,WACA,WACA;CACA,QAAA,GAAOA,+BAAAA,WAAAA,CAAW;EAChB,MAAM;EACN,aACE;EACF,YAAYC,QAAAA,KAAK,OAAO,CAAC,GAAG,EAAE,sBAAsB,MAAM,CAAC;EAC3D,MAAMC,wBAAAA;EACN,eAAe;EACf,MAAM,QAAQ,QAAQ,WAAW;GAC/B,MAAM,SAAS,UAAU,UAAU,MAAM;GACzC,MAAM,QAAQ,UAAU;GACxB,MAAM,eAAA,GAAcC,kCAAAA,0BAAAA,CAClB;IACE,MAAM,MAAM;IACZ,WAAW,MAAM,UAAU;IAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;IACpC,SAAS,MAAM,UAAU;GAC3B,GACA,EAAE,GAAG,MAAM,YAAY,CACzB;GACA,MAAM,SAASC,cAAAA,oBAAoB,aAAa,MAAM,GAAG;GACzD,OAAO,eAAe;GACtB,UAAU,UAAU,MAAM;GAC1B,MAAM,SAAS;IACb,OAAO;IACP,mBAAmB,OAAO;IAC1B,kBAAkB;KAChB,WAAW,MAAM,UAAU;KAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;KACpC,SAAS,MAAM,UAAU;IAC3B;IACA,QAAQ,OAAO,aAAa,KAAK,OAAO,QAAQ,WAAW,IAAI,kBAAkB;IACjF,QAAQ,OAAO,SAAS,KAAK,aAAa;KACxC,MAAM,QAAQ;KACd,QAAQ,QAAQ,SAAS,SAAS,WAAW;KAC7C,cAAc,QAAQ,SAAS;KAC/B,UAAU,SAAS,QAAQ,UAAU;IACvC,EAAE;IACF,SAAS,OAAO;IAChB,aACE;GACJ;GACA,OAAO;IAAE,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;IAAE,CAAC;IAAG,SAAS;GAAO;EAC/F;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"setupDiagnostics.cjs","names":["defineTool","Type","HELP_WHEN","projectHarnessEnvironment","collectDoctorReport"],"sources":["../../../src/extensions/setupDiagnostics.ts"],"sourcesContent":["import { projectHarnessEnvironment } from '@agimon-ai/po-config/harnessState';\nimport type { PoHeadlessSelection } from '@agimon-ai/po-core/headless';\nimport { PO_HELP_WHEN as HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { defineTool } from '@agimon-ai/po-core/serverPlugin';\nimport { Type } from 'typebox';\n\nimport { collectDoctorReport } from '../cli/commands/doctor';\n\nexport const DIAGNOSE_SETUP_NAME = 'diagnose_setup';\nexport interface SetupDiagnosticScope {\n repoRoot: string;\n cwd: string;\n environment: Readonly<Record<string, string | undefined>>;\n selection: Pick<PoHeadlessSelection, 'majorMode' | 'domains' | 'profile'>;\n}\n\nconst guidance: Readonly<Record<string, string>> = {\n 'config.yaml': 'po-author-config',\n 'modes.yaml': 'po-author-major-mode',\n 'domains.yaml': 'po-author-domain',\n 'profiles.yaml': 'po-author-profile',\n};\n\nexport function createSetupDiagnosticsTool(\n readScope: () => SetupDiagnosticScope,\n authorize: (signal?: AbortSignal) => AbortSignal,\n) {\n return defineTool({\n name: DIAGNOSE_SETUP_NAME,\n description:\n \"Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.\",\n parameters: Type.Object({}, { additionalProperties: false }),\n when: HELP_WHEN,\n executionMode: 'serial',\n async execute(_input, execution) {\n const signal = authorize(execution.signal);\n const scope = readScope();\n const environment = projectHarnessEnvironment(\n {\n root: scope.repoRoot,\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n { ...scope.environment },\n );\n const report = collectDoctorReport(environment, scope.cwd);\n signal.throwIfAborted();\n authorize(execution.signal);\n const result = {\n scope: 'current-session',\n configurationRoot: report.repoRoot,\n appliedSelection: {\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n status: report.problems === 0 && report.skipped.length === 0 ? 'checks-passed' : 'issues-found',\n checks: report.sections.map((section) => ({\n area: section.label,\n status: section.problems.length ? 'failed' : 'passed',\n problemCount: section.problems.length,\n guidance: guidance[section.label] ?? 'po-use-help',\n })),\n skipped: report.skipped,\n limitations:\n 'These are saved configuration and installation checks, not a network authentication or agent health test. Error text and configuration values are omitted to protect credentials. Inspect a failed area with its package guidance before proposing a repair.',\n };\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n });\n}\n"],"mappings":";;;;;;AAQA,MAAa,sBAAsB;AAQnC,MAAM,WAA6C;CACjD,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,iBAAiB;AACnB;AAEA,SAAgB,2BACd,WACA,WACA;CACA,QAAA,GAAOA,gCAAAA,WAAAA,CAAW;EAChB,MAAM;EACN,aACE;EACF,YAAYC,QAAAA,KAAK,OAAO,CAAC,GAAG,EAAE,sBAAsB,MAAM,CAAC;EAC3D,MAAMC,wBAAAA;EACN,eAAe;EACf,MAAM,QAAQ,QAAQ,WAAW;GAC/B,MAAM,SAAS,UAAU,UAAU,MAAM;GACzC,MAAM,QAAQ,UAAU;GACxB,MAAM,eAAA,GAAcC,kCAAAA,0BAAAA,CAClB;IACE,MAAM,MAAM;IACZ,WAAW,MAAM,UAAU;IAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;IACpC,SAAS,MAAM,UAAU;GAC3B,GACA,EAAE,GAAG,MAAM,YAAY,CACzB;GACA,MAAM,SAASC,cAAAA,oBAAoB,aAAa,MAAM,GAAG;GACzD,OAAO,eAAe;GACtB,UAAU,UAAU,MAAM;GAC1B,MAAM,SAAS;IACb,OAAO;IACP,mBAAmB,OAAO;IAC1B,kBAAkB;KAChB,WAAW,MAAM,UAAU;KAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;KACpC,SAAS,MAAM,UAAU;IAC3B;IACA,QAAQ,OAAO,aAAa,KAAK,OAAO,QAAQ,WAAW,IAAI,kBAAkB;IACjF,QAAQ,OAAO,SAAS,KAAK,aAAa;KACxC,MAAM,QAAQ;KACd,QAAQ,QAAQ,SAAS,SAAS,WAAW;KAC7C,cAAc,QAAQ,SAAS;KAC/B,UAAU,SAAS,QAAQ,UAAU;IACvC,EAAE;IACF,SAAS,OAAO;IAChB,aACE;GACJ;GACA,OAAO;IAAE,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;IAAE,CAAC;IAAG,SAAS;GAAO;EAC/F;CACF,CAAC;AACH"}
@@ -1,7 +1,7 @@
1
1
  import { collectDoctorReport } from "../cli/commands/doctor/index.mjs";
2
2
  import { projectHarnessEnvironment } from "@agimon-ai/po-config/harnessState";
3
- import { defineTool } from "@agimon-ai/po-core/serverFacet";
4
- import { DOOM_HELP_WHEN } from "@agimon-ai/po-core/help";
3
+ import { defineTool } from "@agimon-ai/po-core/serverPlugin";
4
+ import { PO_HELP_WHEN } from "@agimon-ai/po-core/help";
5
5
  import { Type } from "typebox";
6
6
  //#region src/extensions/setupDiagnostics.ts
7
7
  const DIAGNOSE_SETUP_NAME = "diagnose_setup";
@@ -16,7 +16,7 @@ function createSetupDiagnosticsTool(readScope, authorize) {
16
16
  name: DIAGNOSE_SETUP_NAME,
17
17
  description: "Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.",
18
18
  parameters: Type.Object({}, { additionalProperties: false }),
19
- when: DOOM_HELP_WHEN,
19
+ when: PO_HELP_WHEN,
20
20
  executionMode: "serial",
21
21
  async execute(_input, execution) {
22
22
  const signal = authorize(execution.signal);
@@ -1 +1 @@
1
- {"version":3,"file":"setupDiagnostics.mjs","names":["HELP_WHEN"],"sources":["../../../src/extensions/setupDiagnostics.ts"],"sourcesContent":["import { projectHarnessEnvironment } from '@agimon-ai/po-config/harnessState';\nimport type { DoomHeadlessSelection } from '@agimon-ai/po-core/headless';\nimport { DOOM_HELP_WHEN as HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { defineTool } from '@agimon-ai/po-core/serverFacet';\nimport { Type } from 'typebox';\n\nimport { collectDoctorReport } from '../cli/commands/doctor';\n\nexport const DIAGNOSE_SETUP_NAME = 'diagnose_setup';\nexport interface SetupDiagnosticScope {\n repoRoot: string;\n cwd: string;\n environment: Readonly<Record<string, string | undefined>>;\n selection: Pick<DoomHeadlessSelection, 'majorMode' | 'domains' | 'profile'>;\n}\n\nconst guidance: Readonly<Record<string, string>> = {\n 'config.yaml': 'po-author-config',\n 'modes.yaml': 'po-author-major-mode',\n 'domains.yaml': 'po-author-domain',\n 'profiles.yaml': 'po-author-profile',\n};\n\nexport function createSetupDiagnosticsTool(\n readScope: () => SetupDiagnosticScope,\n authorize: (signal?: AbortSignal) => AbortSignal,\n) {\n return defineTool({\n name: DIAGNOSE_SETUP_NAME,\n description:\n \"Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.\",\n parameters: Type.Object({}, { additionalProperties: false }),\n when: HELP_WHEN,\n executionMode: 'serial',\n async execute(_input, execution) {\n const signal = authorize(execution.signal);\n const scope = readScope();\n const environment = projectHarnessEnvironment(\n {\n root: scope.repoRoot,\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n { ...scope.environment },\n );\n const report = collectDoctorReport(environment, scope.cwd);\n signal.throwIfAborted();\n authorize(execution.signal);\n const result = {\n scope: 'current-session',\n configurationRoot: report.repoRoot,\n appliedSelection: {\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n status: report.problems === 0 && report.skipped.length === 0 ? 'checks-passed' : 'issues-found',\n checks: report.sections.map((section) => ({\n area: section.label,\n status: section.problems.length ? 'failed' : 'passed',\n problemCount: section.problems.length,\n guidance: guidance[section.label] ?? 'po-use-help',\n })),\n skipped: report.skipped,\n limitations:\n 'These are saved configuration and installation checks, not a network authentication or agent health test. Error text and configuration values are omitted to protect credentials. Inspect a failed area with its package guidance before proposing a repair.',\n };\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n });\n}\n"],"mappings":";;;;;;AAQA,MAAa,sBAAsB;AAQnC,MAAM,WAA6C;CACjD,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,iBAAiB;AACnB;AAEA,SAAgB,2BACd,WACA,WACA;CACA,OAAO,WAAW;EAChB,MAAM;EACN,aACE;EACF,YAAY,KAAK,OAAO,CAAC,GAAG,EAAE,sBAAsB,MAAM,CAAC;EAC3D,MAAMA;EACN,eAAe;EACf,MAAM,QAAQ,QAAQ,WAAW;GAC/B,MAAM,SAAS,UAAU,UAAU,MAAM;GACzC,MAAM,QAAQ,UAAU;GACxB,MAAM,cAAc,0BAClB;IACE,MAAM,MAAM;IACZ,WAAW,MAAM,UAAU;IAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;IACpC,SAAS,MAAM,UAAU;GAC3B,GACA,EAAE,GAAG,MAAM,YAAY,CACzB;GACA,MAAM,SAAS,oBAAoB,aAAa,MAAM,GAAG;GACzD,OAAO,eAAe;GACtB,UAAU,UAAU,MAAM;GAC1B,MAAM,SAAS;IACb,OAAO;IACP,mBAAmB,OAAO;IAC1B,kBAAkB;KAChB,WAAW,MAAM,UAAU;KAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;KACpC,SAAS,MAAM,UAAU;IAC3B;IACA,QAAQ,OAAO,aAAa,KAAK,OAAO,QAAQ,WAAW,IAAI,kBAAkB;IACjF,QAAQ,OAAO,SAAS,KAAK,aAAa;KACxC,MAAM,QAAQ;KACd,QAAQ,QAAQ,SAAS,SAAS,WAAW;KAC7C,cAAc,QAAQ,SAAS;KAC/B,UAAU,SAAS,QAAQ,UAAU;IACvC,EAAE;IACF,SAAS,OAAO;IAChB,aACE;GACJ;GACA,OAAO;IAAE,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;IAAE,CAAC;IAAG,SAAS;GAAO;EAC/F;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"setupDiagnostics.mjs","names":["HELP_WHEN"],"sources":["../../../src/extensions/setupDiagnostics.ts"],"sourcesContent":["import { projectHarnessEnvironment } from '@agimon-ai/po-config/harnessState';\nimport type { PoHeadlessSelection } from '@agimon-ai/po-core/headless';\nimport { PO_HELP_WHEN as HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { defineTool } from '@agimon-ai/po-core/serverPlugin';\nimport { Type } from 'typebox';\n\nimport { collectDoctorReport } from '../cli/commands/doctor';\n\nexport const DIAGNOSE_SETUP_NAME = 'diagnose_setup';\nexport interface SetupDiagnosticScope {\n repoRoot: string;\n cwd: string;\n environment: Readonly<Record<string, string | undefined>>;\n selection: Pick<PoHeadlessSelection, 'majorMode' | 'domains' | 'profile'>;\n}\n\nconst guidance: Readonly<Record<string, string>> = {\n 'config.yaml': 'po-author-config',\n 'modes.yaml': 'po-author-major-mode',\n 'domains.yaml': 'po-author-domain',\n 'profiles.yaml': 'po-author-profile',\n};\n\nexport function createSetupDiagnosticsTool(\n readScope: () => SetupDiagnosticScope,\n authorize: (signal?: AbortSignal) => AbortSignal,\n) {\n return defineTool({\n name: DIAGNOSE_SETUP_NAME,\n description:\n \"Check this session's saved configuration, installed packages, and the global web build without changing anything. Returns scoped check results and the relevant setup guidance, never configuration values or credentials.\",\n parameters: Type.Object({}, { additionalProperties: false }),\n when: HELP_WHEN,\n executionMode: 'serial',\n async execute(_input, execution) {\n const signal = authorize(execution.signal);\n const scope = readScope();\n const environment = projectHarnessEnvironment(\n {\n root: scope.repoRoot,\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n { ...scope.environment },\n );\n const report = collectDoctorReport(environment, scope.cwd);\n signal.throwIfAborted();\n authorize(execution.signal);\n const result = {\n scope: 'current-session',\n configurationRoot: report.repoRoot,\n appliedSelection: {\n majorMode: scope.selection.majorMode,\n domains: [...scope.selection.domains],\n profile: scope.selection.profile,\n },\n status: report.problems === 0 && report.skipped.length === 0 ? 'checks-passed' : 'issues-found',\n checks: report.sections.map((section) => ({\n area: section.label,\n status: section.problems.length ? 'failed' : 'passed',\n problemCount: section.problems.length,\n guidance: guidance[section.label] ?? 'po-use-help',\n })),\n skipped: report.skipped,\n limitations:\n 'These are saved configuration and installation checks, not a network authentication or agent health test. Error text and configuration values are omitted to protect credentials. Inspect a failed area with its package guidance before proposing a repair.',\n };\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n });\n}\n"],"mappings":";;;;;;AAQA,MAAa,sBAAsB;AAQnC,MAAM,WAA6C;CACjD,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,iBAAiB;AACnB;AAEA,SAAgB,2BACd,WACA,WACA;CACA,OAAO,WAAW;EAChB,MAAM;EACN,aACE;EACF,YAAY,KAAK,OAAO,CAAC,GAAG,EAAE,sBAAsB,MAAM,CAAC;EAC3D,MAAMA;EACN,eAAe;EACf,MAAM,QAAQ,QAAQ,WAAW;GAC/B,MAAM,SAAS,UAAU,UAAU,MAAM;GACzC,MAAM,QAAQ,UAAU;GACxB,MAAM,cAAc,0BAClB;IACE,MAAM,MAAM;IACZ,WAAW,MAAM,UAAU;IAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;IACpC,SAAS,MAAM,UAAU;GAC3B,GACA,EAAE,GAAG,MAAM,YAAY,CACzB;GACA,MAAM,SAAS,oBAAoB,aAAa,MAAM,GAAG;GACzD,OAAO,eAAe;GACtB,UAAU,UAAU,MAAM;GAC1B,MAAM,SAAS;IACb,OAAO;IACP,mBAAmB,OAAO;IAC1B,kBAAkB;KAChB,WAAW,MAAM,UAAU;KAC3B,SAAS,CAAC,GAAG,MAAM,UAAU,OAAO;KACpC,SAAS,MAAM,UAAU;IAC3B;IACA,QAAQ,OAAO,aAAa,KAAK,OAAO,QAAQ,WAAW,IAAI,kBAAkB;IACjF,QAAQ,OAAO,SAAS,KAAK,aAAa;KACxC,MAAM,QAAQ;KACd,QAAQ,QAAQ,SAAS,SAAS,WAAW;KAC7C,cAAc,QAAQ,SAAS;KAC/B,UAAU,SAAS,QAAQ,UAAU;IACvC,EAAE;IACF,SAAS,OAAO;IAChB,aACE;GACJ;GACA,OAAO;IAAE,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;IAAE,CAAC;IAAG,SAAS;GAAO;EAC/F;CACF,CAAC;AACH"}
package/dist/utils.mjs CHANGED
@@ -1,2 +1 @@
1
- import { findRepositoryRoot, isRepositoryRoot } from "./src/composition/repository/index.mjs";
2
- export { findRepositoryRoot, isRepositoryRoot };
1
+ export { findRepositoryRoot, isRepositoryRoot } from "./src/composition/repository/index.mjs";
@@ -9,7 +9,7 @@ po api-export --out ./api-schema --strict
9
9
  po api-export --out ./api-schema --major-mode copilot --strict
10
10
  ```
11
11
 
12
- The command composes the global root and the workspace live and reads each selected server facet's built `poServer.contracts.dist` straight from its installed package. Each contract module is imported in a bounded child process; the command never imports a server facet, installs packages, or starts servers. A package without a readable contract is recorded as a coverage gap. Run `po sync` first if the configuration names packages that are not installed yet.
12
+ The command composes the global root and the workspace live and reads each selected server package's built `poServer.contracts.dist` straight from its installed package. Each contract module is imported in a bounded child process; the command never imports a server plugin, installs packages, or starts servers. A package without a readable contract is recorded as a coverage gap. Run `po sync` first if the configuration names packages that are not installed yet.
13
13
 
14
14
  The export contains:
15
15
 
@@ -17,7 +17,7 @@ The export contains:
17
17
  - `asyncapi.json`: AsyncAPI 3.0 Pi envelopes, Chord calls, subscriptions and state deltas, session methods and reconstructed state, and selected extension methods and channel payloads. `x-po` identifies scope, service, member, direction through the operation action, and operation kind.
18
18
  - `manifest.json`: selected global, workspace and session modes, contract fingerprints (the generation is always `live`), composition fingerprints, package and protocol versions, explicit dynamic values, coverage gaps, and SHA-256 hashes of both documents.
19
19
 
20
- The global and workspace scopes use their own default major modes. `--major-mode` changes only the session composition. Local WebSockets carry framed CBOR; remote WebSockets carry sealed envelopes around those bytes. Channel operations describe decoded payloads, not JSON WebSocket frames. The selected package's `service` and `member` identify plugin calls carried through `po.plugin.v1.invoke`.
20
+ The global and workspace scopes use their own default major modes. `--major-mode` changes only the session composition. Local WebSockets carry Chord JSON text frames; remote WebSockets carry sealed envelopes around those frames. Channel operations describe decoded payloads. The selected package's `service` and `member` identify plugin calls carried through `po.hub.invoke`.
21
21
 
22
22
  Export with `--strict` in CI. An incomplete export is still written for review, but the command exits with status 1. Missing third-party declarations do not prevent normal sync. Dynamic tool, provider and author-capability values are listed explicitly; exporting a schema does not freeze runtime capabilities or prove a client compatible.
23
23
 
@@ -74,7 +74,7 @@ export default defineApiContract({
74
74
  });
75
75
  ```
76
76
 
77
- Source schemas use JSON Schema draft-07, including TypeBox output. The exporter namespaces local references and translates tuple keywords for OpenAPI 3.1. Use self-contained local references, without `$id` or remote references. An API-free facet should declare empty `http` and `sockets` arrays. Use `gaps` for known missing declarations; never use an unconstrained schema to hide missing coverage.
77
+ Source schemas use JSON Schema draft-07, including TypeBox output. The exporter namespaces local references and translates tuple keywords for OpenAPI 3.1. Use self-contained local references, without `$id` or remote references. An API-free server plugin should declare empty `http` and `sockets` arrays. Use `gaps` for known missing declarations; never use an unconstrained schema to hide missing coverage.
78
78
 
79
79
  The exporter is a separate `api-export` command, not a `sync` flag. For a local distribution build:
80
80
 
@@ -1,6 +1,6 @@
1
1
  # Session APIs
2
2
 
3
- Session APIs let a Po package add HTTP behavior beside the direct headless runtime it extends. A package facet is imported from the package's built `poServer.dist` entry, registered in `po-server`, and called in process. The public client route is `/api/workspaces/<workspace-id>/sessions/<session-id>/plugins/<base-path>/...`.
3
+ Session APIs let a Po package add HTTP behavior beside the direct headless runtime it extends. A package's server plugin is imported from the package's built `poServer.dist` entry, installed in `po-server`, and called in process. The public client route is `/api/workspaces/<workspace-id>/sessions/<session-id>/plugins/<base-path>/...`.
4
4
 
5
5
  This guide also covers the package's TypeScript exports for Node.js callers that want to compose the same in-process services.
6
6
 
@@ -26,7 +26,7 @@ package.json poServer declaration
26
26
  /api/workspaces/<workspace-id>/sessions/<id>/plugins/<base-path>/...
27
27
  ```
28
28
 
29
- The server resolves facet candidates from the same live composition that selects the session runtime. This ensures:
29
+ The server resolves server package candidates from the same live composition that selects the session runtime. This ensures:
30
30
 
31
31
  - the API implementation follows the same repository, mode, and package selection as the session runtime;
32
32
  - each built entry resolves inside its own package and is imported through a URL that changes with the package content; and
@@ -36,7 +36,7 @@ The server starts each handler once, routes requests by a fixed base path, and c
36
36
 
37
37
  ## Declare a session API
38
38
 
39
- A package declares one `poServer` facet in `package.json`:
39
+ A package declares its server plugin in one `poServer` block in `package.json`:
40
40
 
41
41
  ```json
42
42
  {
@@ -48,18 +48,18 @@ A package declares one `poServer` facet in `package.json`:
48
48
  }
49
49
  ```
50
50
 
51
- Publish a default-exported `DoomServerFacet` through that entry. In its `apply`, use `requireDoomServerHost(context).registerApi(api)` and return a disposer that calls the registration's `dispose()`. Declare the host service in `inject` and check scope before registering. The API implementation owns its base path.
51
+ Publish a default-exported `PoServerPlugin`, an object with a `name` and an `apply`, through that entry. In its `apply`, use `requirePoServerHost(context).registerApi(api)` and return a disposer that calls the registration's `dispose()`. Declare the host service in `inject` and check scope before registering. The API implementation owns its base path.
52
52
 
53
- Paths are package-relative and cannot escape the package. The server records the built module path and the modes and layers that selected the package, and uses that ownership for admission. See the [complete facet example](../../../../clients/po-web/docs/package-apis.md#declare-an-api).
53
+ Paths are package-relative and cannot escape the package. The server records the built module path and the modes and layers that selected the package, and uses that ownership for admission. See the [complete plugin example](../../../../clients/po-web/docs/package-apis.md#declare-an-api).
54
54
 
55
55
  ## Implement the handler
56
56
 
57
- Each API registered by a facet implements this lifecycle:
57
+ Each API registered by a server plugin implements this lifecycle:
58
58
 
59
59
  ```ts
60
- interface DoomApi {
60
+ interface PoApi {
61
61
  basePath: string;
62
- start(context: DoomApiContext): {
62
+ start(context: PoApiContext): {
63
63
  fetch(request: Request): Response | Promise<Response>;
64
64
  close(): void;
65
65
  };
@@ -68,7 +68,7 @@ interface DoomApi {
68
68
 
69
69
  `start()` creates session-owned resources once. `fetch()` handles requests relative to the package mount. `close()` must release timers, watchers, streams, and other resources created during startup.
70
70
 
71
- Keep the API adapter reusable and have the facet import it. The facet's disposer closes the registration.
71
+ Keep the API adapter reusable and have the server plugin import it. The plugin's disposer closes the registration.
72
72
 
73
73
  ## Selecting the API composition
74
74
 
@@ -76,7 +76,7 @@ The session root's configuration is the only composition source. The server read
76
76
 
77
77
  Rebuild the package after changing a server-side API. The next new session imports the new build; running sessions keep the module they loaded.
78
78
 
79
- A composition that selects no API is a valid no-API state. In that case package API requests return `404`; the server still provides the typed session protocol. A required eligible facet failure prevents readiness. An optional facet failure is reported and does not remove unrelated APIs.
79
+ A composition that selects no API is a valid no-API state. In that case package API requests return `404`; the server still provides the typed session protocol. A required eligible package failure prevents readiness. An optional package failure is reported and does not remove unrelated APIs.
80
80
 
81
81
  ## Routing and isolation
82
82
 
@@ -111,23 +111,24 @@ Package APIs are executable trusted code. They can access the session's authorit
111
111
 
112
112
  The core package publishes the in-process building blocks through `@agimon-ai/po/server`:
113
113
 
114
- | Export | Responsibility |
115
- | ----------------------------------- | ---------------------------------------------------------------- |
116
- | `createHeadlessSessionManager` | Own direct session hosts and dispose them |
117
- | `createHeadlessHub` | Aggregate sessions, channels, and package API dispatch |
118
- | `serveHeadlessServer` | Expose HTTP and authenticated `/api/ws` WebSocket routes |
119
- | `createAgentSessionRuntime` | Project a direct runtime into typed session state and operations |
120
- | `createAgentServerService` | Adapt one typed session service to the Pi protocol host |
121
- | `createRpcTranscript` | Reduce runtime events into the authoritative transcript |
122
- | `createHeadlessChildSessionService` | Provide explicitly requested child-session capabilities |
114
+ | Export | Responsibility |
115
+ | ----------------------------------- | ----------------------------------------------------------------- |
116
+ | `createHeadlessSessionManager` | Own direct session hosts and dispose them |
117
+ | `createHeadlessHub` | Aggregate sessions, channels, and package API dispatch |
118
+ | `serveHeadlessServer` | Expose HTTP and authenticated `/api/ws` WebSocket routes |
119
+ | `createAgentSessionRuntime` | Project a direct runtime into typed session state and operations |
120
+ | `serveAgentSessions` | Serve `po.session` on a Chord host from resolved session runtimes |
121
+ | `createHeadlessChildSessionService` | Provide explicitly requested child-session capabilities |
123
122
 
124
123
  A minimal composition is:
125
124
 
126
125
  ```ts
126
+ import { createNodePlatform } from '@agimon-ai/po-core/nodePlatform';
127
127
  import { createHeadlessHub, createHeadlessSessionManager, serveHeadlessServer } from '@agimon-ai/po/server';
128
128
 
129
+ const platform = createNodePlatform({ sessionsRoot: '/var/lib/po/sessions' });
129
130
  const manager = createHeadlessSessionManager();
130
- const hub = createHeadlessHub({ manager });
131
+ const hub = createHeadlessHub({ manager, platform });
131
132
  const server = await serveHeadlessServer({
132
133
  headlessHub: hub,
133
134
  port: 7533,
@@ -135,10 +136,10 @@ const server = await serveHeadlessServer({
135
136
  });
136
137
  ```
137
138
 
138
- The caller remains responsible for creating admitted direct session hosts, closing `server`, closing `hub`, and closing `manager` in that order. The executable performs that lifecycle for the command-line case.
139
+ The caller remains responsible for creating admitted direct session hosts with the same `platform`, closing `server`, closing `hub`, and closing `manager` in that order. The executable performs that lifecycle for the command-line case, keeping sessions under `<agent dir>/server/sessions`.
139
140
 
140
141
  ## Related guides
141
142
 
142
143
  - [IPC](ipc.md) explains `/api/ws`, typed operations, package dispatch, and replay.
143
- - [Lifecycle](lifecycle.md) explains when facets load and close.
144
+ - [Lifecycle](lifecycle.md) explains when server packages load and close.
144
145
  - [Security](security.md) describes trusted package code and context capabilities.
@@ -1,6 +1,6 @@
1
1
  # Getting started
2
2
 
3
- `po-server` is the process boundary for one client-neutral headless Po session. It embeds the Pi harness, typed session services, and package facets in one process, then publishes an authenticated HTTP and WebSocket listener.
3
+ `po-server` is the process boundary for one client-neutral headless Po session. It embeds the Pi harness, typed session services, and server plugins in one process, then publishes an authenticated HTTP and WebSocket listener.
4
4
 
5
5
  ## Choose the topology
6
6
 
@@ -57,10 +57,10 @@ A ready session owns:
57
57
  | Resource | Purpose |
58
58
  | ---------------------- | ----------------------------------------------------------------------- |
59
59
  | Loopback HTTP listener | Health, discovery, channel, and package API routes |
60
- | `/api/ws` WebSocket | Authenticated Pi 0.85 Chord protocol |
60
+ | `/api/ws` WebSocket | Authenticated Chord 1.2 link frames |
61
61
  | Direct harness runtime | In-process Pi execution and typed session operations |
62
62
  | Session journal | Upstream v4 JSONL history, normally below `~/.po/agent/server/sessions` |
63
- | Loaded server facets | Built `poServer` entries the composition selects |
63
+ | Loaded server plugins | Built `poServer` entries the composition selects |
64
64
 
65
65
  No separate API listener or filesystem endpoint is created. The session service hydrates its authoritative snapshot from the journal and publishes it through the protocol state.
66
66
 
@@ -74,11 +74,11 @@ No separate API listener or filesystem endpoint is created. The session service
74
74
  | `--web [port]` | 7533 | Listener port; the listener is started for every server |
75
75
  | `-- <harness arguments>` | none | Arguments passed to the embedded headless harness |
76
76
 
77
- There is no server-side command, runtime-directory, or API-directory fallback. Composition comes from the live configuration of each scope. A required facet that cannot be imported fails startup instead of selecting a different module set.
77
+ There is no server-side command, runtime-directory, or API-directory fallback. Composition comes from the live configuration of each scope. A required server package that cannot be imported fails startup instead of selecting a different module set.
78
78
 
79
79
  ## Select the runtime composition
80
80
 
81
- The server follows the repository that owns the session working directory; a member checkout such as a worktree resolves its composition from the workspace root. It composes that configuration, collects the selected packages' `poServer` entries, filters them for the active major mode and layers, and installs the resulting facets into the direct headless host.
81
+ The server follows the repository that owns the session working directory; a member checkout such as a worktree resolves its composition from the workspace root. It composes that configuration, collects the selected packages' `poServer` entries, filters them for the active major mode and layers, and installs the resulting server plugins into the direct headless host.
82
82
 
83
83
  Each entry is imported through a URL that changes with the package content. After you rebuild or upgrade a package, the next new session imports the new build without a server restart; running sessions keep the module they loaded. Run `po sync` after changing configuration that names new packages, so they are installed.
84
84
 
@@ -96,9 +96,9 @@ Configure the cockpit with the server URL and token through its documented pairi
96
96
 
97
97
  ## Stop and recover
98
98
 
99
- `SIGINT` and `SIGTERM` dispose the headless host, close package facets, stop the direct runtime, close the listener, and release history ownership. A normal stop leaves the v4 session journal available for a later server.
99
+ `SIGINT` and `SIGTERM` dispose the headless host, close server plugins, stop the direct runtime, close the listener, and release history ownership. A normal stop leaves the v4 session journal available for a later server.
100
100
 
101
- If startup fails while composing a scope or loading a required facet, no ready listener is published. Treat a failed composition, failed required facet, or history ownership conflict as a readiness failure, not as permission to use another module set.
101
+ If startup fails while composing a scope or loading a required server package, no ready listener is published. Treat a failed composition, failed required server package, or history ownership conflict as a readiness failure, not as permission to use another module set.
102
102
 
103
103
  ## Development
104
104
 
@@ -35,9 +35,9 @@ The token is read from the file, not the command line. Keep the file private. A
35
35
 
36
36
  ## How it works
37
37
 
38
- Startup composes the global scope from configuration and imports the eligible server facets from their packages' built entries. It then creates the direct harness, session service, and package API handlers in process. The listener provides:
38
+ Startup composes the global scope from configuration and imports the eligible server plugins from their packages' built entries. It then creates the direct harness, session service, and package API handlers in process. The listener provides:
39
39
 
40
- - `/api/ws`, an authenticated WebSocket carrying the Pi 0.85 Chord protocol;
40
+ - `/api/ws`, an authenticated WebSocket carrying Chord 1.2 link frames;
41
41
  - `/api/health`, an unauthenticated readiness check;
42
42
  - `/api/workspaces/<workspace-id>/sessions` and related routes for discovery and channel access; and
43
43
  - session package APIs below `/api/workspaces/<workspace-id>/sessions/<session-id>/plugins/<base-path>/...`.
@@ -46,7 +46,7 @@ The Pi protocol exposes typed management, hub, and session services. Session cal
46
46
 
47
47
  ## Security
48
48
 
49
- The server binds to loopback by default and requires the token for every route except `/api/health`. A token file keeps the capability out of process listings. The server is not a sandbox: the harness, extensions, and server facets run with the account's authority.
49
+ The server binds to loopback by default and requires the token for every route except `/api/health`. A token file keeps the capability out of process listings. The server is not a sandbox: the harness, extensions, and server plugins run with the account's authority.
50
50
 
51
51
  Po Web owns browser authentication, remote tunnels, device cookies, and passkeys. When it proxies a session, browser code does not need the server token. Do not publish the server listener without an authenticated boundary.
52
52
 
@@ -59,7 +59,7 @@ Read [Security and trust boundaries](security.md) before sharing a listener or t
59
59
  | [Getting started](getting-started.md) | Installation, options, live composition, and web integration |
60
60
  | [Lifecycle](lifecycle.md) | In-process startup, readiness, shutdown, and history ownership |
61
61
  | [IPC](ipc.md) | The `/api/ws` protocol, typed operations, HTTP routes, and replay |
62
- | [Session APIs](api.md) | `poServer` facets, package handlers, and TypeScript exports |
62
+ | [Session APIs](api.md) | `poServer` plugins, package handlers, and TypeScript exports |
63
63
  | [Security](security.md) | Tokens, listener exposure, trusted code, and data boundaries |
64
64
 
65
65
  ## License
@@ -11,7 +11,7 @@ The canonical server has one client-neutral listener. It exposes HTTP routes and
11
11
  | |
12
12
  v v
13
13
  HTTP control surface /api/ws WebSocket
14
- health, sessions, APIs Pi 0.85 Chord services
14
+ health, sessions, APIs Chord 1.3 objects
15
15
  | |
16
16
  +------------------+------------------+
17
17
  v
@@ -29,9 +29,6 @@ The server exposes these client-neutral routes:
29
29
  | `GET /api/health` | Unauthenticated readiness and session count |
30
30
  | `GET /api/workspaces/<workspace-id>/sessions` | Session metadata for the headless hub |
31
31
  | `GET /api/workspaces/<workspace-id>/sessions/<id>` | One session's metadata |
32
- | `GET /api/events` | Server-sent session and channel events |
33
- | `GET /api/workspaces/<workspace-id>/sessions/<id>/channels` | Current channel projections |
34
- | `POST /api/workspaces/<workspace-id>/sessions/<id>/channel/<type>` | Deliver a channel operation |
35
32
  | `/api/workspaces/<workspace-id>/sessions/<id>/plugins/<base-path>/...` | Dispatch a session package API in process |
36
33
 
37
34
  All routes other than health require the configured token. HTTP clients should send `Authorization: Bearer <token>` or `x-po-token`. The WebSocket may use the same capability in its authorization header or query string; avoid query strings when a header is available because URLs can be logged.
@@ -40,13 +37,12 @@ The old raw command route is not part of this surface. Session control uses the
40
37
 
41
38
  ## `/api/ws` protocol
42
39
 
43
- `/api/ws` carries the Pi 0.85 byte protocol over an already-authenticated WebSocket. The server hosts the stable cockpit server identity and publishes these typed services:
40
+ `/api/ws` carries Chord 1.3 (link protocol v4) frames, one JSON text message each, over an already-authenticated WebSocket. Each socket is a client link stamped with its own connection principal. The server host is named `server` and serves these remote contracts:
44
41
 
45
- - `po.hub.v1` lists sessions, subscribes to channel events, and sends typed channel operations;
46
- - `po.session-management.v1` attaches and detaches a session; and
47
- - `po.session.v1` exposes one session's state and operations.
42
+ - `po.hub` (input `{}`) lists sessions, subscribes to channel events, sends typed channel operations, reads Home, and invokes plugin methods; and
43
+ - `po.session` (input `{ sessionId }`) exposes one session's `state` and operations, plus `alive`, which turns false when the runtime behind it exits.
48
44
 
49
- A client first attaches through the management service, then binds the session service for that session. The service boundary is typed even though the transport carries protocol bytes.
45
+ A client holds `po.session` for the session it shows. Every connection shares one projected runtime per session; the server checks the connection's scope and Desktop ownership before resolving the object and on every call. Clients use `attachHub` and `attachSession` from `@agimon-ai/po-core/sessionProtocol`.
50
46
 
51
47
  ## Typed session operations
52
48
 
@@ -72,7 +68,7 @@ The hub's session and channel event history is also bounded to 1,024 events. The
72
68
 
73
69
  ## Session package APIs
74
70
 
75
- A package API is registered by a server facet and called through the in-process `Request` adapter. The listener strips `/api/workspaces/<workspace-id>/sessions/<id>/plugins/<base-path>` before invoking the handler, so a request to `/api/workspaces/<workspace-id>/sessions/one/plugins/runner/runs/r1/log` reaches the `runner` handler as `/runs/r1/log`.
71
+ A package API is registered by a server plugin and called through the in-process `Request` adapter. The listener strips `/api/workspaces/<workspace-id>/sessions/<id>/plugins/<base-path>` before invoking the handler, so a request to `/api/workspaces/<workspace-id>/sessions/one/plugins/runner/runs/r1/log` reaches the `runner` handler as `/runs/r1/log`.
76
72
 
77
73
  Package handlers run with the session's trusted host context. They still validate request bodies, bound reads and streams, constrain paths, and avoid returning secrets merely because the caller passed the listener token.
78
74
 
@@ -94,4 +90,4 @@ Workspace settings are at `/api/workspaces/<workspace-id>/settings`. Create or a
94
90
 
95
91
  The global socket retains the aggregate hub protocol used by Po Web. Workspace sockets expose only sessions in that workspace; session sockets expose only the named session. Both restrict session attachments, subscriptions, thread reads, and package calls to their addressed scope. All transports use the same Pi/Chord framing. Old flat session routes, singular plugin mounts, and `/api/pi` are removed without aliases.
96
92
 
97
- Startup loads global facets from the global root's live composition, workspace facets when that workspace is admitted, and session facets from the owning workspace's composition with the session's selection. REST requests dispatch only to that mount; there is no fallback to another scope.
93
+ Startup loads global packages from the global root's live composition, workspace packages when that workspace is admitted, and session packages from the owning workspace's composition with the session's selection. REST requests dispatch only to that mount; there is no fallback to another scope.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Package hooks follow the [plugin lifecycle contract](../../../po-core/docs/plugins.md): register, `onStart`, `onStop`, unregister, and `onDispose`. Server readiness waits for required plugin startup; browser reconnects do not restart those plugins.
4
4
 
5
- `po-server` owns one session boundary from startup through shutdown. The Pi harness, session services, package facets, and listener live in the same process. A client can disconnect without stopping the runtime, and a later client can recover the current replicated state.
5
+ `po-server` owns one session boundary from startup through shutdown. The Pi harness, session services, server plugins, and listener live in the same process. A client can disconnect without stopping the runtime, and a later client can recover the current replicated state.
6
6
 
7
7
  ## The ownership model
8
8
 
@@ -12,7 +12,7 @@ po-server process
12
12
  +-- session manager and headless hub
13
13
  +-- DirectHarnessRuntime
14
14
  +-- typed management and session services
15
- +-- package facet host and in-process API handlers
15
+ +-- server plugin host and in-process API handlers
16
16
  +-- HTTP and WebSocket listener, including /api/ws
17
17
  +-- v4 JSONL session journal
18
18
  ```
@@ -21,7 +21,7 @@ The server, not a client, owns runtime disposal and history ownership. This give
21
21
 
22
22
  ## Startup is readiness-ordered
23
23
 
24
- The server publishes the listener only after the runtime and required facets are ready:
24
+ The server publishes the listener only after the runtime and required server packages are ready:
25
25
 
26
26
  ```text
27
27
  parse options and identity
@@ -30,13 +30,13 @@ parse options and identity
30
30
  read token and compose the global scope from configuration
31
31
  |
32
32
  v
33
- import eligible facets from built package entries
33
+ import eligible server plugins from built package entries
34
34
  |
35
35
  v
36
36
  create DirectHarnessRuntime and prepare the headless host
37
37
  |
38
38
  v
39
- activate facets and initialize typed session services
39
+ activate server packages and initialize typed session services
40
40
  |
41
41
  v
42
42
  bind HTTP and /api/ws
@@ -52,7 +52,7 @@ The executable performs these steps:
52
52
  3. Resolve session identity and harness options from the caller's repository.
53
53
  4. Compose the scope from configuration, collect the selected packages' `poServer` entries, check that each built entry stays inside its package, and filter by ownership and scope before importing modules through their content-addressed URLs.
54
54
  5. Create the direct runtime with explicit history ownership, model configuration, session identity, and working directory.
55
- 6. Prepare and activate the selected server facets. Required failures stop readiness; optional failures are reported and isolated.
55
+ 6. Prepare and activate the selected server packages. Required failures stop readiness; optional failures are reported and isolated.
56
56
  7. Mount in-process package API handlers and initialize the typed session projection.
57
57
  8. Bind the loopback HTTP listener and authenticated `/api/ws` WebSocket endpoint.
58
58
 
@@ -62,14 +62,14 @@ A startup error is written to stderr with a `[po-server]` prefix and exits non-z
62
62
 
63
63
  Once ready, the server holds a stable session boundary:
64
64
 
65
- | Owned resource | Lifetime |
66
- | ---------------------------------- | -------------------------------- |
67
- | Session ID and name | Whole server process |
68
- | Direct harness runtime | Whole server process |
69
- | Typed session state and operations | Whole server process |
70
- | Package facet registrations | Until shutdown or facet disposal |
71
- | HTTP and `/api/ws` listener | Whole server process |
72
- | Session journal ownership | Whole server process |
65
+ | Owned resource | Lifetime |
66
+ | ---------------------------------- | --------------------------------- |
67
+ | Session ID and name | Whole server process |
68
+ | Direct harness runtime | Whole server process |
69
+ | Typed session state and operations | Whole server process |
70
+ | Server plugin registrations | Until shutdown or plugin disposal |
71
+ | HTTP and `/api/ws` listener | Whole server process |
72
+ | Session journal ownership | Whole server process |
73
73
 
74
74
  The session service projects runtime activity into an authoritative snapshot, transient progress, concurrent in-flight items, and bounded presentation events. A client does not need to remain connected for the runtime to update the journal.
75
75
 
@@ -83,16 +83,16 @@ Live presentation events are bounded to 1,024 events or 8 MiB. The state reports
83
83
 
84
84
  This is recovery state, not an audit log. Clients that need authoritative transcript or configuration data should use the typed snapshot and query operations. A client must not infer missing history from the bounded presentation window.
85
85
 
86
- ## Package facet changes
86
+ ## Server package changes
87
87
 
88
- Each facet is imported through a URL that changes with its package content. Rebuilding or upgrading a package does not mutate a running session: the next new session imports the new build. Global and workspace scopes are checked again when a session opens or a workspace is admitted, and remount when an entry changed; a failed remount restores the previous facets. After a set number of superseded package versions, the server restarts at the next idle moment so old modules do not accumulate. During shutdown, facet disposers run before the host and runtime release their resources.
88
+ Each server plugin is imported through a URL that changes with its package content. Rebuilding or upgrading a package does not mutate a running session: the next new session imports the new build. Global and workspace scopes are checked again after a watched package change, a finished sync, or a package install or removal, and reinstall only what changed: an unchanged package is skipped, a changed one is disposed and its new build applied, and a new build that fails restores the previous one. A package that is no longer selected stays installed. After a set number of superseded package versions, the server restarts at the next idle moment so old modules do not accumulate. During shutdown, plugin disposers run before the host and runtime release their resources.
89
89
 
90
90
  ## Shutdown and failures
91
91
 
92
92
  `SIGINT`, `SIGTERM`, runtime exit, and explicit disposal all disable new operations and release resources in ownership order:
93
93
 
94
94
  1. stop accepting new package and session operations;
95
- 2. close active facet registrations and package handlers;
95
+ 2. close active plugin registrations and package handlers;
96
96
  3. stop the headless host and pending extension interactions;
97
97
  4. close the typed service projection and direct runtime;
98
98
  5. release history ownership and close the JSONL repository;