@xopcai/xopc 0.0.254 → 0.0.256

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 (198) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-Ci5Rxmi_.js → activity-store-DYb6xFC3.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-D82jpmFL.js → agent-avatar-dicebear-BZJZvmYw.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Bq7GNF1L.js +1 -0
  6. package/dist/gateway/static/root/assets/{agents-p3kWyz1T.js → agents-1vtaw07m.js} +1 -1
  7. package/dist/gateway/static/root/assets/{api-CXIzQJ2Z.js → api-NADZ8X8B.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-mhxcQpkQ.js → app-management-settings-panel-DG64SQsx.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-BIMwACUF.js → appearance-settings-BRWQdIIy.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-D3ziBisx.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-C63Xp_sU.js → archive-plugin-D3FQ9VzV.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-D12KYOav.js → attachment-load-Cid3dBaW.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-DXj0o5CY.js → automations-page-BUTNaZtj.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-D4NJSE8l.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-Bcv8hun6.js → binary-plugins-BSYMCuaB.js} +1 -1
  16. package/dist/gateway/static/root/assets/block-editor-qDlC3t7b.js +159 -0
  17. package/dist/gateway/static/root/assets/{browser-automation-inputs-CAclu735.js → browser-automation-inputs-rA2QROKe.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-automations-page-BITfKX8L.js → browser-automations-page-Du1KVE01.js} +2 -2
  19. package/dist/gateway/static/root/assets/browser-settings-page-WZ0Jt5Hp.js +8 -0
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-D1AYoRx4.js +7 -0
  21. package/dist/gateway/static/root/assets/channels-settings-CZnlYu2L.js +1 -0
  22. package/dist/gateway/static/root/assets/{channels-status-swr-Cmbx0E8O.js → channels-status-swr-B2aMPOSM.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-CNBgHN9U.js → chat-terminal-dock-CY-I_bCe.js} +2 -2
  24. package/dist/gateway/static/root/assets/{chunk-KS7C4IRE-BaASWQor.js → chunk-KS7C4IRE-Cq1tE_3b.js} +2 -2
  25. package/dist/gateway/static/root/assets/code-editor-CXIH8jQw.js +1 -0
  26. package/dist/gateway/static/root/assets/connectors-page-CkH3gaqs.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-DCTN4QAG.js → cron-expression-z4WOWyBU.js} +1 -1
  28. package/dist/gateway/static/root/assets/date-picker-vKUcJeQZ.js +1 -0
  29. package/dist/gateway/static/root/assets/{dependency-picker-l6IXzk0C.js → dependency-picker-BpZ9A2gi.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-cGn_20DO.js → desktop-pet-ClrAMqgn.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-DIfccDKS.js → desktop-pet-settings-DKNKGiEG.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-debug-page-CTS5RP_D.js → extension-debug-page-C39hFkJm.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-page-Dg9YssYH.js → extension-page-DkqVsWB7.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-settings-page-CWZYL8Fi.js → extension-settings-page-Be4lFw8f.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-config-swr-Chsr5wGH.js → gateway-config-swr-DEKSw3d-.js} +1 -1
  36. package/dist/gateway/static/root/assets/gateway-settings-HIHGY-0Y.js +1 -0
  37. package/dist/gateway/static/root/assets/{gateway-startup-retry-C9ynH6VV.js → gateway-startup-retry-Dlyt2VhF.js} +1 -1
  38. package/dist/gateway/static/root/assets/{heartbeat-settings-WUhSfvob.js → heartbeat-settings-DiYjWa1F.js} +1 -1
  39. package/dist/gateway/static/root/assets/home-page-BLZNEVmk.js +1 -0
  40. package/dist/gateway/static/root/assets/{image-generation-api-D_TsVe7h.js → image-generation-api-CJIPVk_d.js} +1 -1
  41. package/dist/gateway/static/root/assets/index-50Kr6L6C.css +2 -0
  42. package/dist/gateway/static/root/assets/index-BWdn9NaX.js +76 -0
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DGBf6YfD.js → keyboard-shortcuts-settings-ge76J038.js} +1 -1
  44. package/dist/gateway/static/root/assets/languages-BFe8nIOO.js +2 -0
  45. package/dist/gateway/static/root/assets/local-app-workbench-page-E47xrPDI.js +2 -0
  46. package/dist/gateway/static/root/assets/{local-apps-page-DGWP_xsQ.js → local-apps-page-gkw7VRL4.js} +1 -1
  47. package/dist/gateway/static/root/assets/{locale-store-B2v8mNJw.js → locale-store-DJPCr2mb.js} +1 -1
  48. package/dist/gateway/static/root/assets/logs-page-HHtDMSUW.js +2 -0
  49. package/dist/gateway/static/root/assets/{management-settings-DUAZ-dtt.js → management-settings-DOfCSojd.js} +1 -1
  50. package/dist/gateway/static/root/assets/markdown-editor-BhBJANcx.js +1 -0
  51. package/dist/gateway/static/root/assets/{markdown-view-DBWu9d_n.js → markdown-view-k_PJsY2C.js} +2 -2
  52. package/dist/gateway/static/root/assets/{media-plugins-CsUjcIBy.js → media-plugins-D8wMcUtB.js} +1 -1
  53. package/dist/gateway/static/root/assets/messages-BeIiRpmk.js +3 -0
  54. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-Dxu8twiQ.js → mobile-pairing-wizard-B4Ewewwr.js} +1 -1
  55. package/dist/gateway/static/root/assets/note-detail-panel-DPd5L2A9.js +5 -0
  56. package/dist/gateway/static/root/assets/notes-page-CE_De-iQ.js +8 -0
  57. package/dist/gateway/static/root/assets/{page-tabs-YeJKwV-7.js → page-tabs-DoxnT3X4.js} +1 -1
  58. package/dist/gateway/static/root/assets/popover-select-CKBYnT3c.js +1 -0
  59. package/dist/gateway/static/root/assets/{preview-open-alternatives-BfJ3jMDG.js → preview-open-alternatives-D4oL1yua.js} +1 -1
  60. package/dist/gateway/static/root/assets/product-open-page-CeStuxSl.js +1 -0
  61. package/dist/gateway/static/root/assets/project-detail-page-DXhBJzJy.js +1 -0
  62. package/dist/gateway/static/root/assets/projects-page-CcqhmZoX.js +1 -0
  63. package/dist/gateway/static/root/assets/{registry-api-B9OZUdwC.js → registry-api-Dalzf2w0.js} +1 -1
  64. package/dist/gateway/static/root/assets/remote-access-hub-ulmJT_Ac.js +1 -0
  65. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-uJ8Br3ZL.js → runtime-tools-settings-panel-CrOpchy5.js} +2 -2
  66. package/dist/gateway/static/root/assets/{schema-form-CXwn6up5.js → schema-form-Dk52v4cQ.js} +1 -1
  67. package/dist/gateway/static/root/assets/sessions-page-RM0kAsNa.js +1 -0
  68. package/dist/gateway/static/root/assets/settings-advanced-gate-BfLbu67w.js +1 -0
  69. package/dist/gateway/static/root/assets/{settings-form-section-YVNYsR0U.js → settings-form-section-dvGi1APN.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-cHqrIdVR.js → settings-page-CEYjEm2D.js} +1 -1
  71. package/dist/gateway/static/root/assets/setup-status-panel-BZ4i0CYX.js +1 -0
  72. package/dist/gateway/static/root/assets/{share-preview-page-DnjSDQru.js → share-preview-page-DP4Qgsv6.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-B5yHTrGO.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-BicZK04u.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-DkrGEdiY.js → skills-page-Dlr1Ue1w.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-CqZbiZuK.js → skills-page.utils-I1wcnceD.js} +1 -1
  77. package/dist/gateway/static/root/assets/source-workspace-editor-DunRD1gY.js +1 -0
  78. package/dist/gateway/static/root/assets/{system-settings-panel-Dmw0RfxZ.js → system-settings-panel-DIaFAHT0.js} +1 -1
  79. package/dist/gateway/static/root/assets/task-detail-page-4_5g-V8B.js +1 -0
  80. package/dist/gateway/static/root/assets/{theme-store-CubltMKm.js → theme-store-DYDrhfnD.js} +1 -1
  81. package/dist/gateway/static/root/assets/{tunnel-api-CiieC6HP.js → tunnel-api-DAXx1rHF.js} +1 -1
  82. package/dist/gateway/static/root/assets/{use-autosave-XQ3SuyB9.js → use-autosave-BwEFbveP.js} +1 -1
  83. package/dist/gateway/static/root/assets/user-model-page-CQnXw4ba.js +2 -0
  84. package/dist/gateway/static/root/assets/{vendor-codemirror-Qdcjid65.js → vendor-codemirror-DFxP3B9T.js} +16 -16
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-D4QzVgdt.js → voice-api-key-field-C-WbC2fM.js} +1 -1
  86. package/dist/gateway/static/root/assets/{voice-config-api-B1ZbyVmF.js → voice-config-api-Ds0z9O11.js} +1 -1
  87. package/dist/gateway/static/root/assets/{work-discovery-overlay-D5Tf8GRZ.js → work-discovery-overlay-DiGw5KKj.js} +1 -1
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BW9p8Maz.js → workflow-run-setup-panel-BIU2wg99.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-D3Z7JVHH.js +6 -0
  90. package/dist/gateway/static/root/index.html +12 -12
  91. package/dist/package.js +1 -1
  92. package/dist/packages/gateway-contract/src/user-message-display.js +0 -18
  93. package/dist/src/agent/context/execution-context.js +34 -21
  94. package/dist/src/agent/context/execution-context.types.d.ts +2 -0
  95. package/dist/src/agent/inbound/attachment-pipeline.d.ts +1 -0
  96. package/dist/src/agent/inbound/attachment-pipeline.js +6 -1
  97. package/dist/src/agent/prompt/sections/memory-skills.js +2 -1
  98. package/dist/src/agent/prompt/sections/tooling.js +2 -0
  99. package/dist/src/agent/tools/create-share-tool.js +39 -1
  100. package/dist/src/agent/tools/delegate-tool.js +1 -0
  101. package/dist/src/agent/tools/factory.js +14 -1
  102. package/dist/src/agent/tools/index.d.ts +1 -1
  103. package/dist/src/agent/tools/index.js +2 -2
  104. package/dist/src/agent/tools/user-context-tool.d.ts +3 -0
  105. package/dist/src/agent/tools/user-context-tool.js +147 -4
  106. package/dist/src/agent/workflow/catalog.js +6 -2
  107. package/dist/src/chat-commands/builtins/workflow.js +1 -1
  108. package/dist/src/cli/commands/tunnel.js +3 -3
  109. package/dist/src/connectors/connected-source-understanding.js +4 -4
  110. package/dist/src/gateway/agent-builtin-tools.d.ts +7 -1
  111. package/dist/src/gateway/agent-builtin-tools.js +7 -0
  112. package/dist/src/gateway/device-routes.js +1 -1
  113. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  114. package/dist/src/gateway/hono/routes/lazy-bundles.js +2 -2
  115. package/dist/src/gateway/hono/routes/sessions.js +1 -1
  116. package/dist/src/gateway/hono/routes/shares.js +404 -7
  117. package/dist/src/gateway/hono/routes/site-shares.js +19 -13
  118. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  119. package/dist/src/gateway/hono/routes/user-model.js +35 -102
  120. package/dist/src/gateway/hono/routes/workflows.js +7 -4
  121. package/dist/src/gateway/service/sessions-api.js +1 -1
  122. package/dist/src/gateway/service.js +6 -6
  123. package/dist/src/remote-access/exposure-manager.js +1 -1
  124. package/dist/src/session/index.js +1 -1
  125. package/dist/src/session/store.js +1 -1
  126. package/dist/src/share/hosted-note-publication.d.ts +22 -0
  127. package/dist/src/share/hosted-note-publication.js +96 -0
  128. package/dist/src/share/hosted-session-share.d.ts +86 -7
  129. package/dist/src/share/hosted-session-share.js +72 -15
  130. package/dist/src/share/hosted-static-site-publication.d.ts +16 -0
  131. package/dist/src/share/hosted-static-site-publication.js +108 -0
  132. package/dist/src/share/hosted-static-site-publish.d.ts +23 -0
  133. package/dist/src/share/hosted-static-site-publish.js +53 -0
  134. package/dist/src/share/note-share-service.d.ts +1 -0
  135. package/dist/src/share/note-share-service.js +4 -4
  136. package/dist/src/share/share-url.d.ts +1 -1
  137. package/dist/src/share/share-url.js +14 -9
  138. package/dist/src/tui/backends/embedded-backend.js +2 -2
  139. package/dist/src/tui/tui-agent-events.js +1 -1
  140. package/dist/src/tui/tui-workflow-slash.d.ts +3 -6
  141. package/dist/src/tui/tui-workflow-slash.js +3 -6
  142. package/dist/src/tunnel/index.js +1 -1
  143. package/dist/src/tunnel/tunnel-service.js +1 -1
  144. package/dist/src/user-model/bootstrap.d.ts +17 -0
  145. package/dist/src/user-model/bootstrap.js +118 -0
  146. package/dist/src/user-model/index.d.ts +3 -0
  147. package/dist/src/user-model/index.js +4 -1
  148. package/dist/src/user-model/profile.d.ts +5 -0
  149. package/dist/src/user-model/profile.js +98 -0
  150. package/dist/src/user-model/usage-policy.d.ts +2 -0
  151. package/dist/src/user-model/usage-policy.js +6 -0
  152. package/dist/src/voice/realtime/agentEngine.js +17 -0
  153. package/dist/src/voice/realtime/memory-context.js +1 -1
  154. package/dist/src/voice/realtime/playback-echo.d.ts +2 -0
  155. package/dist/src/voice/realtime/playback-echo.js +15 -0
  156. package/dist/src/work-discovery/analyzer.js +8 -6
  157. package/dist/src/work-discovery/service.d.ts +1 -1
  158. package/dist/src/work-discovery/service.js +4 -4
  159. package/dist/src/work-discovery/types.d.ts +1 -1
  160. package/dist/src/workflows/domain/run.d.ts +8 -1
  161. package/dist/src/workflows/domain/validation.d.ts +3 -4
  162. package/dist/src/workflows/domain/validation.js +119 -8
  163. package/dist/src/workflows/service/workflow-run-service.js +8 -1
  164. package/package.json +5 -5
  165. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-vul32IsP.js +0 -1
  166. package/dist/gateway/static/root/assets/apps-page-CJFJKNwS.js +0 -1
  167. package/dist/gateway/static/root/assets/automations-workspace-B2wxcpgq.js +0 -6
  168. package/dist/gateway/static/root/assets/block-editor-C61LqK_-.js +0 -185
  169. package/dist/gateway/static/root/assets/browser-settings-page-BMjY8cyv.js +0 -8
  170. package/dist/gateway/static/root/assets/capabilities-settings-panel-wB3Vgmp3.js +0 -7
  171. package/dist/gateway/static/root/assets/channels-settings-U5ffzu4r.js +0 -1
  172. package/dist/gateway/static/root/assets/connectors-page-BGaF--m5.js +0 -2
  173. package/dist/gateway/static/root/assets/date-picker-BuEyUxZn.js +0 -1
  174. package/dist/gateway/static/root/assets/gateway-settings-vHI_Que8.js +0 -1
  175. package/dist/gateway/static/root/assets/home-page-CYjlMzPx.js +0 -1
  176. package/dist/gateway/static/root/assets/index-BBlJYVxR.js +0 -74
  177. package/dist/gateway/static/root/assets/index-_I0dD2LN.css +0 -2
  178. package/dist/gateway/static/root/assets/languages-5WaOu0Lf.js +0 -2
  179. package/dist/gateway/static/root/assets/local-app-workbench-page-CLlIl83V.js +0 -2
  180. package/dist/gateway/static/root/assets/logs-page-DuhCigiB.js +0 -2
  181. package/dist/gateway/static/root/assets/markdown-editor-BjMTIM-m.js +0 -1
  182. package/dist/gateway/static/root/assets/messages-ChSTFZR5.js +0 -3
  183. package/dist/gateway/static/root/assets/note-detail-panel-DMdbaTZp.js +0 -5
  184. package/dist/gateway/static/root/assets/notes-page-xe_vX0nM.js +0 -8
  185. package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +0 -1
  186. package/dist/gateway/static/root/assets/product-open-page-B7NRGPox.js +0 -1
  187. package/dist/gateway/static/root/assets/project-detail-page-hG7ELibZ.js +0 -1
  188. package/dist/gateway/static/root/assets/projects-page-C5G2ET4w.js +0 -1
  189. package/dist/gateway/static/root/assets/remote-access-hub-DTO-faxH.js +0 -1
  190. package/dist/gateway/static/root/assets/sessions-page-CwzsUCgP.js +0 -1
  191. package/dist/gateway/static/root/assets/settings-advanced-gate-Djc3EdoO.js +0 -1
  192. package/dist/gateway/static/root/assets/setup-status-panel-MUAMcZLD.js +0 -1
  193. package/dist/gateway/static/root/assets/shares-settings-C7A0aywX.js +0 -1
  194. package/dist/gateway/static/root/assets/skill-reload-api-D1xSGJAQ.js +0 -1
  195. package/dist/gateway/static/root/assets/source-workspace-editor-CVWzt0oT.js +0 -1
  196. package/dist/gateway/static/root/assets/task-detail-page-BvZSCLUH.js +0 -1
  197. package/dist/gateway/static/root/assets/user-model-page-BKJC7tyW.js +0 -2
  198. package/dist/gateway/static/root/assets/workflows-page-DuqRodIc.js +0 -5
@@ -9,7 +9,7 @@ import { SessionShareSnapshotConflictError } from "./session-share-service.js";
9
9
  import { basename } from "node:path";
10
10
  import { createReadStream } from "node:fs";
11
11
  import { createHash, randomBytes, randomUUID } from "node:crypto";
12
- import { readFile, stat } from "node:fs/promises";
12
+ import { stat } from "node:fs/promises";
13
13
  //#region src/share/hosted-session-share.ts
14
14
  init_credentials();
15
15
  init_resolution();
@@ -82,6 +82,7 @@ var HostedSessionShareBuilder = class {
82
82
  cutoffSeq: source.snapshot.lastSeq,
83
83
  manifest: {
84
84
  schemaVersion: 1,
85
+ kind: "session_document",
85
86
  title: (source.metadata.name?.trim() || "Shared conversation").slice(0, 200),
86
87
  snapshotAt: (/* @__PURE__ */ new Date()).toISOString(),
87
88
  ...input.description?.trim() ? { description: input.description.trim().slice(0, 1e3) } : {},
@@ -105,7 +106,7 @@ var HostedSessionShareBuilder = class {
105
106
  };
106
107
  }
107
108
  };
108
- var HostedSessionSharePublisher = class {
109
+ var HostedPublicationPublisher = class {
109
110
  baseUrl;
110
111
  constructor(baseUrl = process.env.XOPC_SHARE_URL ?? resolveConnectedPlatformEndpoint("shareApi") ?? DEFAULT_SHARE_URL, credentials = new CredentialResolver(), fetchImpl = fetch) {
111
112
  this.credentials = credentials;
@@ -113,23 +114,38 @@ var HostedSessionSharePublisher = class {
113
114
  this.baseUrl = baseUrl.replace(/\/+$/, "");
114
115
  }
115
116
  async create(snapshot, lifecycle) {
117
+ return this.createPublication({
118
+ kind: "session_document",
119
+ manifest: snapshot.manifest,
120
+ assets: snapshot.assets
121
+ }, lifecycle);
122
+ }
123
+ async createPublication(snapshot, lifecycle) {
116
124
  const publicToken = randomBytes(32).toString("base64url");
117
- const draft = await this.request("/api/v1/session-shares", {
125
+ const draft = await this.request("/api/v1/publications", {
118
126
  method: "POST",
119
127
  headers: { "Idempotency-Key": `xopc-${randomUUID()}` },
120
128
  body: JSON.stringify({
129
+ kind: snapshot.kind,
121
130
  publicToken,
122
131
  manifest: snapshot.manifest,
123
132
  ...lifecycle
124
133
  })
125
134
  });
126
135
  await this.uploadAssets(draft, snapshot.assets);
127
- const finalized = await this.request(`/api/v1/session-shares/${encodeURIComponent(draft.shareId)}/uploads/${encodeURIComponent(draft.uploadId)}/finalize`, { method: "POST" });
136
+ const finalized = await this.request(`/api/v1/publications/${encodeURIComponent(draft.shareId)}/uploads/${encodeURIComponent(draft.uploadId)}/finalize`, { method: "POST" });
128
137
  if (!draft.publicUrl) throw new Error("Hosted Share did not return a public URL");
129
138
  return toResult(finalized.item, draft.publicUrl);
130
139
  }
131
140
  async refresh(shareId, expectedRevision, publicUrl, snapshot) {
132
- const draft = await this.request(`/api/v1/session-shares/${encodeURIComponent(shareId)}/revisions`, {
141
+ return this.refreshPublication(shareId, expectedRevision, publicUrl, {
142
+ kind: "session_document",
143
+ manifest: snapshot.manifest,
144
+ assets: snapshot.assets
145
+ });
146
+ }
147
+ async refreshPublication(shareId, expectedRevision, publicUrl, snapshot) {
148
+ const draft = await this.request(`/api/v1/publications/${encodeURIComponent(shareId)}/revisions`, {
133
149
  method: "POST",
134
150
  headers: { "Idempotency-Key": `xopc-${randomUUID()}` },
135
151
  body: JSON.stringify({
@@ -138,28 +154,47 @@ var HostedSessionSharePublisher = class {
138
154
  })
139
155
  });
140
156
  await this.uploadAssets(draft, snapshot.assets);
141
- return toResult((await this.request(`/api/v1/session-shares/${encodeURIComponent(shareId)}/uploads/${encodeURIComponent(draft.uploadId)}/finalize`, { method: "POST" })).item, publicUrl);
157
+ return toResult((await this.request(`/api/v1/publications/${encodeURIComponent(shareId)}/uploads/${encodeURIComponent(draft.uploadId)}/finalize`, { method: "POST" })).item, publicUrl);
142
158
  }
143
- async list() {
144
- return (await this.request("/api/v1/session-shares")).items;
159
+ async listPublications() {
160
+ return (await this.request("/api/v1/publications")).items;
161
+ }
162
+ async capabilities() {
163
+ return this.request("/api/v1/publications/capabilities");
145
164
  }
146
165
  async revoke(shareId) {
147
- await this.request(`/api/v1/session-shares/${encodeURIComponent(shareId)}`, { method: "DELETE" });
166
+ await this.revokePublication(shareId);
167
+ }
168
+ async revokePublication(shareId) {
169
+ await this.request(`/api/v1/publications/${encodeURIComponent(shareId)}`, { method: "DELETE" });
170
+ }
171
+ async listRevisions(shareId) {
172
+ return (await this.request(`/api/v1/publications/${encodeURIComponent(shareId)}/revisions`)).items;
173
+ }
174
+ async rollbackPublication(shareId, expectedRevision, targetRevision) {
175
+ return (await this.request(`/api/v1/publications/${encodeURIComponent(shareId)}/rollback`, {
176
+ method: "POST",
177
+ body: JSON.stringify({
178
+ expectedRevision,
179
+ targetRevision
180
+ })
181
+ })).item;
148
182
  }
149
183
  async uploadAssets(draft, assets) {
150
184
  const uploads = new Map(draft.assetUploads.map((upload) => [upload.assetId, upload.uploadUrl]));
151
185
  for (const asset of assets) {
152
186
  const uploadUrl = uploads.get(asset.id);
153
187
  if (!uploadUrl) throw new Error(`Hosted Share did not accept attachment: ${asset.id}`);
154
- const bytes = await readFile(asset.path);
155
- if (bytes.byteLength !== asset.size) throw new Error(`Attachment changed during upload: ${asset.id}`);
188
+ const current = await stat(asset.path);
189
+ if (!current.isFile() || current.size !== asset.size) throw new Error(`Attachment changed during upload: ${asset.id}`);
156
190
  await this.request(uploadUrl, {
157
191
  method: "PUT",
158
192
  headers: {
159
- "Content-Length": String(bytes.byteLength),
193
+ "Content-Length": String(asset.size),
160
194
  "Content-Type": "application/octet-stream"
161
195
  },
162
- body: bytes
196
+ body: createReadStream(asset.path),
197
+ duplex: "half"
163
198
  });
164
199
  }
165
200
  }
@@ -180,7 +215,7 @@ var HostedSessionSharePublisher = class {
180
215
  });
181
216
  const body = await response.json().catch(() => ({}));
182
217
  if (response.status === 401) throw new HostedShareAuthorizationError();
183
- if (!response.ok) throw new Error(body.error?.message || `Hosted Share request failed (${response.status})`);
218
+ if (!response.ok) throw new HostedShareRemoteError(body.error?.message || `Hosted Share request failed (${response.status})`, response.status, body.error?.code);
184
219
  return body;
185
220
  }
186
221
  };
@@ -190,14 +225,36 @@ var HostedShareAuthorizationError = class extends Error {
190
225
  this.name = "HostedShareAuthorizationError";
191
226
  }
192
227
  };
228
+ var HostedShareRemoteError = class extends Error {
229
+ constructor(message, status, code) {
230
+ super(message);
231
+ this.status = status;
232
+ this.code = code;
233
+ this.name = "HostedShareRemoteError";
234
+ }
235
+ };
193
236
  var HostedShareBindingStore = class {
194
237
  state = new DurableState("hosted-share-bindings");
195
238
  async list(sessionId) {
196
239
  return this.state.values().filter((item) => item.sessionId === sessionId).sort((a, b) => b.createdAt.localeCompare(a.createdAt));
197
240
  }
241
+ async listBySource(kind, id) {
242
+ return this.state.values().filter((item) => item.source.kind === kind && item.source.id === id).sort((a, b) => b.createdAt.localeCompare(a.createdAt));
243
+ }
244
+ async listAll() {
245
+ return this.state.values().sort((a, b) => b.createdAt.localeCompare(a.createdAt));
246
+ }
198
247
  async upsert(binding) {
199
248
  this.state.set(binding.id, binding);
200
249
  }
250
+ async markRevoked(id) {
251
+ const binding = this.state.get(id);
252
+ if (binding) this.state.set(id, {
253
+ ...binding,
254
+ revoked: true,
255
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
256
+ });
257
+ }
201
258
  async reconcile(remote) {
202
259
  const byId = new Map(remote.map((item) => [item.id, item]));
203
260
  requireXopcDatabase();
@@ -242,4 +299,4 @@ async function checksumFile(path) {
242
299
  return hash.digest("hex");
243
300
  }
244
301
  //#endregion
245
- export { HostedSessionShareBuilder, HostedSessionSharePublisher, HostedShareAuthorizationError, HostedShareBindingStore };
302
+ export { HostedPublicationPublisher, HostedSessionShareBuilder, HostedShareAuthorizationError, HostedShareBindingStore, HostedShareRemoteError };
@@ -0,0 +1,16 @@
1
+ import type { HostedPublicationSnapshot } from './hosted-session-share.js';
2
+ export interface HostedStaticSitePublicationSnapshot extends HostedPublicationSnapshot {
3
+ kind: 'static_site';
4
+ rootDir: string;
5
+ title: string;
6
+ fileCount: number;
7
+ totalBytes: number;
8
+ }
9
+ export declare class HostedStaticSitePublicationBuilder {
10
+ build(workspaceRoot: string, input: {
11
+ path: string;
12
+ title?: string;
13
+ description?: string;
14
+ spaFallback?: boolean;
15
+ }): Promise<HostedStaticSitePublicationSnapshot>;
16
+ }
@@ -0,0 +1,108 @@
1
+ import { isPathUnderWorkspace } from "../gateway/workspace-editor-path.js";
2
+ import { resolveMimeType } from "./share-store.js";
3
+ import { basename, dirname, extname, posix, relative, resolve } from "node:path";
4
+ import { createReadStream } from "node:fs";
5
+ import { createHash } from "node:crypto";
6
+ import { lstat, readdir, realpath, stat } from "node:fs/promises";
7
+ //#region src/share/hosted-static-site-publication.ts
8
+ const MAX_FILES = 2e3;
9
+ const MAX_FILE_BYTES = 64 * 1024 * 1024;
10
+ const MAX_TOTAL_BYTES = 512 * 1024 * 1024;
11
+ var HostedStaticSitePublicationBuilder = class {
12
+ async build(workspaceRoot, input) {
13
+ const realSource = await realpath(resolve(workspaceRoot, normalizeInputPath(input.path)));
14
+ if (!isPathUnderWorkspace(workspaceRoot, realSource)) throw new Error("Static site path is outside the workspace");
15
+ const sourceStat = await stat(realSource);
16
+ const singleHtml = sourceStat.isFile();
17
+ if (singleHtml && resolveMimeType(realSource) !== "text/html") throw new Error("Static site file must be an HTML document");
18
+ if (!singleHtml && !sourceStat.isDirectory()) throw new Error("Static site source must be an HTML file or directory");
19
+ const rootDir = singleHtml ? dirname(realSource) : realSource;
20
+ const entries = singleHtml ? [{
21
+ path: "index.html",
22
+ absolutePath: realSource
23
+ }] : (await collectFiles(rootDir)).map((path) => ({
24
+ path,
25
+ absolutePath: resolve(rootDir, path)
26
+ }));
27
+ if (!singleHtml && !entries.some((entry) => entry.path === "index.html")) throw new Error("Static site must contain index.html");
28
+ const assets = [];
29
+ const files = [];
30
+ let totalBytes = 0;
31
+ for (const entry of entries) {
32
+ const filePath = entry.path;
33
+ const absolutePath = entry.absolutePath;
34
+ const fileStat = await stat(absolutePath);
35
+ if (fileStat.size > MAX_FILE_BYTES) throw new Error(`Static site file exceeds publishing limit: ${filePath}`);
36
+ totalBytes += fileStat.size;
37
+ if (totalBytes > MAX_TOTAL_BYTES) throw new Error("Static site exceeds total publishing limit");
38
+ const id = createHash("sha256").update(filePath).digest("hex").slice(0, 40);
39
+ assets.push({
40
+ id,
41
+ path: absolutePath,
42
+ size: fileStat.size
43
+ });
44
+ files.push({
45
+ id,
46
+ path: filePath,
47
+ mimeType: resolveMimeType(filePath),
48
+ size: fileStat.size,
49
+ sha256: await sha256File(absolutePath)
50
+ });
51
+ }
52
+ const defaultTitle = singleHtml ? basename(realSource, extname(realSource)) : basename(realSource);
53
+ const title = input.title?.trim() || defaultTitle || "Published site";
54
+ return {
55
+ kind: "static_site",
56
+ rootDir,
57
+ title,
58
+ fileCount: files.length,
59
+ totalBytes,
60
+ assets,
61
+ manifest: {
62
+ schemaVersion: 1,
63
+ kind: "static_site",
64
+ title,
65
+ snapshotAt: (/* @__PURE__ */ new Date()).toISOString(),
66
+ ...input.description?.trim() ? { description: input.description.trim() } : {},
67
+ entrypoint: "index.html",
68
+ spaFallback: input.spaFallback ?? true,
69
+ files
70
+ }
71
+ };
72
+ }
73
+ };
74
+ async function collectFiles(rootDir) {
75
+ const files = [];
76
+ const visit = async (directory) => {
77
+ const entries = await readdir(directory, { withFileTypes: true });
78
+ entries.sort((left, right) => left.name.localeCompare(right.name));
79
+ for (const entry of entries) {
80
+ const absolutePath = resolve(directory, entry.name);
81
+ const details = await lstat(absolutePath);
82
+ if (details.isSymbolicLink()) throw new Error(`Static site cannot contain symbolic links: ${entry.name}`);
83
+ if (details.isDirectory()) {
84
+ await visit(absolutePath);
85
+ continue;
86
+ }
87
+ if (!details.isFile()) throw new Error(`Unsupported static site entry: ${entry.name}`);
88
+ const filePath = relative(rootDir, absolutePath).split("\\").join("/");
89
+ if (filePath.split("/").some((part) => !part || part === "." || part === "..")) throw new Error("Invalid static site path");
90
+ files.push(posix.normalize(filePath));
91
+ if (files.length > MAX_FILES) throw new Error(`Static site has more than ${MAX_FILES} files`);
92
+ }
93
+ };
94
+ await visit(rootDir);
95
+ return files;
96
+ }
97
+ function normalizeInputPath(value) {
98
+ const normalized = value.trim().replace(/\\/g, "/").replace(/^\/+/, "");
99
+ if (!normalized || normalized.includes("\0") || normalized.split("/").some((part) => part === "..")) throw new Error("Invalid static site path");
100
+ return normalized;
101
+ }
102
+ async function sha256File(filePath) {
103
+ const hash = createHash("sha256");
104
+ for await (const chunk of createReadStream(filePath)) hash.update(chunk);
105
+ return hash.digest("hex");
106
+ }
107
+ //#endregion
108
+ export { HostedStaticSitePublicationBuilder };
@@ -0,0 +1,23 @@
1
+ import { HostedPublicationPublisher, HostedShareBindingStore, type HostedShareBinding } from './hosted-session-share.js';
2
+ import { HostedStaticSitePublicationBuilder, type HostedStaticSitePublicationSnapshot } from './hosted-static-site-publication.js';
3
+ export interface PublishHostedStaticSiteInput {
4
+ workspaceRoot: string;
5
+ path: string;
6
+ title?: string;
7
+ description?: string;
8
+ spaFallback?: boolean;
9
+ ttlMs: number;
10
+ maxViews: number | null;
11
+ sessionKey?: string;
12
+ agentId?: string;
13
+ }
14
+ export interface PublishHostedStaticSiteResult {
15
+ binding: HostedShareBinding;
16
+ snapshot: HostedStaticSitePublicationSnapshot;
17
+ }
18
+ /** Build, upload, activate, and locally bind one immutable static-site snapshot. */
19
+ export declare function publishHostedStaticSite(input: PublishHostedStaticSiteInput, deps?: {
20
+ builder?: HostedStaticSitePublicationBuilder;
21
+ publisher?: HostedPublicationPublisher;
22
+ bindings?: HostedShareBindingStore;
23
+ }): Promise<PublishHostedStaticSiteResult>;
@@ -0,0 +1,53 @@
1
+ import { HostedPublicationPublisher, HostedShareBindingStore } from "./hosted-session-share.js";
2
+ import { HostedStaticSitePublicationBuilder } from "./hosted-static-site-publication.js";
3
+ //#region src/share/hosted-static-site-publish.ts
4
+ /** Build, upload, activate, and locally bind one immutable static-site snapshot. */
5
+ async function publishHostedStaticSite(input, deps = {}) {
6
+ const builder = deps.builder ?? new HostedStaticSitePublicationBuilder();
7
+ const publisher = deps.publisher ?? new HostedPublicationPublisher();
8
+ const bindings = deps.bindings ?? new HostedShareBindingStore();
9
+ const snapshot = await builder.build(input.workspaceRoot, {
10
+ path: input.path,
11
+ title: input.title,
12
+ description: input.description,
13
+ spaFallback: input.spaFallback
14
+ });
15
+ const result = await publisher.createPublication(snapshot, {
16
+ ttlMs: input.ttlMs,
17
+ maxViews: input.maxViews
18
+ });
19
+ const now = (/* @__PURE__ */ new Date()).toISOString();
20
+ const binding = {
21
+ ...result,
22
+ kind: "static_site",
23
+ source: {
24
+ kind: "static_site",
25
+ id: input.path,
26
+ version: now
27
+ },
28
+ revisionSources: { [String(result.snapshotRevision)]: {
29
+ kind: "static_site",
30
+ id: input.path,
31
+ version: now
32
+ } },
33
+ workspaceContext: {
34
+ workspaceRoot: input.workspaceRoot,
35
+ ...input.sessionKey ? { sessionKey: input.sessionKey } : {},
36
+ ...input.agentId ? { agentId: input.agentId } : {}
37
+ },
38
+ title: snapshot.title,
39
+ description: input.description?.trim() || null,
40
+ attachmentCount: snapshot.fileCount,
41
+ attachmentIds: snapshot.assets.map((asset) => asset.id),
42
+ createdAt: now,
43
+ updatedAt: now,
44
+ revoked: false
45
+ };
46
+ await bindings.upsert(binding);
47
+ return {
48
+ binding,
49
+ snapshot
50
+ };
51
+ }
52
+ //#endregion
53
+ export { publishHostedStaticSite };
@@ -65,3 +65,4 @@ export declare class NoteShareService {
65
65
  private artifactRelativePath;
66
66
  private artifactDir;
67
67
  }
68
+ export declare function projectPublicNoteMarkdown(note: Note, selected: Set<string>): string;
@@ -2,8 +2,8 @@ import { resolveStateDir } from "../config/paths-state.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
4
  import { init_paths } from "../config/paths.js";
5
- import { collectReferencedAttachmentIds } from "../notes/note-attachment-sync.js";
6
5
  import { issueShareAssetTicket, verifyShareAssetTicket } from "./share-asset-ticket.js";
6
+ import { collectReferencedAttachmentIds } from "../notes/note-attachment-sync.js";
7
7
  import { dirname, join } from "node:path";
8
8
  import { createHash, randomUUID } from "node:crypto";
9
9
  import { copyFile, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -155,7 +155,7 @@ var NoteShareService = class {
155
155
  for (const id of referenced) if (!known.has(id)) throw new Error(`Referenced attachment is missing: ${id}`);
156
156
  const selected = requestedAttachmentIds === void 0 ? [...referenced] : Array.from(new Set(requestedAttachmentIds));
157
157
  for (const id of selected) if (!referenced.has(id)) throw new Error(`Attachment is not referenced by this Note: ${id}`);
158
- const projectedMarkdown = projectPublicMarkdown(note, new Set(selected));
158
+ const projectedMarkdown = projectPublicNoteMarkdown(note, new Set(selected));
159
159
  const markdownBytes = Buffer.byteLength(projectedMarkdown, "utf8");
160
160
  if (markdownBytes > cfg.maxMarkdownBytes) throw new Error("Note Markdown exceeds sharing limit");
161
161
  if (selected.length > cfg.maxAttachmentCount) throw new Error("Note has too many attachments to share");
@@ -235,7 +235,7 @@ var NoteShareService = class {
235
235
  return join(resolveStateDir(), this.artifactRelativePath(shareId));
236
236
  }
237
237
  };
238
- function projectPublicMarkdown(note, selected) {
238
+ function projectPublicNoteMarkdown(note, selected) {
239
239
  const canonicalTarget = "xopc-attachment://notes/([^/\\s)]+)/([^\\s)]+)";
240
240
  const assertOwned = new RegExp(canonicalTarget, "gi");
241
241
  note.markdown.replace(assertOwned, (_match, rawNoteId) => {
@@ -260,4 +260,4 @@ function projectPublicMarkdown(note, selected) {
260
260
  return markdown;
261
261
  }
262
262
  //#endregion
263
- export { NoteShareService, NoteShareVersionConflictError };
263
+ export { NoteShareService, NoteShareVersionConflictError, projectPublicNoteMarkdown };
@@ -33,7 +33,7 @@ export interface ResolvedSiteShareUrl {
33
33
  }
34
34
  /**
35
35
  * Resolve the URL pair for a site share. Priority mirrors `resolveShareUrl`:
36
- * 1. FRP tunnel → wildcard subdomain on `<publicHostSuffix>`.
36
+ * 1. FRP tunnel → gateway `/site/<token>/` subpath.
37
37
  * 2. Reverse-proxy `publicUrl` → `<publicUrl>/site/<token>/` subpath.
38
38
  * 3. Direct gateway bind → `http://<host>:<port>/site/<token>/`.
39
39
  */
@@ -1,12 +1,12 @@
1
1
  import { enumerateLanGatewayCandidates } from "../gateway/host.js";
2
- import { loadTunnelState } from "../tunnel/tunnel-state.js";
2
+ import { getTunnelService } from "../tunnel/tunnel-service.js";
3
3
  //#region src/share/share-url.ts
4
4
  function resolveShareUrl(token, ctx) {
5
- const tunnelState = loadTunnelState();
5
+ const tunnelPublicUrl = activeTunnelPublicUrl();
6
6
  const { gatewayHost, gatewayPort, reverseProxyPublicUrl } = ctx;
7
7
  const path = `/s/${token}`;
8
- if (tunnelState?.publicUrl) return {
9
- shareUrl: `${tunnelState.publicUrl.replace(/\/+$/, "")}${path}`,
8
+ if (tunnelPublicUrl) return {
9
+ shareUrl: `${tunnelPublicUrl.replace(/\/+$/, "")}${path}`,
10
10
  lanUrl: buildLanUrl(gatewayHost, gatewayPort, path),
11
11
  reachability: "public",
12
12
  reachabilityHint: null
@@ -40,22 +40,23 @@ function isLoopbackHost(host) {
40
40
  return host === "127.0.0.1" || host === "localhost" || host === "::1";
41
41
  }
42
42
  function resolveReachabilityForList(ctx) {
43
- if (loadTunnelState()?.publicUrl) return "public";
43
+ if (activeTunnelPublicUrl()) return "public";
44
44
  if (ctx.reverseProxyPublicUrl?.trim()) return "public";
45
45
  if (!isLoopbackHost(ctx.gatewayHost)) return "lan";
46
46
  return "local-only";
47
47
  }
48
48
  /**
49
49
  * Resolve the URL pair for a site share. Priority mirrors `resolveShareUrl`:
50
- * 1. FRP tunnel → wildcard subdomain on `<publicHostSuffix>`.
50
+ * 1. FRP tunnel → gateway `/site/<token>/` subpath.
51
51
  * 2. Reverse-proxy `publicUrl` → `<publicUrl>/site/<token>/` subpath.
52
52
  * 3. Direct gateway bind → `http://<host>:<port>/site/<token>/`.
53
53
  */
54
54
  function resolveSiteShareUrl(ctx) {
55
- if (loadTunnelState()?.publicUrl) {
56
- const root = `https://${ctx.subdomainLabel}.${ctx.publicHostSuffix}`;
55
+ const tunnelPublicUrl = activeTunnelPublicUrl();
56
+ if (tunnelPublicUrl) {
57
+ const root = tunnelPublicUrl.replace(/\/+$/, "");
57
58
  return {
58
- shareUrl: `${root}/`,
59
+ shareUrl: `${root}/site/${ctx.token}/`,
59
60
  thumbnailUrl: `${root}/site/${ctx.token}/thumbnail`,
60
61
  reachability: "public",
61
62
  reachabilityHint: null
@@ -80,5 +81,9 @@ function resolveSiteShareUrl(ctx) {
80
81
  reachabilityHint: loopback ? "当前仅本机可访问,开启远程隧道后对外可达" : "当前局域网内可访问,开启远程隧道后对外网可达"
81
82
  };
82
83
  }
84
+ function activeTunnelPublicUrl() {
85
+ const status = getTunnelService().getStatus();
86
+ return status.state === "connected" && status.publicUrl ? status.publicUrl : null;
87
+ }
83
88
  //#endregion
84
89
  export { resolveReachabilityForList, resolveShareUrl, resolveSiteShareUrl };
@@ -12,11 +12,11 @@ import { effectiveWorkspacePathForSession } from "../../session/session-workspac
12
12
  import { ProjectService } from "../../projects/project-service.js";
13
13
  import { inferSuggestedProjectDefaultAgentId } from "../../projects/project-agent-suggestion.js";
14
14
  import "../../projects/index.js";
15
+ import { buildSessionTimeline } from "../../session/transcript-outline.js";
16
+ import { transcriptRowsToClientHistory } from "../../session/client-history.js";
15
17
  import { createCreateShareTool, isShareToolAvailable } from "../../agent/tools/create-share-tool.js";
16
18
  import { evictEmbeddedSessionRunner } from "../../agent/embedded/session-runner.js";
17
19
  import { setTuiDefaultAgentConfig } from "../../commands/agents.config.js";
18
- import { buildSessionTimeline } from "../../session/transcript-outline.js";
19
- import { transcriptRowsToClientHistory } from "../../session/client-history.js";
20
20
  import { SessionIndex } from "../../session/manager.js";
21
21
  import "../../session/index.js";
22
22
  import { parseModelRef } from "../../agent/models/selection.js";
@@ -1,5 +1,5 @@
1
- import { formatAgentRunErrorForDisplay } from "../agent/client-error-format.js";
2
1
  import { stripRuntimeContextFromUserContent } from "../session/user-message-display.js";
2
+ import { formatAgentRunErrorForDisplay } from "../agent/client-error-format.js";
3
3
  import { createAssistantMessageFromText } from "./components/assistant-message.js";
4
4
  import { markRunEvent, markRunIdleAfterCompletion } from "./tui-run-state.js";
5
5
  //#region src/tui/tui-agent-events.ts
@@ -11,17 +11,14 @@
11
11
  * shortest reliable path is to turn `/audit_repo` into the same plain-text
12
12
  * request the model already knows how to handle.
13
13
  *
14
- * Why catalog the workflow list at the TUI layer?
15
- * The catalog reads `~/.xopc/workflows/` synchronously (single `readdir`),
16
- * so the slash dispatch stays sync and the user sees no latency. The lookup
17
- * only runs for inputs that started with `/` and didn't match any built-in
18
- * or extension command, so the cost is negligible.
14
+ * The lookup only runs for inputs that started with `/` and did not match a
15
+ * built-in or extension command. A short cache keeps repeated dispatch cheap.
19
16
  *
20
17
  * Built-in TUI command names that overlap with a workflow file name keep their
21
18
  * existing TUI behaviour — the slash dispatcher matches the built-in switch
22
19
  * cases before this helper is consulted.
23
20
  */
24
- /** Reset the cache (for tests, or after a `/workflow save`). */
21
+ /** Reset the cache after workflow changes and in tests. */
25
22
  export declare function resetWorkflowSlashCache(): void;
26
23
  /**
27
24
  * Returns a rewritten user message when `name` matches a known workflow,
@@ -13,11 +13,8 @@ import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
13
13
  * shortest reliable path is to turn `/audit_repo` into the same plain-text
14
14
  * request the model already knows how to handle.
15
15
  *
16
- * Why catalog the workflow list at the TUI layer?
17
- * The catalog reads `~/.xopc/workflows/` synchronously (single `readdir`),
18
- * so the slash dispatch stays sync and the user sees no latency. The lookup
19
- * only runs for inputs that started with `/` and didn't match any built-in
20
- * or extension command, so the cost is negligible.
16
+ * The lookup only runs for inputs that started with `/` and did not match a
17
+ * built-in or extension command. A short cache keeps repeated dispatch cheap.
21
18
  *
22
19
  * Built-in TUI command names that overlap with a workflow file name keep their
23
20
  * existing TUI behaviour — the slash dispatcher matches the built-in switch
@@ -26,7 +23,7 @@ import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
26
23
  let cachedNames = null;
27
24
  let cachedAt = 0;
28
25
  const CACHE_TTL_MS = 5e3;
29
- /** Reset the cache (for tests, or after a `/workflow save`). */
26
+ /** Reset the cache after workflow changes and in tests. */
30
27
  function resetWorkflowSlashCache() {
31
28
  cachedNames = null;
32
29
  cachedAt = 0;
@@ -1,7 +1,7 @@
1
- import { loadTunnelState, resolveTunnelStatePath, saveTunnelState } from "./tunnel-state.js";
2
1
  import { TunnelBrokerClient, resolveBrokerApiBase } from "./broker-client.js";
3
2
  import { FRPC_VERSION, clearFrpcPathForProcess, ensureFrpcBinary, publishFrpcPathForProcess } from "./frpc-binary.js";
4
3
  import { TUNNEL_REGISTRATION_SECRET_REQUIRED_CODE, TunnelRegistrationSecretError, getTunnelRegistrationSecretMeta, isLocalDevelopmentTunnelBroker, isMaskedTunnelSecretPatchValue, resolveOptionalTunnelRegistrationSecret, resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret, tunnelRegistrationSecretRequiredMessage } from "./env.js";
4
+ import { loadTunnelState, resolveTunnelStatePath, saveTunnelState } from "./tunnel-state.js";
5
5
  import { logTunnelAudit } from "./tunnel-audit.js";
6
6
  import { TunnelService, getTunnelService, hashGatewayToken } from "./tunnel-service.js";
7
7
  import { CURRENT_TUNNEL_CONSENT_VERSION, TUNNEL_CONSENT_REQUIRED_CODE, TUNNEL_RISK_SUMMARY_LINES, TunnelConsentError, assertTunnelMayStart, getTunnelConsentState, hasValidTunnelConsent } from "./consent.js";
@@ -1,13 +1,13 @@
1
1
  import { PACKAGE_VERSION, init_package_version } from "../package-version.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
- import { clearTunnelState, loadTunnelState, saveTunnelState, updateTunnelState } from "./tunnel-state.js";
5
4
  import { TunnelBrokerClient, resolveBrokerApiBase } from "./broker-client.js";
6
5
  import { clearFrpcPathForProcess, ensureFrpcBinary, publishFrpcPathForProcess } from "./frpc-binary.js";
7
6
  import { writeFrpcConfig } from "./frpc-config.js";
8
7
  import { spawnFrpcProcess } from "./frpc-process.js";
9
8
  import { TunnelRegistrationSecretError } from "./env.js";
10
9
  import { canResumePersistedTunnel, persistedFromRegistration, registrationFromPersisted } from "./tunnel-persist.js";
10
+ import { clearTunnelState, loadTunnelState, saveTunnelState, updateTunnelState } from "./tunnel-state.js";
11
11
  import { logTunnelAudit } from "./tunnel-audit.js";
12
12
  import { createHash } from "node:crypto";
13
13
  import { EventEmitter } from "node:events";
@@ -0,0 +1,17 @@
1
+ import { type UserProfilePatch } from './profile.js';
2
+ export interface UserModelBootstrapInput {
3
+ profile: UserProfilePatch;
4
+ responsibilities?: string[];
5
+ goals?: string[];
6
+ communicationPreferences?: string[];
7
+ boundaries?: string[];
8
+ relationships?: string[];
9
+ }
10
+ export declare function bootstrapUserModel(input: UserModelBootstrapInput, now?: number): {
11
+ profile: Partial<Record<import("./profile.js").UserProfileField, string>>;
12
+ created: {
13
+ assertions: number;
14
+ goals: number;
15
+ rules: number;
16
+ };
17
+ };