@agimon-ai/doompi-core 0.0.1-alpha.92 → 0.0.1-alpha.94

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 (151) hide show
  1. package/dist/apiContracts.d.mts.map +1 -1
  2. package/dist/contextDetail.cjs +1 -0
  3. package/dist/contextDetail.cjs.map +1 -1
  4. package/dist/contextDetail.mjs +1 -0
  5. package/dist/contextDetail.mjs.map +1 -1
  6. package/dist/contextProjection.cjs.map +1 -1
  7. package/dist/contextProjection.d.mts +2 -0
  8. package/dist/contextProjection.d.mts.map +1 -1
  9. package/dist/contextProjection.mjs.map +1 -1
  10. package/dist/headless.cjs +1 -0
  11. package/dist/headless.d.mts +2 -2
  12. package/dist/headless.mjs +2 -2
  13. package/dist/headlessHub.cjs +37 -3
  14. package/dist/headlessHub.cjs.map +1 -1
  15. package/dist/headlessHub.d.mts.map +1 -1
  16. package/dist/headlessHub.mjs +37 -3
  17. package/dist/headlessHub.mjs.map +1 -1
  18. package/dist/headlessServer.cjs +25 -1
  19. package/dist/headlessServer.cjs.map +1 -1
  20. package/dist/headlessServer.d.mts.map +1 -1
  21. package/dist/headlessServer.mjs +25 -1
  22. package/dist/headlessServer.mjs.map +1 -1
  23. package/dist/headlessSessionHost.d.mts +3 -0
  24. package/dist/headlessSessionHost.d.mts.map +1 -1
  25. package/dist/history.cjs +3 -0
  26. package/dist/history.d.mts +2 -2
  27. package/dist/history.mjs +2 -2
  28. package/dist/hubChannel.d.mts +2 -2
  29. package/dist/main.cjs +1 -0
  30. package/dist/main.d.mts +2 -2
  31. package/dist/main.mjs +2 -2
  32. package/dist/packageApiServer.cjs +1 -0
  33. package/dist/packageApiServer.cjs.map +1 -1
  34. package/dist/packageApiServer.d.mts +1 -0
  35. package/dist/packageApiServer.d.mts.map +1 -1
  36. package/dist/packageApiServer.mjs +1 -0
  37. package/dist/packageApiServer.mjs.map +1 -1
  38. package/dist/remoteRuntime.cjs +54 -15
  39. package/dist/remoteRuntime.cjs.map +1 -1
  40. package/dist/remoteRuntime.d.mts +4 -2
  41. package/dist/remoteRuntime.d.mts.map +1 -1
  42. package/dist/remoteRuntime.mjs +41 -2
  43. package/dist/remoteRuntime.mjs.map +1 -1
  44. package/dist/src/constants/remote.cjs +9 -0
  45. package/dist/src/constants/remote.cjs.map +1 -1
  46. package/dist/src/constants/remote.mjs +8 -1
  47. package/dist/src/constants/remote.mjs.map +1 -1
  48. package/dist/src/schemas/headless.cjs +7 -0
  49. package/dist/src/schemas/headless.cjs.map +1 -1
  50. package/dist/src/schemas/headless.d.mts +12 -2
  51. package/dist/src/schemas/headless.d.mts.map +1 -1
  52. package/dist/src/schemas/headless.mjs +7 -1
  53. package/dist/src/schemas/headless.mjs.map +1 -1
  54. package/dist/src/schemas/hubChannel.d.mts +22 -0
  55. package/dist/src/schemas/hubChannel.d.mts.map +1 -1
  56. package/dist/src/schemas/packageApi.cjs.map +1 -1
  57. package/dist/src/schemas/packageApi.d.mts +8 -3
  58. package/dist/src/schemas/packageApi.d.mts.map +1 -1
  59. package/dist/src/schemas/packageApi.mjs.map +1 -1
  60. package/dist/src/server/devProxyForward.cjs +141 -0
  61. package/dist/src/server/devProxyForward.cjs.map +1 -0
  62. package/dist/src/server/devProxyForward.mjs +139 -0
  63. package/dist/src/server/devProxyForward.mjs.map +1 -0
  64. package/dist/src/server/devProxyRoutes.cjs +97 -0
  65. package/dist/src/server/devProxyRoutes.cjs.map +1 -0
  66. package/dist/src/server/devProxyRoutes.mjs +97 -0
  67. package/dist/src/server/devProxyRoutes.mjs.map +1 -0
  68. package/dist/src/server/devProxySocket.cjs +87 -0
  69. package/dist/src/server/devProxySocket.cjs.map +1 -0
  70. package/dist/src/server/devProxySocket.mjs +87 -0
  71. package/dist/src/server/devProxySocket.mjs.map +1 -0
  72. package/dist/src/server/directHarnessRuntime.cjs +39 -15
  73. package/dist/src/server/directHarnessRuntime.cjs.map +1 -1
  74. package/dist/src/server/directHarnessRuntime.mjs +39 -16
  75. package/dist/src/server/directHarnessRuntime.mjs.map +1 -1
  76. package/dist/src/server/sessionMcpHandler.cjs +36 -41
  77. package/dist/src/server/sessionMcpHandler.cjs.map +1 -1
  78. package/dist/src/server/sessionMcpHandler.d.mts +1 -1
  79. package/dist/src/server/sessionMcpHandler.d.mts.map +1 -1
  80. package/dist/src/server/sessionMcpHandler.mjs +35 -40
  81. package/dist/src/server/sessionMcpHandler.mjs.map +1 -1
  82. package/dist/src/server/sessionMcpRoutes.cjs +21 -1
  83. package/dist/src/server/sessionMcpRoutes.cjs.map +1 -1
  84. package/dist/src/server/sessionMcpRoutes.mjs +21 -1
  85. package/dist/src/server/sessionMcpRoutes.mjs.map +1 -1
  86. package/dist/src/services/devProxyPolicy/index.cjs +168 -0
  87. package/dist/src/services/devProxyPolicy/index.cjs.map +1 -0
  88. package/dist/src/services/devProxyPolicy/index.mjs +165 -0
  89. package/dist/src/services/devProxyPolicy/index.mjs.map +1 -0
  90. package/dist/src/services/devProxyStore/index.cjs +107 -0
  91. package/dist/src/services/devProxyStore/index.cjs.map +1 -0
  92. package/dist/src/services/devProxyStore/index.mjs +104 -0
  93. package/dist/src/services/devProxyStore/index.mjs.map +1 -0
  94. package/dist/src/services/headlessClient/index.cjs +9 -1
  95. package/dist/src/services/headlessClient/index.cjs.map +1 -1
  96. package/dist/src/services/headlessClient/index.mjs +9 -1
  97. package/dist/src/services/headlessClient/index.mjs.map +1 -1
  98. package/dist/src/services/loopbackAddress/index.cjs +58 -0
  99. package/dist/src/services/loopbackAddress/index.cjs.map +1 -0
  100. package/dist/src/services/loopbackAddress/index.mjs +56 -0
  101. package/dist/src/services/loopbackAddress/index.mjs.map +1 -0
  102. package/dist/src/services/piExtensionHost/index.cjs +1 -2
  103. package/dist/src/services/piExtensionHost/index.cjs.map +1 -1
  104. package/dist/src/services/piExtensionHost/index.mjs +1 -2
  105. package/dist/src/services/piExtensionHost/index.mjs.map +1 -1
  106. package/dist/src/services/sessionMcpConversations/index.cjs +17 -1
  107. package/dist/src/services/sessionMcpConversations/index.cjs.map +1 -1
  108. package/dist/src/services/sessionMcpConversations/index.mjs +17 -1
  109. package/dist/src/services/sessionMcpConversations/index.mjs.map +1 -1
  110. package/dist/src/services/workspaceRegistry/index.cjs +60 -1
  111. package/dist/src/services/workspaceRegistry/index.cjs.map +1 -1
  112. package/dist/src/services/workspaceRegistry/index.d.mts +27 -0
  113. package/dist/src/services/workspaceRegistry/index.d.mts.map +1 -1
  114. package/dist/src/services/workspaceRegistry/index.mjs +57 -2
  115. package/dist/src/services/workspaceRegistry/index.mjs.map +1 -1
  116. package/dist/src/systems/main/adapters/headlessHost.cjs +29 -1
  117. package/dist/src/systems/main/adapters/headlessHost.cjs.map +1 -1
  118. package/dist/src/systems/main/adapters/headlessHost.d.mts +6 -0
  119. package/dist/src/systems/main/adapters/headlessHost.d.mts.map +1 -1
  120. package/dist/src/systems/main/adapters/headlessHost.mjs +29 -2
  121. package/dist/src/systems/main/adapters/headlessHost.mjs.map +1 -1
  122. package/dist/src/systems/main/adapters/headlessSessionHost.cjs +128 -88
  123. package/dist/src/systems/main/adapters/headlessSessionHost.cjs.map +1 -1
  124. package/dist/src/systems/main/adapters/headlessSessionHost.d.mts.map +1 -1
  125. package/dist/src/systems/main/adapters/headlessSessionHost.mjs +129 -89
  126. package/dist/src/systems/main/adapters/headlessSessionHost.mjs.map +1 -1
  127. package/dist/src/types/server/directHarnessRuntime.d.mts +5 -0
  128. package/dist/src/types/server/directHarnessRuntime.d.mts.map +1 -1
  129. package/dist/src/web/services/sessionRegistry/index.cjs +0 -37
  130. package/dist/src/web/services/sessionRegistry/index.cjs.map +1 -1
  131. package/dist/src/web/services/sessionRegistry/index.d.mts +1 -14
  132. package/dist/src/web/services/sessionRegistry/index.d.mts.map +1 -1
  133. package/dist/src/web/services/sessionRegistry/index.mjs +1 -35
  134. package/dist/src/web/services/sessionRegistry/index.mjs.map +1 -1
  135. package/dist/src/web/types/mcpWidget.d.mts +1 -1
  136. package/dist/src/web/types/sessionRegistry.d.mts +0 -16
  137. package/dist/src/web/types/sessionRegistry.d.mts.map +1 -1
  138. package/dist/src/web/types/webPlugin.d.mts +13 -0
  139. package/dist/src/web/types/webPlugin.d.mts.map +1 -1
  140. package/dist/syncLocation.cjs +2 -0
  141. package/dist/syncLocation.cjs.map +1 -1
  142. package/dist/syncLocation.d.mts +2 -0
  143. package/dist/syncLocation.d.mts.map +1 -1
  144. package/dist/syncLocation.mjs +2 -1
  145. package/dist/syncLocation.mjs.map +1 -1
  146. package/dist/typesContextApi.d.mts +2 -0
  147. package/dist/typesContextApi.d.mts.map +1 -1
  148. package/dist/web.cjs +0 -3
  149. package/dist/web.d.mts +4 -4
  150. package/dist/web.mjs +2 -2
  151. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/packageApi.ts","../src/schemas/serverBundle.ts","../src/schemas/apiContracts.ts","../src/services/apiContracts/index.ts","../src/schemas/builtinApiContracts.ts","../src/schemas/httpApiContracts.ts","../src/schemas/sessionProtocol.ts","../src/schemas/sessionApiContracts.ts","../src/schemas/transportApiContracts.ts"],"mappings":"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"}
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/packageApi.ts","../src/schemas/serverBundle.ts","../src/schemas/apiContracts.ts","../src/services/apiContracts/index.ts","../src/schemas/builtinApiContracts.ts","../src/schemas/httpApiContracts.ts","../src/schemas/sessionProtocol.ts","../src/schemas/sessionApiContracts.ts","../src/schemas/transportApiContracts.ts"],"mappings":"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"}
@@ -47,6 +47,7 @@ function buildContextDetail(input) {
47
47
  tokens: skill.promptTokens ?? 0,
48
48
  description: skill.description,
49
49
  ...skill.filePath === void 0 ? {} : { filePath: skill.filePath },
50
+ ...skill.body === void 0 ? {} : { body: skill.body },
50
51
  modelInvocable: skill.modelInvocable
51
52
  });
52
53
  if (input.systemPrompt !== void 0) items.push({
@@ -1 +1 @@
1
- {"version":3,"file":"contextDetail.cjs","names":["tokensForTool"],"sources":["../src/services/contextDetail/index.ts"],"sourcesContent":["import type { ContextItemDetail, ContextPromptStage, ContextToolDetail } from '../../types/contextApi';\nimport type { ContextItemSource, ContextSkillInventory } from '../contextProjection';\nimport { type CountTokens, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * The prose and schema behind the projection's figures.\n *\n * Built from the same inventory in the same pass, so a detail can never\n * describe a composition the panel is not showing. Nothing is grouped here:\n * the panel already knows which mode a row sits under, and a lookup by name is\n * all a click needs.\n */\n\nconst MCP_KEY_PREFIX = 'mcp:';\nconst CORE_OWNER = 'pi';\n\n/** The same join the projection makes, so a row and its detail agree on the owner. */\nfunction ownerOf(source: ToolSource): string {\n if (source.kind === 'extension') return source.packageName ?? source.key;\n if (source.kind === 'mcp') return source.key.slice(MCP_KEY_PREFIX.length);\n return CORE_OWNER;\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nexport interface ContextDetailInput {\n readonly sources: readonly ToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n readonly countTokens: CountTokens;\n /** The assembled prompt, when the host has one to report. */\n readonly systemPrompt?: { readonly text: string; readonly tokens: number; readonly stage: ContextPromptStage };\n}\n\nexport function buildContextDetail(input: ContextDetailInput): ContextItemDetail[] {\n const items: ContextItemDetail[] = [];\n\n for (const source of input.sources) {\n const owner = ownerOf(source);\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const detail: ContextToolDetail = {\n itemKind: 'tool',\n name: tool.name,\n owner,\n source: source.kind === 'core' ? 'core' : source.kind,\n active: tool.active,\n tokens: { schemaTokens: cost.schemaTokens, promptTokens: cost.promptTokens, totalTokens: cost.totalTokens },\n ...(tool.description ? { description: tool.description } : {}),\n ...(tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {}),\n ...(tool.promptGuidelines?.length ? { promptGuidelines: tool.promptGuidelines } : {}),\n ...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n };\n items.push(detail);\n }\n }\n\n for (const skill of input.skills) {\n items.push({\n itemKind: 'skill',\n name: skill.name,\n owner: skill.owner,\n source: skillSource(skill.group),\n active: true,\n tokens: skill.promptTokens ?? 0,\n description: skill.description,\n ...(skill.filePath === undefined ? {} : { filePath: skill.filePath }),\n modelInvocable: skill.modelInvocable,\n });\n }\n\n if (input.systemPrompt !== undefined) {\n items.push({\n itemKind: 'prompt',\n name: 'system',\n tokens: input.systemPrompt.tokens,\n stage: input.systemPrompt.stage,\n text: input.systemPrompt.text,\n });\n }\n\n return items;\n}\n"],"mappings":";;;AAcA,MAAM,aAAa;;AAGnB,SAAS,QAAQ,QAA4B;CAC3C,IAAI,OAAO,SAAS,aAAa,OAAO,OAAO,eAAe,OAAO;CACrE,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,IAAI,MAAM,CAAqB;CACxE,OAAO;AACT;AAEA,SAAS,YAAY,OAA0D;CAC7E,IAAI,UAAU,WAAW,OAAO;CAChC,IAAI,UAAU,cAAc,OAAO;CACnC,OAAO;AACT;AAUA,SAAgB,mBAAmB,OAAgD;CACjF,MAAM,QAA6B,CAAC;CAEpC,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAQ,QAAQ,MAAM;EAC5B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,OAAOA,cAAAA,cAAc,MAAM,MAAM,WAAW;GAClD,MAAM,SAA4B;IAChC,UAAU;IACV,MAAM,KAAK;IACX;IACA,QAAQ,OAAO,SAAS,SAAS,SAAS,OAAO;IACjD,QAAQ,KAAK;IACb,QAAQ;KAAE,cAAc,KAAK;KAAc,cAAc,KAAK;KAAc,aAAa,KAAK;IAAY;IAC1G,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;IAC5D,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;IAClE,GAAI,KAAK,kBAAkB,SAAS,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;IACnF,GAAI,KAAK,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;GACzE;GACA,MAAM,KAAK,MAAM;EACnB;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,QACxB,MAAM,KAAK;EACT,UAAU;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,QAAQ,YAAY,MAAM,KAAK;EAC/B,QAAQ;EACR,QAAQ,MAAM,gBAAgB;EAC9B,aAAa,MAAM;EACnB,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;EACnE,gBAAgB,MAAM;CACxB,CAAC;CAGH,IAAI,MAAM,iBAAiB,KAAA,GACzB,MAAM,KAAK;EACT,UAAU;EACV,MAAM;EACN,QAAQ,MAAM,aAAa;EAC3B,OAAO,MAAM,aAAa;EAC1B,MAAM,MAAM,aAAa;CAC3B,CAAC;CAGH,OAAO;AACT"}
1
+ {"version":3,"file":"contextDetail.cjs","names":["tokensForTool"],"sources":["../src/services/contextDetail/index.ts"],"sourcesContent":["import type { ContextItemDetail, ContextPromptStage, ContextToolDetail } from '../../types/contextApi';\nimport type { ContextItemSource, ContextSkillInventory } from '../contextProjection';\nimport { type CountTokens, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * The prose and schema behind the projection's figures.\n *\n * Built from the same inventory in the same pass, so a detail can never\n * describe a composition the panel is not showing. Nothing is grouped here:\n * the panel already knows which mode a row sits under, and a lookup by name is\n * all a click needs.\n */\n\nconst MCP_KEY_PREFIX = 'mcp:';\nconst CORE_OWNER = 'pi';\n\n/** The same join the projection makes, so a row and its detail agree on the owner. */\nfunction ownerOf(source: ToolSource): string {\n if (source.kind === 'extension') return source.packageName ?? source.key;\n if (source.kind === 'mcp') return source.key.slice(MCP_KEY_PREFIX.length);\n return CORE_OWNER;\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nexport interface ContextDetailInput {\n readonly sources: readonly ToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n readonly countTokens: CountTokens;\n /** The assembled prompt, when the host has one to report. */\n readonly systemPrompt?: { readonly text: string; readonly tokens: number; readonly stage: ContextPromptStage };\n}\n\nexport function buildContextDetail(input: ContextDetailInput): ContextItemDetail[] {\n const items: ContextItemDetail[] = [];\n\n for (const source of input.sources) {\n const owner = ownerOf(source);\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const detail: ContextToolDetail = {\n itemKind: 'tool',\n name: tool.name,\n owner,\n source: source.kind === 'core' ? 'core' : source.kind,\n active: tool.active,\n tokens: { schemaTokens: cost.schemaTokens, promptTokens: cost.promptTokens, totalTokens: cost.totalTokens },\n ...(tool.description ? { description: tool.description } : {}),\n ...(tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {}),\n ...(tool.promptGuidelines?.length ? { promptGuidelines: tool.promptGuidelines } : {}),\n ...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n };\n items.push(detail);\n }\n }\n\n for (const skill of input.skills) {\n items.push({\n itemKind: 'skill',\n name: skill.name,\n owner: skill.owner,\n source: skillSource(skill.group),\n active: true,\n tokens: skill.promptTokens ?? 0,\n description: skill.description,\n ...(skill.filePath === undefined ? {} : { filePath: skill.filePath }),\n ...(skill.body === undefined ? {} : { body: skill.body }),\n modelInvocable: skill.modelInvocable,\n });\n }\n\n if (input.systemPrompt !== undefined) {\n items.push({\n itemKind: 'prompt',\n name: 'system',\n tokens: input.systemPrompt.tokens,\n stage: input.systemPrompt.stage,\n text: input.systemPrompt.text,\n });\n }\n\n return items;\n}\n"],"mappings":";;;AAcA,MAAM,aAAa;;AAGnB,SAAS,QAAQ,QAA4B;CAC3C,IAAI,OAAO,SAAS,aAAa,OAAO,OAAO,eAAe,OAAO;CACrE,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,IAAI,MAAM,CAAqB;CACxE,OAAO;AACT;AAEA,SAAS,YAAY,OAA0D;CAC7E,IAAI,UAAU,WAAW,OAAO;CAChC,IAAI,UAAU,cAAc,OAAO;CACnC,OAAO;AACT;AAUA,SAAgB,mBAAmB,OAAgD;CACjF,MAAM,QAA6B,CAAC;CAEpC,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAQ,QAAQ,MAAM;EAC5B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,OAAOA,cAAAA,cAAc,MAAM,MAAM,WAAW;GAClD,MAAM,SAA4B;IAChC,UAAU;IACV,MAAM,KAAK;IACX;IACA,QAAQ,OAAO,SAAS,SAAS,SAAS,OAAO;IACjD,QAAQ,KAAK;IACb,QAAQ;KAAE,cAAc,KAAK;KAAc,cAAc,KAAK;KAAc,aAAa,KAAK;IAAY;IAC1G,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;IAC5D,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;IAClE,GAAI,KAAK,kBAAkB,SAAS,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;IACnF,GAAI,KAAK,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;GACzE;GACA,MAAM,KAAK,MAAM;EACnB;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,QACxB,MAAM,KAAK;EACT,UAAU;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,QAAQ,YAAY,MAAM,KAAK;EAC/B,QAAQ;EACR,QAAQ,MAAM,gBAAgB;EAC9B,aAAa,MAAM;EACnB,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;EACnE,GAAI,MAAM,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK;EACvD,gBAAgB,MAAM;CACxB,CAAC;CAGH,IAAI,MAAM,iBAAiB,KAAA,GACzB,MAAM,KAAK;EACT,UAAU;EACV,MAAM;EACN,QAAQ,MAAM,aAAa;EAC3B,OAAO,MAAM,aAAa;EAC1B,MAAM,MAAM,aAAa;CAC3B,CAAC;CAGH,OAAO;AACT"}
@@ -46,6 +46,7 @@ function buildContextDetail(input) {
46
46
  tokens: skill.promptTokens ?? 0,
47
47
  description: skill.description,
48
48
  ...skill.filePath === void 0 ? {} : { filePath: skill.filePath },
49
+ ...skill.body === void 0 ? {} : { body: skill.body },
49
50
  modelInvocable: skill.modelInvocable
50
51
  });
51
52
  if (input.systemPrompt !== void 0) items.push({
@@ -1 +1 @@
1
- {"version":3,"file":"contextDetail.mjs","names":[],"sources":["../src/services/contextDetail/index.ts"],"sourcesContent":["import type { ContextItemDetail, ContextPromptStage, ContextToolDetail } from '../../types/contextApi';\nimport type { ContextItemSource, ContextSkillInventory } from '../contextProjection';\nimport { type CountTokens, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * The prose and schema behind the projection's figures.\n *\n * Built from the same inventory in the same pass, so a detail can never\n * describe a composition the panel is not showing. Nothing is grouped here:\n * the panel already knows which mode a row sits under, and a lookup by name is\n * all a click needs.\n */\n\nconst MCP_KEY_PREFIX = 'mcp:';\nconst CORE_OWNER = 'pi';\n\n/** The same join the projection makes, so a row and its detail agree on the owner. */\nfunction ownerOf(source: ToolSource): string {\n if (source.kind === 'extension') return source.packageName ?? source.key;\n if (source.kind === 'mcp') return source.key.slice(MCP_KEY_PREFIX.length);\n return CORE_OWNER;\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nexport interface ContextDetailInput {\n readonly sources: readonly ToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n readonly countTokens: CountTokens;\n /** The assembled prompt, when the host has one to report. */\n readonly systemPrompt?: { readonly text: string; readonly tokens: number; readonly stage: ContextPromptStage };\n}\n\nexport function buildContextDetail(input: ContextDetailInput): ContextItemDetail[] {\n const items: ContextItemDetail[] = [];\n\n for (const source of input.sources) {\n const owner = ownerOf(source);\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const detail: ContextToolDetail = {\n itemKind: 'tool',\n name: tool.name,\n owner,\n source: source.kind === 'core' ? 'core' : source.kind,\n active: tool.active,\n tokens: { schemaTokens: cost.schemaTokens, promptTokens: cost.promptTokens, totalTokens: cost.totalTokens },\n ...(tool.description ? { description: tool.description } : {}),\n ...(tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {}),\n ...(tool.promptGuidelines?.length ? { promptGuidelines: tool.promptGuidelines } : {}),\n ...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n };\n items.push(detail);\n }\n }\n\n for (const skill of input.skills) {\n items.push({\n itemKind: 'skill',\n name: skill.name,\n owner: skill.owner,\n source: skillSource(skill.group),\n active: true,\n tokens: skill.promptTokens ?? 0,\n description: skill.description,\n ...(skill.filePath === undefined ? {} : { filePath: skill.filePath }),\n modelInvocable: skill.modelInvocable,\n });\n }\n\n if (input.systemPrompt !== undefined) {\n items.push({\n itemKind: 'prompt',\n name: 'system',\n tokens: input.systemPrompt.tokens,\n stage: input.systemPrompt.stage,\n text: input.systemPrompt.text,\n });\n }\n\n return items;\n}\n"],"mappings":";;AAcA,MAAM,aAAa;;AAGnB,SAAS,QAAQ,QAA4B;CAC3C,IAAI,OAAO,SAAS,aAAa,OAAO,OAAO,eAAe,OAAO;CACrE,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,IAAI,MAAM,CAAqB;CACxE,OAAO;AACT;AAEA,SAAS,YAAY,OAA0D;CAC7E,IAAI,UAAU,WAAW,OAAO;CAChC,IAAI,UAAU,cAAc,OAAO;CACnC,OAAO;AACT;AAUA,SAAgB,mBAAmB,OAAgD;CACjF,MAAM,QAA6B,CAAC;CAEpC,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAQ,QAAQ,MAAM;EAC5B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,OAAO,cAAc,MAAM,MAAM,WAAW;GAClD,MAAM,SAA4B;IAChC,UAAU;IACV,MAAM,KAAK;IACX;IACA,QAAQ,OAAO,SAAS,SAAS,SAAS,OAAO;IACjD,QAAQ,KAAK;IACb,QAAQ;KAAE,cAAc,KAAK;KAAc,cAAc,KAAK;KAAc,aAAa,KAAK;IAAY;IAC1G,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;IAC5D,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;IAClE,GAAI,KAAK,kBAAkB,SAAS,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;IACnF,GAAI,KAAK,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;GACzE;GACA,MAAM,KAAK,MAAM;EACnB;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,QACxB,MAAM,KAAK;EACT,UAAU;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,QAAQ,YAAY,MAAM,KAAK;EAC/B,QAAQ;EACR,QAAQ,MAAM,gBAAgB;EAC9B,aAAa,MAAM;EACnB,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;EACnE,gBAAgB,MAAM;CACxB,CAAC;CAGH,IAAI,MAAM,iBAAiB,KAAA,GACzB,MAAM,KAAK;EACT,UAAU;EACV,MAAM;EACN,QAAQ,MAAM,aAAa;EAC3B,OAAO,MAAM,aAAa;EAC1B,MAAM,MAAM,aAAa;CAC3B,CAAC;CAGH,OAAO;AACT"}
1
+ {"version":3,"file":"contextDetail.mjs","names":[],"sources":["../src/services/contextDetail/index.ts"],"sourcesContent":["import type { ContextItemDetail, ContextPromptStage, ContextToolDetail } from '../../types/contextApi';\nimport type { ContextItemSource, ContextSkillInventory } from '../contextProjection';\nimport { type CountTokens, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * The prose and schema behind the projection's figures.\n *\n * Built from the same inventory in the same pass, so a detail can never\n * describe a composition the panel is not showing. Nothing is grouped here:\n * the panel already knows which mode a row sits under, and a lookup by name is\n * all a click needs.\n */\n\nconst MCP_KEY_PREFIX = 'mcp:';\nconst CORE_OWNER = 'pi';\n\n/** The same join the projection makes, so a row and its detail agree on the owner. */\nfunction ownerOf(source: ToolSource): string {\n if (source.kind === 'extension') return source.packageName ?? source.key;\n if (source.kind === 'mcp') return source.key.slice(MCP_KEY_PREFIX.length);\n return CORE_OWNER;\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nexport interface ContextDetailInput {\n readonly sources: readonly ToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n readonly countTokens: CountTokens;\n /** The assembled prompt, when the host has one to report. */\n readonly systemPrompt?: { readonly text: string; readonly tokens: number; readonly stage: ContextPromptStage };\n}\n\nexport function buildContextDetail(input: ContextDetailInput): ContextItemDetail[] {\n const items: ContextItemDetail[] = [];\n\n for (const source of input.sources) {\n const owner = ownerOf(source);\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const detail: ContextToolDetail = {\n itemKind: 'tool',\n name: tool.name,\n owner,\n source: source.kind === 'core' ? 'core' : source.kind,\n active: tool.active,\n tokens: { schemaTokens: cost.schemaTokens, promptTokens: cost.promptTokens, totalTokens: cost.totalTokens },\n ...(tool.description ? { description: tool.description } : {}),\n ...(tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {}),\n ...(tool.promptGuidelines?.length ? { promptGuidelines: tool.promptGuidelines } : {}),\n ...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n };\n items.push(detail);\n }\n }\n\n for (const skill of input.skills) {\n items.push({\n itemKind: 'skill',\n name: skill.name,\n owner: skill.owner,\n source: skillSource(skill.group),\n active: true,\n tokens: skill.promptTokens ?? 0,\n description: skill.description,\n ...(skill.filePath === undefined ? {} : { filePath: skill.filePath }),\n ...(skill.body === undefined ? {} : { body: skill.body }),\n modelInvocable: skill.modelInvocable,\n });\n }\n\n if (input.systemPrompt !== undefined) {\n items.push({\n itemKind: 'prompt',\n name: 'system',\n tokens: input.systemPrompt.tokens,\n stage: input.systemPrompt.stage,\n text: input.systemPrompt.text,\n });\n }\n\n return items;\n}\n"],"mappings":";;AAcA,MAAM,aAAa;;AAGnB,SAAS,QAAQ,QAA4B;CAC3C,IAAI,OAAO,SAAS,aAAa,OAAO,OAAO,eAAe,OAAO;CACrE,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,IAAI,MAAM,CAAqB;CACxE,OAAO;AACT;AAEA,SAAS,YAAY,OAA0D;CAC7E,IAAI,UAAU,WAAW,OAAO;CAChC,IAAI,UAAU,cAAc,OAAO;CACnC,OAAO;AACT;AAUA,SAAgB,mBAAmB,OAAgD;CACjF,MAAM,QAA6B,CAAC;CAEpC,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAQ,QAAQ,MAAM;EAC5B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,OAAO,cAAc,MAAM,MAAM,WAAW;GAClD,MAAM,SAA4B;IAChC,UAAU;IACV,MAAM,KAAK;IACX;IACA,QAAQ,OAAO,SAAS,SAAS,SAAS,OAAO;IACjD,QAAQ,KAAK;IACb,QAAQ;KAAE,cAAc,KAAK;KAAc,cAAc,KAAK;KAAc,aAAa,KAAK;IAAY;IAC1G,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;IAC5D,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;IAClE,GAAI,KAAK,kBAAkB,SAAS,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;IACnF,GAAI,KAAK,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;GACzE;GACA,MAAM,KAAK,MAAM;EACnB;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,QACxB,MAAM,KAAK;EACT,UAAU;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,QAAQ,YAAY,MAAM,KAAK;EAC/B,QAAQ;EACR,QAAQ,MAAM,gBAAgB;EAC9B,aAAa,MAAM;EACnB,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;EACnE,GAAI,MAAM,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK;EACvD,gBAAgB,MAAM;CACxB,CAAC;CAGH,IAAI,MAAM,iBAAiB,KAAA,GACzB,MAAM,KAAK;EACT,UAAU;EACV,MAAM;EACN,QAAQ,MAAM,aAAa;EAC3B,OAAO,MAAM,aAAa;EAC1B,MAAM,MAAM,aAAa;CAC3B,CAAC;CAGH,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextProjection.cjs","names":["tokensForTool"],"sources":["../src/services/contextProjection/index.ts"],"sourcesContent":["/** What admitted a package into the composition. */\nexport interface PackageAttribution {\n /** `major` for a layer package, `domain` for a plugin a domain carries. */\n kind: 'major' | 'domain';\n /** The major mode name, or the domain name. */\n mode: string;\n /** The layer the package was listed under; absent for a domain plugin. */\n layer?: string;\n}\n\nimport type { ContextPromptStage } from '../../types/contextApi';\nimport { type CountTokens, type ToolEntry, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\n/**\n * What the assembled system prompt costs, and how complete the figure is.\n *\n * Kept out of `groups` on purpose. Every tool's prose and every skill's listing\n * already count inside the group subtotals, and those are slices of this same\n * text, so folding it into `totalTokens` would bill them twice.\n */\nexport interface ContextSystemPromptProjection {\n readonly tokens: number;\n readonly stage: ContextPromptStage;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n /** Selection snapshot used to build this projection, replayable after reconnect. */\n readonly selection: {\n readonly majorMode: string;\n readonly domains: readonly string[];\n readonly profile?: string;\n };\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly systemPrompt?: ContextSystemPromptProjection;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextConditionalAttribution {\n readonly kind: 'minor' | 'domain';\n readonly mode: string;\n readonly label?: string;\n}\n\nexport interface ContextToolInventory extends ToolEntry {\n /** A contribution-level gate is more specific than its package's major-mode owner. */\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextToolSource extends Omit<ToolSource, 'tools'> {\n readonly tools: readonly ContextToolInventory[];\n}\n\n/** Skill fields needed to project cost and serve detail. Virtual resources may not have a filesystem path. */\nexport interface ContextSkillInventory {\n readonly name: string;\n readonly description: string;\n readonly group: 'extensions' | 'help' | 'plugins' | 'default';\n readonly owner: string;\n readonly modelInvocable: boolean;\n readonly promptTokens?: number;\n readonly filePath?: string;\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n readonly profile?: string;\n /** Additional groups supplied by the composition owner, in display order. */\n readonly groups: readonly { readonly id: string; readonly label: string; readonly kind: ContextGroupKind }[];\n /** Domains the composition resolved under, whether or not they carried a plugin. */\n readonly domains: readonly string[];\n readonly sources: readonly ContextToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n /** Absent until the session has a prompt to report. */\n readonly systemPrompt?: ContextSystemPromptProjection;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const group of input.groups) declare(group.id, group.label, group.kind);\n // A domain that contributed no plugin is still part of what the session is\n // running under, and a reader comparing the panel against the footer would\n // otherwise read its absence as the panel being out of date.\n for (const domain of input.domains) declare(domain, domain, 'domain');\n\n const place = (owner: string, item: ContextItemProjection, conditional?: ContextConditionalAttribution): void => {\n const attributed = conditional ?? input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n const kind = attributed?.kind ?? 'core';\n declare(id, attributed && 'label' in attributed ? (attributed.label ?? id) : id, kind);\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item, tool.contextAttribution);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(\n skill.owner,\n {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n },\n skill.contextAttribution,\n );\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n selection: {\n majorMode: input.majorMode,\n domains: [...input.domains],\n ...(input.profile === undefined ? {} : { profile: input.profile }),\n },\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextProjection.cjs","names":["tokensForTool"],"sources":["../src/services/contextProjection/index.ts"],"sourcesContent":["/** What admitted a package into the composition. */\nexport interface PackageAttribution {\n /** `major` for a layer package, `domain` for a plugin a domain carries. */\n kind: 'major' | 'domain';\n /** The major mode name, or the domain name. */\n mode: string;\n /** The layer the package was listed under; absent for a domain plugin. */\n layer?: string;\n}\n\nimport type { ContextPromptStage } from '../../types/contextApi';\nimport { type CountTokens, type ToolEntry, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\n/**\n * What the assembled system prompt costs, and how complete the figure is.\n *\n * Kept out of `groups` on purpose. Every tool's prose and every skill's listing\n * already count inside the group subtotals, and those are slices of this same\n * text, so folding it into `totalTokens` would bill them twice.\n */\nexport interface ContextSystemPromptProjection {\n readonly tokens: number;\n readonly stage: ContextPromptStage;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n /** Selection snapshot used to build this projection, replayable after reconnect. */\n readonly selection: {\n readonly majorMode: string;\n readonly domains: readonly string[];\n readonly profile?: string;\n };\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly systemPrompt?: ContextSystemPromptProjection;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextConditionalAttribution {\n readonly kind: 'minor' | 'domain';\n readonly mode: string;\n readonly label?: string;\n}\n\nexport interface ContextToolInventory extends ToolEntry {\n /** A contribution-level gate is more specific than its package's major-mode owner. */\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextToolSource extends Omit<ToolSource, 'tools'> {\n readonly tools: readonly ContextToolInventory[];\n}\n\n/** Skill fields needed to project cost and serve detail. Virtual resources may not have a filesystem path. */\nexport interface ContextSkillInventory {\n readonly name: string;\n readonly description: string;\n readonly group: 'extensions' | 'help' | 'plugins' | 'default';\n readonly owner: string;\n readonly modelInvocable: boolean;\n readonly promptTokens?: number;\n readonly filePath?: string;\n /** The skill's instructions, when the host holds them; read only when a reader opens the row. */\n readonly body?: string;\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n readonly profile?: string;\n /** Additional groups supplied by the composition owner, in display order. */\n readonly groups: readonly { readonly id: string; readonly label: string; readonly kind: ContextGroupKind }[];\n /** Domains the composition resolved under, whether or not they carried a plugin. */\n readonly domains: readonly string[];\n readonly sources: readonly ContextToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n /** Absent until the session has a prompt to report. */\n readonly systemPrompt?: ContextSystemPromptProjection;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const group of input.groups) declare(group.id, group.label, group.kind);\n // A domain that contributed no plugin is still part of what the session is\n // running under, and a reader comparing the panel against the footer would\n // otherwise read its absence as the panel being out of date.\n for (const domain of input.domains) declare(domain, domain, 'domain');\n\n const place = (owner: string, item: ContextItemProjection, conditional?: ContextConditionalAttribution): void => {\n const attributed = conditional ?? input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n const kind = attributed?.kind ?? 'core';\n declare(id, attributed && 'label' in attributed ? (attributed.label ?? id) : id, kind);\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item, tool.contextAttribution);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(\n skill.owner,\n {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n },\n skill.contextAttribution,\n );\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n selection: {\n majorMode: input.majorMode,\n domains: [...input.domains],\n ...(input.profile === undefined ? {} : { profile: input.profile }),\n },\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":"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"}
@@ -95,6 +95,8 @@ export interface ContextSkillInventory {
95
95
  readonly modelInvocable: boolean;
96
96
  readonly promptTokens?: number;
97
97
  readonly filePath?: string;
98
+ /** The skill's instructions, when the host holds them; read only when a reader opens the row. */
99
+ readonly body?: string;
98
100
  readonly contextAttribution?: ContextConditionalAttribution;
99
101
  }
100
102
  export interface ContextProjectionInput {
@@ -1 +1 @@
1
- {"version":3,"file":"contextProjection.d.mts","names":[],"sources":["../src/services/contextProjection/index.ts"],"mappings":";;;;;iBACiB;;EAEf;;EAEA;;EAEA;;;;;;;;;;;;;qBAiBW;;qBAGA;;qBAGA;YAED;YACA;iBAWK;WACN;WACA;WACA,QAAQ;;WAER;WACA;WACA;;iBAGM;WACN;WACA;WACA,MAAM;WACN,gBAAgB;;WAEhB;;WAEA;;;;;;;;;iBAUM;WACN;WACA,OAAO;;iBAGD;WACN,gBAAgB;WAChB;;WAEA;aACE;aACA;aACA;;WAEF,iBAAiB;WACjB;WACA;WACA,eAAe;WACf,kBAAkB;;iBAGZ;WACN;WACA;WACA;;iBAGM,6BAA6B;;WAEnC,qBAAqB;;iBAGf,0BAA0B,KAAK;WACrC,gBAAgB;;;iBAIV;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA,qBAAqB;;iBAGf;WACN;WACA;WACA;;WAEA;aAA4B;aAAqB;aAAwB,MAAM;;;WAE/E;WACA,kBAAkB;WAClB,iBAAiB;;;;;;;;WAQjB,aAAa,SAAS,eAAe;WACrC,aAAa;;WAEb,eAAe;;wBAmBV,eAAe,OAAO,yBAAyB"}
1
+ {"version":3,"file":"contextProjection.d.mts","names":[],"sources":["../src/services/contextProjection/index.ts"],"mappings":";;;;;iBACiB;;EAEf;;EAEA;;EAEA;;;;;;;;;;;;;qBAiBW;;qBAGA;;qBAGA;YAED;YACA;iBAWK;WACN;WACA;WACA,QAAQ;;WAER;WACA;WACA;;iBAGM;WACN;WACA;WACA,MAAM;WACN,gBAAgB;;WAEhB;;WAEA;;;;;;;;;iBAUM;WACN;WACA,OAAO;;iBAGD;WACN,gBAAgB;WAChB;;WAEA;aACE;aACA;aACA;;WAEF,iBAAiB;WACjB;WACA;WACA,eAAe;WACf,kBAAkB;;iBAGZ;WACN;WACA;WACA;;iBAGM,6BAA6B;;WAEnC,qBAAqB;;iBAGf,0BAA0B,KAAK;WACrC,gBAAgB;;;iBAIV;WACN;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;WACA,qBAAqB;;iBAGf;WACN;WACA;WACA;;WAEA;aAA4B;aAAqB;aAAwB,MAAM;;;WAE/E;WACA,kBAAkB;WAClB,iBAAiB;;;;;;;;WAQjB,aAAa,SAAS,eAAe;WACrC,aAAa;;WAEb,eAAe;;wBAmBV,eAAe,OAAO,yBAAyB"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextProjection.mjs","names":[],"sources":["../src/services/contextProjection/index.ts"],"sourcesContent":["/** What admitted a package into the composition. */\nexport interface PackageAttribution {\n /** `major` for a layer package, `domain` for a plugin a domain carries. */\n kind: 'major' | 'domain';\n /** The major mode name, or the domain name. */\n mode: string;\n /** The layer the package was listed under; absent for a domain plugin. */\n layer?: string;\n}\n\nimport type { ContextPromptStage } from '../../types/contextApi';\nimport { type CountTokens, type ToolEntry, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\n/**\n * What the assembled system prompt costs, and how complete the figure is.\n *\n * Kept out of `groups` on purpose. Every tool's prose and every skill's listing\n * already count inside the group subtotals, and those are slices of this same\n * text, so folding it into `totalTokens` would bill them twice.\n */\nexport interface ContextSystemPromptProjection {\n readonly tokens: number;\n readonly stage: ContextPromptStage;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n /** Selection snapshot used to build this projection, replayable after reconnect. */\n readonly selection: {\n readonly majorMode: string;\n readonly domains: readonly string[];\n readonly profile?: string;\n };\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly systemPrompt?: ContextSystemPromptProjection;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextConditionalAttribution {\n readonly kind: 'minor' | 'domain';\n readonly mode: string;\n readonly label?: string;\n}\n\nexport interface ContextToolInventory extends ToolEntry {\n /** A contribution-level gate is more specific than its package's major-mode owner. */\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextToolSource extends Omit<ToolSource, 'tools'> {\n readonly tools: readonly ContextToolInventory[];\n}\n\n/** Skill fields needed to project cost and serve detail. Virtual resources may not have a filesystem path. */\nexport interface ContextSkillInventory {\n readonly name: string;\n readonly description: string;\n readonly group: 'extensions' | 'help' | 'plugins' | 'default';\n readonly owner: string;\n readonly modelInvocable: boolean;\n readonly promptTokens?: number;\n readonly filePath?: string;\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n readonly profile?: string;\n /** Additional groups supplied by the composition owner, in display order. */\n readonly groups: readonly { readonly id: string; readonly label: string; readonly kind: ContextGroupKind }[];\n /** Domains the composition resolved under, whether or not they carried a plugin. */\n readonly domains: readonly string[];\n readonly sources: readonly ContextToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n /** Absent until the session has a prompt to report. */\n readonly systemPrompt?: ContextSystemPromptProjection;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const group of input.groups) declare(group.id, group.label, group.kind);\n // A domain that contributed no plugin is still part of what the session is\n // running under, and a reader comparing the panel against the footer would\n // otherwise read its absence as the panel being out of date.\n for (const domain of input.domains) declare(domain, domain, 'domain');\n\n const place = (owner: string, item: ContextItemProjection, conditional?: ContextConditionalAttribution): void => {\n const attributed = conditional ?? input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n const kind = attributed?.kind ?? 'core';\n declare(id, attributed && 'label' in attributed ? (attributed.label ?? id) : id, kind);\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item, tool.contextAttribution);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(\n skill.owner,\n {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n },\n skill.contextAttribution,\n );\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n selection: {\n majorMode: input.majorMode,\n domains: [...input.domains],\n ...(input.profile === undefined ? {} : { profile: input.profile }),\n },\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextProjection.mjs","names":[],"sources":["../src/services/contextProjection/index.ts"],"sourcesContent":["/** What admitted a package into the composition. */\nexport interface PackageAttribution {\n /** `major` for a layer package, `domain` for a plugin a domain carries. */\n kind: 'major' | 'domain';\n /** The major mode name, or the domain name. */\n mode: string;\n /** The layer the package was listed under; absent for a domain plugin. */\n layer?: string;\n}\n\nimport type { ContextPromptStage } from '../../types/contextApi';\nimport { type CountTokens, type ToolEntry, type ToolSource, tokensForTool } from '../toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\n/**\n * What the assembled system prompt costs, and how complete the figure is.\n *\n * Kept out of `groups` on purpose. Every tool's prose and every skill's listing\n * already count inside the group subtotals, and those are slices of this same\n * text, so folding it into `totalTokens` would bill them twice.\n */\nexport interface ContextSystemPromptProjection {\n readonly tokens: number;\n readonly stage: ContextPromptStage;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n /** Selection snapshot used to build this projection, replayable after reconnect. */\n readonly selection: {\n readonly majorMode: string;\n readonly domains: readonly string[];\n readonly profile?: string;\n };\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly systemPrompt?: ContextSystemPromptProjection;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextConditionalAttribution {\n readonly kind: 'minor' | 'domain';\n readonly mode: string;\n readonly label?: string;\n}\n\nexport interface ContextToolInventory extends ToolEntry {\n /** A contribution-level gate is more specific than its package's major-mode owner. */\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextToolSource extends Omit<ToolSource, 'tools'> {\n readonly tools: readonly ContextToolInventory[];\n}\n\n/** Skill fields needed to project cost and serve detail. Virtual resources may not have a filesystem path. */\nexport interface ContextSkillInventory {\n readonly name: string;\n readonly description: string;\n readonly group: 'extensions' | 'help' | 'plugins' | 'default';\n readonly owner: string;\n readonly modelInvocable: boolean;\n readonly promptTokens?: number;\n readonly filePath?: string;\n /** The skill's instructions, when the host holds them; read only when a reader opens the row. */\n readonly body?: string;\n readonly contextAttribution?: ContextConditionalAttribution;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n readonly profile?: string;\n /** Additional groups supplied by the composition owner, in display order. */\n readonly groups: readonly { readonly id: string; readonly label: string; readonly kind: ContextGroupKind }[];\n /** Domains the composition resolved under, whether or not they carried a plugin. */\n readonly domains: readonly string[];\n readonly sources: readonly ContextToolSource[];\n readonly skills: readonly ContextSkillInventory[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n /** Absent until the session has a prompt to report. */\n readonly systemPrompt?: ContextSystemPromptProjection;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: ContextSkillInventory['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const group of input.groups) declare(group.id, group.label, group.kind);\n // A domain that contributed no plugin is still part of what the session is\n // running under, and a reader comparing the panel against the footer would\n // otherwise read its absence as the panel being out of date.\n for (const domain of input.domains) declare(domain, domain, 'domain');\n\n const place = (owner: string, item: ContextItemProjection, conditional?: ContextConditionalAttribution): void => {\n const attributed = conditional ?? input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n const kind = attributed?.kind ?? 'core';\n declare(id, attributed && 'label' in attributed ? (attributed.label ?? id) : id, kind);\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item, tool.contextAttribution);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(\n skill.owner,\n {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n },\n skill.contextAttribution,\n );\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n selection: {\n majorMode: input.majorMode,\n domains: [...input.domains],\n ...(input.profile === undefined ? {} : { profile: input.profile }),\n },\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":";;;;;;;;;;;;;AAwBA,MAAa,6BAA6B;;AAG1C,MAAa,0BAA0B;;AAGvC,MAAa,+BAA+B;;AAM5C,MAAM,aAAa;;AAEnB,MAAM,aAAa;AAGnB,MAAM,aAA+C;CAAE,OAAO;CAAG,OAAO;CAAG,QAAQ;CAAG,MAAM;AAAE;AAC9F,MAAM,eAAkD;CAAE,WAAW;CAAG,KAAK;CAAG,QAAQ;CAAG,MAAM;AAAE;AA6GnG,SAAS,YAAY,OAA0D;CAC7E,IAAI,UAAU,WAAW,OAAO;CAChC,IAAI,UAAU,cAAc,OAAO;CACnC,OAAO;AACT;AAEA,SAAS,MAAM,MAA6B,OAAsC;CAChF,OAAO,aAAa,KAAK,UAAU,aAAa,MAAM,WAAW,KAAK,KAAK,cAAc,MAAM,IAAI;AACrG;AAEA,SAAgB,eAAe,OAAkD;CAC/E,MAAM,0BAAU,IAAI,IAAoB;CAKxC,MAAM,WAAW,IAAY,OAAe,SAAiC;EAC3E,IAAI,CAAC,QAAQ,IAAI,EAAE,GAAG,QAAQ,IAAI,IAAI;GAAE;GAAM;GAAO,OAAO,CAAC;EAAE,CAAC;CAClE;CACA,IAAI,MAAM,WAAW,QAAQ,MAAM,WAAW,MAAM,WAAW,OAAO;CACtE,KAAK,MAAM,SAAS,MAAM,QAAQ,QAAQ,MAAM,IAAI,MAAM,OAAO,MAAM,IAAI;CAI3E,KAAK,MAAM,UAAU,MAAM,SAAS,QAAQ,QAAQ,QAAQ,QAAQ;CAEpE,MAAM,SAAS,OAAe,MAA6B,gBAAsD;EAC/G,MAAM,aAAa,eAAe,MAAM,YAAY;EACpD,MAAM,KAAK,YAAY,QAAQ;EAC/B,MAAM,OAAO,YAAY,QAAQ;EACjC,QAAQ,IAAI,cAAc,WAAW,aAAc,WAAW,SAAS,KAAM,IAAI,IAAI;EACrF,QAAQ,IAAI,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI;CAClC;CAEA,KAAK,MAAM,UAAU,MAAM,SAAS;EAIlC,MAAM,QACJ,OAAO,SAAS,cACX,OAAO,eAAe,OAAO,MAC9B,OAAO,SAAS,QACd,OAAO,IAAI,MAAM,CAAqB,IACtC;EACR,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,OAAO,cAAc,MAAM,MAAM,WAAW;GAClD,MAAM,OAA8B;IAClC,MAAM,KAAK;IACX,UAAU;IACV,QAAQ,OAAO,SAAS,SAAS,SAAS,OAAO;IACjD;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK;GACf;GACA,IAAI,OAAO,SAAS,QAAQ;IAC1B,QAAQ,YAAY,YAAY,MAAM;IACtC,QAAQ,IAAI,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI;GAC1C,OACE,MAAM,OAAO,MAAM,KAAK,kBAAkB;EAE9C;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,QACxB,MACE,MAAM,OACN;EACE,MAAM,MAAM;EACZ,UAAU;EACV,QAAQ,YAAY,MAAM,KAAK;EAC/B,OAAO,MAAM;EACb,QAAQ,MAAM,gBAAgB;EAG9B,QAAQ;CACV,GACA,MAAM,kBACR;CAGF,MAAM,SAAmC,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CAC5D,KAAK,CAAC,IAAI,YAAY;EACrB,MAAM,QAAQ,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,KAAK,KAAK;EAI1C,OAAO;GACL;GACA,OAAO,OAAO;GACd,MAAM,OAAO;GACb;GACA,QAAQ,MAAM,QAAQ,OAAO,SAAS,SAAS,KAAK,SAAS,KAAK,SAAS,IAAI,CAAC;GAChF,gBAAgB,MAAM,QAAQ,OAAO,SAAS,SAAS,KAAK,SAAS,IAAI,KAAK,SAAS,CAAC;EAC1F;CACF,CAAC,CAAC,CACD,MAAM,MAAM,UAAU,WAAW,KAAK,QAAQ,WAAW,MAAM,SAAS,KAAK,MAAM,cAAc,MAAM,KAAK,CAAC;CAEhH,OAAO;EACL,SAAA;EACA,UAAU,MAAM;EAChB,WAAW;GACT,WAAW,MAAM;GACjB,SAAS,CAAC,GAAG,MAAM,OAAO;GAC1B,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;EAClE;EACA;EACA,aAAa,OAAO,QAAQ,OAAO,UAAU,QAAQ,MAAM,QAAQ,CAAC;EACpE,gBAAgB,OAAO,QAAQ,OAAO,UAAU,QAAQ,MAAM,gBAAgB,CAAC;EAC/E,GAAI,MAAM,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,MAAM,aAAa;EAC/E,WAAW;CACb;AACF"}
package/dist/headless.cjs CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_headless = require("./src/schemas/headless.cjs");
3
3
  exports.DOOM_HEADLESS_HOST_SERVICE = require_headless.DOOM_HEADLESS_HOST_SERVICE;
4
4
  exports.DOOM_HEADLESS_OWNER = require_headless.DOOM_HEADLESS_OWNER;
5
+ exports.DOOM_LOAD_SKILL_TOOL = require_headless.DOOM_LOAD_SKILL_TOOL;
5
6
  exports.readDoomHeadlessHost = require_headless.readDoomHeadlessHost;
6
7
  exports.readDoomHeadlessOwner = require_headless.readDoomHeadlessOwner;
7
8
  exports.requireDoomHeadlessHost = require_headless.requireDoomHeadlessHost;
@@ -1,2 +1,2 @@
1
- import { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DoomHeadlessActivity, DoomHeadlessCapability, DoomHeadlessCapabilitySnapshot, DoomHeadlessClient, DoomHeadlessClientRequest, DoomHeadlessCommand, DoomHeadlessCompactionResult, DoomHeadlessCondition, DoomHeadlessContent, DoomHeadlessEventName, DoomHeadlessExecutionContext, DoomHeadlessHook, DoomHeadlessHookEvent, DoomHeadlessHookResult, DoomHeadlessHostService, DoomHeadlessModelSettings, DoomHeadlessRegistration, DoomHeadlessResource, DoomHeadlessSelection, DoomHeadlessSelectionChange, DoomHeadlessSession, DoomHeadlessTool, DoomHeadlessToolCompletionRequest, DoomHeadlessToolCompletionResult, DoomHeadlessToolRestriction, DoomHeadlessToolResult, DoomMcpSkillAccess, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost } from "./src/schemas/headless.mjs";
2
- export { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DoomHeadlessActivity, DoomHeadlessCapability, DoomHeadlessCapabilitySnapshot, DoomHeadlessClient, DoomHeadlessClientRequest, DoomHeadlessCommand, DoomHeadlessCompactionResult, DoomHeadlessCondition, DoomHeadlessContent, DoomHeadlessEventName, DoomHeadlessExecutionContext, DoomHeadlessHook, DoomHeadlessHookEvent, DoomHeadlessHookResult, DoomHeadlessHostService, DoomHeadlessModelSettings, DoomHeadlessRegistration, DoomHeadlessResource, DoomHeadlessSelection, DoomHeadlessSelectionChange, DoomHeadlessSession, DoomHeadlessTool, DoomHeadlessToolCompletionRequest, DoomHeadlessToolCompletionResult, DoomHeadlessToolRestriction, DoomHeadlessToolResult, DoomMcpSkillAccess, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost };
1
+ import { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DOOM_LOAD_SKILL_TOOL, DoomHeadlessActivity, DoomHeadlessCapability, DoomHeadlessCapabilitySnapshot, DoomHeadlessClient, DoomHeadlessClientRequest, DoomHeadlessCommand, DoomHeadlessCompactionResult, DoomHeadlessCondition, DoomHeadlessContent, DoomHeadlessEventName, DoomHeadlessExecutionContext, DoomHeadlessHook, DoomHeadlessHookEvent, DoomHeadlessHookResult, DoomHeadlessHostService, DoomHeadlessModelSettings, DoomHeadlessRegistration, DoomHeadlessResource, DoomHeadlessSelection, DoomHeadlessSelectionChange, DoomHeadlessSession, DoomHeadlessTool, DoomHeadlessToolCompletionRequest, DoomHeadlessToolCompletionResult, DoomHeadlessToolRestriction, DoomHeadlessToolResult, DoomMcpSkillAccess, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost } from "./src/schemas/headless.mjs";
2
+ export { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DOOM_LOAD_SKILL_TOOL, DoomHeadlessActivity, DoomHeadlessCapability, DoomHeadlessCapabilitySnapshot, DoomHeadlessClient, DoomHeadlessClientRequest, DoomHeadlessCommand, DoomHeadlessCompactionResult, DoomHeadlessCondition, DoomHeadlessContent, DoomHeadlessEventName, DoomHeadlessExecutionContext, DoomHeadlessHook, DoomHeadlessHookEvent, DoomHeadlessHookResult, DoomHeadlessHostService, DoomHeadlessModelSettings, DoomHeadlessRegistration, DoomHeadlessResource, DoomHeadlessSelection, DoomHeadlessSelectionChange, DoomHeadlessSession, DoomHeadlessTool, DoomHeadlessToolCompletionRequest, DoomHeadlessToolCompletionResult, DoomHeadlessToolRestriction, DoomHeadlessToolResult, DoomMcpSkillAccess, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost };
package/dist/headless.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost } from "./src/schemas/headless.mjs";
2
- export { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost };
1
+ import { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DOOM_LOAD_SKILL_TOOL, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost } from "./src/schemas/headless.mjs";
2
+ export { DOOM_HEADLESS_HOST_SERVICE, DOOM_HEADLESS_OWNER, DOOM_LOAD_SKILL_TOOL, readDoomHeadlessHost, readDoomHeadlessOwner, requireDoomHeadlessHost };
@@ -2,8 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_index = require("./src/services/serverFacet/index.cjs");
3
3
  const require_serverFacetLoader = require("./src/server/serverFacetLoader.cjs");
4
4
  require("./serverFacet.cjs");
5
+ const require_directHarnessRuntime = require("./src/server/directHarnessRuntime.cjs");
5
6
  const require_pluginProtocol = require("./src/schemas/pluginProtocol.cjs");
6
7
  require("./pluginProtocol.cjs");
8
+ let _earendil_works_pi_agent_core_harness_context = require("@earendil-works/pi-agent-core/harness/context");
7
9
  //#region src/server/headlessHub.ts
8
10
  const AUTHORIZATION_HEADER = "authorization";
9
11
  const CHANNEL_PRIORITY = {
@@ -11,12 +13,30 @@ const CHANNEL_PRIORITY = {
11
13
  workspace: 1,
12
14
  session: 2
13
15
  };
16
+ /**
17
+ * When a reopened session last settled, from the marker its runtime journals at every run end.
18
+ * Without it a session with a whole history would read as fresh until its next turn.
19
+ */
20
+ async function lastSettledAt(host) {
21
+ try {
22
+ const entry = await host.runtime.lane.findEntry({
23
+ type: "custom",
24
+ customType: require_directHarnessRuntime.AGENT_SETTLED_ENTRY_TYPE,
25
+ order: "newestFirst"
26
+ }, _earendil_works_pi_agent_core_harness_context.BACKGROUND_CONTEXT);
27
+ const data = entry?.type === "custom" ? entry.data : void 0;
28
+ return typeof data?.timestamp === "number" && Number.isFinite(data.timestamp) ? new Date(data.timestamp).toISOString() : void 0;
29
+ } catch {
30
+ return;
31
+ }
32
+ }
14
33
  function scopeOf(session) {
15
34
  return {
16
35
  sessionId: session.id,
17
36
  ...session.workspaceId === void 0 ? {} : { workspaceId: session.workspaceId },
18
37
  cwd: session.cwd,
19
- ...session.environment === void 0 ? {} : { environment: session.environment }
38
+ ...session.environment === void 0 ? {} : { environment: session.environment },
39
+ ...session.host.sessionContext === void 0 ? {} : { sessionContext: session.host.sessionContext }
20
40
  };
21
41
  }
22
42
  /** Owns direct, same-process session and channel state for presentation adapters. */
@@ -420,7 +440,8 @@ function createHeadlessHub(options) {
420
440
  const register = (session) => {
421
441
  if (closed) throw new Error("The headless hub is closed.");
422
442
  if (sessions.has(session.id)) throw new Error(`Session '${session.id}' is already registered.`);
423
- if (sessionShutdowns.has(session.id)) throw new Error(`Session '${session.id}' is still shutting down.`);
443
+ if (sessionShutdowns.get(session.id)?.pending) throw new Error(`Session '${session.id}' is still shutting down.`);
444
+ sessionShutdowns.delete(session.id);
424
445
  let current = {
425
446
  ...session,
426
447
  updatedAt: session.updatedAt ?? session.createdAt,
@@ -664,8 +685,12 @@ function createHeadlessHub(options) {
664
685
  pluginRegistry,
665
686
  invokePlugin: (call, direction, caller) => pluginRegistry.invoke(call, direction, caller),
666
687
  async create(sessionOptions) {
688
+ const id = sessionOptions.sessionId;
667
689
  if (closed) throw new Error("The headless hub is closed.");
690
+ if (sessions.has(id)) throw new Error(`Session '${id}' is already registered.`);
691
+ if (sessionShutdowns.get(id)?.pending) throw new Error(`Session '${id}' is still shutting down.`);
668
692
  const host = await options.manager.create(sessionOptions);
693
+ const settledAt = await lastSettledAt(host);
669
694
  const session = {
670
695
  id: sessionOptions.sessionId,
671
696
  workspaceId: sessionOptions.workspaceId,
@@ -676,9 +701,18 @@ function createHeadlessHub(options) {
676
701
  ...sessionOptions.parentSessionId === void 0 ? {} : { parentSessionId: sessionOptions.parentSessionId },
677
702
  ...sessionOptions.sessionProvenance === void 0 ? {} : { sessionProvenance: sessionOptions.sessionProvenance },
678
703
  environment: sessionOptions.environment,
704
+ ...settledAt === void 0 ? {} : {
705
+ everPrompted: true,
706
+ lastSettledAt: settledAt
707
+ },
679
708
  host
680
709
  };
681
- register(session);
710
+ try {
711
+ register(session);
712
+ } catch (error) {
713
+ await Promise.resolve(options.manager.closeSession(id)).catch((closeError) => options.onNotice?.(`Session '${id}' could not be closed after a failed registration: ${String(closeError)}`));
714
+ throw error;
715
+ }
682
716
  return session;
683
717
  },
684
718
  closeSession,