@geminixiang/mikan 1.0.0-beta.37 → 1.0.0-beta.39

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 (201) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +1 -1
  3. package/dist/adapter.js +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +3 -6
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +16 -39
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/github/bot.d.ts +2 -0
  10. package/dist/adapters/github/bot.d.ts.map +1 -1
  11. package/dist/adapters/github/bot.js +15 -11
  12. package/dist/adapters/github/bot.js.map +1 -1
  13. package/dist/adapters/github/github-ops.d.ts +1 -1
  14. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  15. package/dist/adapters/github/github-ops.js +2 -1
  16. package/dist/adapters/github/github-ops.js.map +1 -1
  17. package/dist/adapters/github/repo.d.ts +2 -1
  18. package/dist/adapters/github/repo.d.ts.map +1 -1
  19. package/dist/adapters/github/repo.js +2 -3
  20. package/dist/adapters/github/repo.js.map +1 -1
  21. package/dist/adapters/github/types.d.ts +1 -1
  22. package/dist/adapters/github/types.d.ts.map +1 -1
  23. package/dist/adapters/github/types.js.map +1 -1
  24. package/dist/adapters/intake.js +1 -1
  25. package/dist/adapters/intake.js.map +1 -1
  26. package/dist/adapters/shared.d.ts +17 -5
  27. package/dist/adapters/shared.d.ts.map +1 -1
  28. package/dist/adapters/shared.js +44 -8
  29. package/dist/adapters/shared.js.map +1 -1
  30. package/dist/adapters/slack/blocks.d.ts +14 -0
  31. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  32. package/dist/adapters/slack/blocks.js +34 -0
  33. package/dist/adapters/slack/blocks.js.map +1 -1
  34. package/dist/adapters/slack/bot.d.ts +19 -6
  35. package/dist/adapters/slack/bot.d.ts.map +1 -1
  36. package/dist/adapters/slack/bot.js +88 -21
  37. package/dist/adapters/slack/bot.js.map +1 -1
  38. package/dist/adapters/slack/types.d.ts +1 -1
  39. package/dist/adapters/slack/types.js.map +1 -1
  40. package/dist/adapters/telegram/bot.d.ts +5 -6
  41. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  42. package/dist/adapters/telegram/bot.js +29 -51
  43. package/dist/adapters/telegram/bot.js.map +1 -1
  44. package/dist/adapters/types.d.ts +19 -1
  45. package/dist/adapters/types.d.ts.map +1 -1
  46. package/dist/adapters/types.js.map +1 -1
  47. package/dist/agent.d.ts +0 -1
  48. package/dist/agent.d.ts.map +1 -1
  49. package/dist/agent.js +79 -101
  50. package/dist/agent.js.map +1 -1
  51. package/dist/cli/ext-dev.d.ts.map +1 -1
  52. package/dist/cli/ext-dev.js +8 -8
  53. package/dist/cli/ext-dev.js.map +1 -1
  54. package/dist/cli/ext.js +3 -3
  55. package/dist/cli/ext.js.map +1 -1
  56. package/dist/cli/office.js +2 -2
  57. package/dist/cli/office.js.map +1 -1
  58. package/dist/commands/auto-reply.d.ts.map +1 -1
  59. package/dist/commands/auto-reply.js +1 -2
  60. package/dist/commands/auto-reply.js.map +1 -1
  61. package/dist/commands/login.js +1 -1
  62. package/dist/commands/login.js.map +1 -1
  63. package/dist/commands/manifest.d.ts.map +1 -1
  64. package/dist/commands/manifest.js +3 -1
  65. package/dist/commands/manifest.js.map +1 -1
  66. package/dist/commands/model.d.ts.map +1 -1
  67. package/dist/commands/model.js +3 -7
  68. package/dist/commands/model.js.map +1 -1
  69. package/dist/commands/sandbox.d.ts.map +1 -1
  70. package/dist/commands/sandbox.js +7 -7
  71. package/dist/commands/sandbox.js.map +1 -1
  72. package/dist/commands/session-view.d.ts.map +1 -1
  73. package/dist/commands/session-view.js +1 -2
  74. package/dist/commands/session-view.js.map +1 -1
  75. package/dist/commands/types.d.ts +2 -1
  76. package/dist/commands/types.d.ts.map +1 -1
  77. package/dist/commands/types.js.map +1 -1
  78. package/dist/config.d.ts +10 -18
  79. package/dist/config.d.ts.map +1 -1
  80. package/dist/config.js +16 -15
  81. package/dist/config.js.map +1 -1
  82. package/dist/execution-resolver.d.ts +4 -6
  83. package/dist/execution-resolver.d.ts.map +1 -1
  84. package/dist/execution-resolver.js +10 -19
  85. package/dist/execution-resolver.js.map +1 -1
  86. package/dist/harness/extensions/loader.js +1 -1
  87. package/dist/harness/extensions/loader.js.map +1 -1
  88. package/dist/harness/skills.d.ts +8 -0
  89. package/dist/harness/skills.d.ts.map +1 -1
  90. package/dist/harness/skills.js +46 -4
  91. package/dist/harness/skills.js.map +1 -1
  92. package/dist/harness/types.d.ts +2 -0
  93. package/dist/harness/types.d.ts.map +1 -1
  94. package/dist/harness/types.js.map +1 -1
  95. package/dist/index.d.ts +2 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +1 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/main.js +16 -16
  100. package/dist/main.js.map +1 -1
  101. package/dist/{office-address.d.ts → office/address.d.ts} +13 -14
  102. package/dist/office/address.d.ts.map +1 -0
  103. package/dist/{office-address.js → office/address.js} +13 -18
  104. package/dist/office/address.js.map +1 -0
  105. package/dist/office/index.d.ts +11 -0
  106. package/dist/office/index.d.ts.map +1 -0
  107. package/dist/office/index.js +11 -0
  108. package/dist/office/index.js.map +1 -0
  109. package/dist/office/layout.d.ts +20 -0
  110. package/dist/office/layout.d.ts.map +1 -0
  111. package/dist/office/layout.js +88 -0
  112. package/dist/office/layout.js.map +1 -0
  113. package/dist/{office-migration.d.ts → office/migration.d.ts} +3 -3
  114. package/dist/office/migration.d.ts.map +1 -0
  115. package/dist/{office-migration.js → office/migration.js} +8 -12
  116. package/dist/office/migration.js.map +1 -0
  117. package/dist/{office-registry.d.ts → office/registry.d.ts} +18 -24
  118. package/dist/office/registry.d.ts.map +1 -0
  119. package/dist/{office-registry.js → office/registry.js} +22 -83
  120. package/dist/office/registry.js.map +1 -0
  121. package/dist/office/types.d.ts +71 -0
  122. package/dist/office/types.d.ts.map +1 -0
  123. package/dist/office/types.js +2 -0
  124. package/dist/office/types.js.map +1 -0
  125. package/dist/packages/admin.js +5 -5
  126. package/dist/packages/admin.js.map +1 -1
  127. package/dist/packages/inspect.d.ts.map +1 -1
  128. package/dist/packages/inspect.js +3 -8
  129. package/dist/packages/inspect.js.map +1 -1
  130. package/dist/packages/materialize.js +1 -1
  131. package/dist/packages/materialize.js.map +1 -1
  132. package/dist/packages/resolve.js +5 -8
  133. package/dist/packages/resolve.js.map +1 -1
  134. package/dist/packages/types.d.ts +2 -5
  135. package/dist/packages/types.d.ts.map +1 -1
  136. package/dist/packages/types.js.map +1 -1
  137. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  138. package/dist/runtime/conversation-runtime.js +13 -15
  139. package/dist/runtime/conversation-runtime.js.map +1 -1
  140. package/dist/runtime/session-lifecycle.js +1 -1
  141. package/dist/runtime/session-lifecycle.js.map +1 -1
  142. package/dist/runtime/types.d.ts +3 -2
  143. package/dist/runtime/types.d.ts.map +1 -1
  144. package/dist/runtime/types.js.map +1 -1
  145. package/dist/sandbox/identity.js +1 -1
  146. package/dist/sandbox/identity.js.map +1 -1
  147. package/dist/settings-mutation.d.ts +3 -2
  148. package/dist/settings-mutation.d.ts.map +1 -1
  149. package/dist/settings-mutation.js +6 -7
  150. package/dist/settings-mutation.js.map +1 -1
  151. package/dist/tools/generate-image.d.ts +8 -2
  152. package/dist/tools/generate-image.d.ts.map +1 -1
  153. package/dist/tools/generate-image.js +5 -3
  154. package/dist/tools/generate-image.js.map +1 -1
  155. package/dist/tools/index.d.ts +5 -0
  156. package/dist/tools/index.d.ts.map +1 -1
  157. package/dist/tools/index.js +3 -5
  158. package/dist/tools/index.js.map +1 -1
  159. package/dist/trigger.d.ts +1 -1
  160. package/dist/trigger.d.ts.map +1 -1
  161. package/dist/trigger.js +5 -10
  162. package/dist/trigger.js.map +1 -1
  163. package/dist/types.d.ts +3 -22
  164. package/dist/types.d.ts.map +1 -1
  165. package/dist/types.js.map +1 -1
  166. package/dist/vault/index.js +1 -1
  167. package/dist/vault/index.js.map +1 -1
  168. package/dist/vault/injection.d.ts +3 -1
  169. package/dist/vault/injection.d.ts.map +1 -1
  170. package/dist/vault/injection.js +2 -2
  171. package/dist/vault/injection.js.map +1 -1
  172. package/dist/web/admin/portal.d.ts.map +1 -1
  173. package/dist/web/admin/portal.js +67 -80
  174. package/dist/web/admin/portal.js.map +1 -1
  175. package/dist/web/admin/types.d.ts +2 -1
  176. package/dist/web/admin/types.d.ts.map +1 -1
  177. package/dist/web/admin/types.js.map +1 -1
  178. package/dist/web/server.d.ts +1 -1
  179. package/dist/web/server.d.ts.map +1 -1
  180. package/dist/web/server.js +3 -3
  181. package/dist/web/server.js.map +1 -1
  182. package/dist/web/session-view/portal.js +1 -1
  183. package/dist/web/session-view/portal.js.map +1 -1
  184. package/dist/workspace-projection/index.d.ts +2 -4
  185. package/dist/workspace-projection/index.d.ts.map +1 -1
  186. package/dist/workspace-projection/index.js +21 -56
  187. package/dist/workspace-projection/index.js.map +1 -1
  188. package/dist/workspace-projection/types.d.ts +0 -2
  189. package/dist/workspace-projection/types.d.ts.map +1 -1
  190. package/dist/workspace-projection/types.js.map +1 -1
  191. package/package.json +41 -16
  192. package/dist/office-address.d.ts.map +0 -1
  193. package/dist/office-address.js.map +0 -1
  194. package/dist/office-migration.d.ts.map +0 -1
  195. package/dist/office-migration.js.map +0 -1
  196. package/dist/office-registry.d.ts.map +0 -1
  197. package/dist/office-registry.js.map +0 -1
  198. package/dist/store.d.ts +0 -51
  199. package/dist/store.d.ts.map +0 -1
  200. package/dist/store.js +0 -185
  201. package/dist/store.js.map +0 -1
@@ -1,10 +1,12 @@
1
1
  import type { SandboxConfig, SandboxCredentialCapabilities } from "../sandbox/types.js";
2
+ import type { OfficeAddress } from "../types.js";
2
3
  import type { ResolvedVault, VaultInjection } from "./types.js";
3
4
  export type { VaultInjection } from "./types.js";
4
5
  export declare function resolveVaultInjection(options: {
5
6
  vault: ResolvedVault | undefined;
6
7
  capabilities: SandboxCredentialCapabilities;
7
8
  sandboxType: SandboxConfig["type"];
8
- conversationId: string;
9
+ /** Diagnostic identity for error reports only; no injection decision reads it. */
10
+ address: OfficeAddress;
9
11
  }): VaultInjection;
10
12
  //# sourceMappingURL=injection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"injection.d.ts","sourceRoot":"","sources":["../../src/vault/injection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAsB,cAAc,EAAE,MAAM,YAAY,CAAC;AAEpF,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,YAAY,EAAE,6BAA6B,CAAC;IAC5C,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,cAAc,CA6BjB"}
1
+ {"version":3,"file":"injection.d.ts","sourceRoot":"","sources":["../../src/vault/injection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAsB,cAAc,EAAE,MAAM,YAAY,CAAC;AAEpF,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,YAAY,EAAE,6BAA6B,CAAC;IAC5C,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,kFAAkF;IAClF,OAAO,EAAE,aAAa,CAAC;CACxB,GAAG,cAAc,CA6BjB"}
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "fs";
2
2
  import { reportUserFacingError } from "../observability/sentry.js";
3
3
  export function resolveVaultInjection(options) {
4
- const { vault, capabilities, sandboxType, conversationId } = options;
4
+ const { vault, capabilities, sandboxType, address } = options;
5
5
  if (vault && vault.mounts.length > 0 && !capabilities.fileMounts) {
6
6
  throw new Error(`Sandbox type "${sandboxType}" does not support vault file mounts`);
7
7
  }
@@ -15,7 +15,7 @@ export function resolveVaultInjection(options) {
15
15
  severity: "warning",
16
16
  context: {
17
17
  sandboxType,
18
- conversationId,
18
+ conversationId: address.conversationId,
19
19
  target: mount.target,
20
20
  hasVault: Boolean(vault),
21
21
  },
@@ -1 +1 @@
1
- {"version":3,"file":"injection.js","sourceRoot":"","sources":["../../src/vault/injection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAMnE,MAAM,UAAU,qBAAqB,CAAC,OAKrC;IACC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IACrE,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,iBAAiB,WAAW,sCAAsC,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,MAAM,GAAyB,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,qBAAqB,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,EAAE;gBAChE,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,iBAAiB;gBAC1B,SAAS,EAAE,gBAAgB;gBAC3B,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE;oBACP,WAAW;oBACX,cAAc;oBACd,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC;iBACzB;aACF,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,GAAG,GACP,YAAY,CAAC,GAAG,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IACzF,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC","sourcesContent":["import { existsSync } from \"fs\";\nimport { reportUserFacingError } from \"../observability/sentry.js\";\nimport type { SandboxConfig, SandboxCredentialCapabilities } from \"../sandbox/types.js\";\nimport type { ResolvedVault, ResolvedVaultMount, VaultInjection } from \"./types.js\";\n\nexport type { VaultInjection } from \"./types.js\";\n\nexport function resolveVaultInjection(options: {\n vault: ResolvedVault | undefined;\n capabilities: SandboxCredentialCapabilities;\n sandboxType: SandboxConfig[\"type\"];\n conversationId: string;\n}): VaultInjection {\n const { vault, capabilities, sandboxType, conversationId } = options;\n if (vault && vault.mounts.length > 0 && !capabilities.fileMounts) {\n throw new Error(`Sandbox type \"${sandboxType}\" does not support vault file mounts`);\n }\n\n const mounts: ResolvedVaultMount[] = [];\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType,\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mounts.push({ source: mount.source, target: mount.target });\n }\n\n const env =\n capabilities.env && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return { ...(env ? { env } : {}), mounts };\n}\n"]}
1
+ {"version":3,"file":"injection.js","sourceRoot":"","sources":["../../src/vault/injection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAOnE,MAAM,UAAU,qBAAqB,CAAC,OAMrC;IACC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC9D,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,iBAAiB,WAAW,sCAAsC,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,MAAM,GAAyB,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,qBAAqB,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,EAAE;gBAChE,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,iBAAiB;gBAC1B,SAAS,EAAE,gBAAgB;gBAC3B,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE;oBACP,WAAW;oBACX,cAAc,EAAE,OAAO,CAAC,cAAc;oBACtC,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC;iBACzB;aACF,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,GAAG,GACP,YAAY,CAAC,GAAG,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IACzF,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC","sourcesContent":["import { existsSync } from \"fs\";\nimport { reportUserFacingError } from \"../observability/sentry.js\";\nimport type { SandboxConfig, SandboxCredentialCapabilities } from \"../sandbox/types.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport type { ResolvedVault, ResolvedVaultMount, VaultInjection } from \"./types.js\";\n\nexport type { VaultInjection } from \"./types.js\";\n\nexport function resolveVaultInjection(options: {\n vault: ResolvedVault | undefined;\n capabilities: SandboxCredentialCapabilities;\n sandboxType: SandboxConfig[\"type\"];\n /** Diagnostic identity for error reports only; no injection decision reads it. */\n address: OfficeAddress;\n}): VaultInjection {\n const { vault, capabilities, sandboxType, address } = options;\n if (vault && vault.mounts.length > 0 && !capabilities.fileMounts) {\n throw new Error(`Sandbox type \"${sandboxType}\" does not support vault file mounts`);\n }\n\n const mounts: ResolvedVaultMount[] = [];\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType,\n conversationId: address.conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mounts.push({ source: mount.source, target: mount.target });\n }\n\n const env =\n capabilities.env && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return { ...(env ? { env } : {}), mounts };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/web/admin/portal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAG5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAkCvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAWtD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAmJD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,aAAa,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,UAAU,GAChB,sBAAsB,CAexB;AA6iCD,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,cAAc,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAwBD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE,CAuB/F;AA6JD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiB9E"}
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/web/admin/portal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAG5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAiCvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAWtD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAmJD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,aAAa,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,UAAU,GAChB,sBAAsB,CAexB;AAuiCD,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,cAAc,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAwBD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE,CAuB/F;AAmJD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiB9E"}
@@ -3,7 +3,6 @@ import { basename, join, resolve as pathResolve, sep as pathSep } from "path";
3
3
  import { MikanModels, parseFrontmatter, SessionStore } from "../../harness/index.js";
4
4
  import { loadConversationAutoReplyConfig, loadConversationWorkspaceOverride, loadGlobalSettings, resolveConversationSettings, saveConversationAutoReplyConfig, } from "../../config.js";
5
5
  import { applyConversationSettings, applyConversationWorkspacePolicy, applyGlobalSettings, applyGlobalWorkspacePolicy, } from "../../settings-mutation.js";
6
- import { effectiveStateDir } from "../../cli/arg-grammar.js";
7
6
  import { addPackage, inspectConversationPackages, refreshPackage, removePackage, } from "../../packages/index.js";
8
7
  import { escapeHtml } from "../../utils/html.js";
9
8
  import { readRawBody } from "../../utils/http-body.js";
@@ -14,9 +13,7 @@ import { credentialAuthorizationKey } from "../../sandbox/identity.js";
14
13
  import { resolveWorkspaceProjection } from "../../workspace-projection/index.js";
15
14
  import { sharedVaultKey } from "../../vault/index.js";
16
15
  import { modelKey, resolveAdminModelAccessStatuses } from "./provider-models.js";
17
- import { sameOffice } from "../../office-address.js";
18
- import { assertPlatformName, conversationOfficeDir, createOfficeAddress, } from "../../office-address.js";
19
- import { listRegisteredOffices } from "../../office-registry.js";
16
+ import { assertPlatformName, createOfficeAddress, listRegisteredOffices, sameOffice, } from "../../office/index.js";
20
17
  // ── Handler ────────────────────────────────────────────────────────────────────
21
18
  export async function handleAdminRequest(req, res, url, services) {
22
19
  if (!url.pathname.startsWith("/admin"))
@@ -200,12 +197,12 @@ function resolveTargetConversation(body, token) {
200
197
  const platform = typeof body.platform === "string" ? body.platform.trim() : "";
201
198
  return resolveConversationScope(requested, platform, token);
202
199
  }
203
- function requireAdminWorkingDir(res, services) {
204
- if (!services.workingDir) {
200
+ function requireAdminWorkspace(res, services) {
201
+ if (!services.workspace) {
205
202
  jsonRes(res, 503, { error: "Working directory not available" });
206
203
  return null;
207
204
  }
208
- return services.workingDir;
205
+ return services.workspace;
209
206
  }
210
207
  // ── API handlers ───────────────────────────────────────────────────────────────
211
208
  function serveMe(res, token) {
@@ -223,14 +220,14 @@ function serveMe(res, token) {
223
220
  * mapping — instead of scanning the workspace. Offices whose directory
224
221
  * disappeared are filtered out.
225
222
  */
226
- function listAdminOffices(workingDir) {
227
- return listRegisteredOffices()
228
- .filter((office) => existsSync(conversationOfficeDir(workingDir, office)))
223
+ function listAdminOffices(workspace) {
224
+ return listRegisteredOffices(workspace.stateDir)
225
+ .filter((office) => existsSync(workspace.office(office).dir))
229
226
  .map((office) => createOfficeAddress(office.platform, office.conversationId))
230
227
  .toSorted((a, b) => a.platform.localeCompare(b.platform) || a.conversationId.localeCompare(b.conversationId));
231
228
  }
232
- function conversationLastActivity(workingDir, office) {
233
- const dir = conversationOfficeDir(workingDir, office);
229
+ function conversationLastActivity(workspace, office) {
230
+ const dir = workspace.office(office).dir;
234
231
  if (!existsSync(dir))
235
232
  return null;
236
233
  let latest = 0;
@@ -271,31 +268,31 @@ function conversationDisplayLabel(services, office) {
271
268
  return `${office.platform}:${office.conversationId}`;
272
269
  }
273
270
  function serveConversationsList(res, services) {
274
- const workingDir = requireAdminWorkingDir(res, services);
275
- if (!workingDir)
271
+ const workspace = requireAdminWorkspace(res, services);
272
+ if (!workspace)
276
273
  return;
277
274
  const running = services.runtime?.getRunningSessions() ?? [];
278
- const conversations = listAdminOffices(workingDir).map((office) => ({
275
+ const conversations = listAdminOffices(workspace).map((office) => ({
279
276
  platform: office.platform,
280
277
  conversationId: office.conversationId,
281
278
  label: conversationDisplayLabel(services, office),
282
279
  running: running.some((session) => sameOffice(session.address, office)),
283
- lastActivityAt: conversationLastActivity(workingDir, office),
280
+ lastActivityAt: conversationLastActivity(workspace, office),
284
281
  }));
285
282
  jsonRes(res, 200, { conversations });
286
283
  }
287
284
  function serveSessionUsage(res, services) {
288
- const workingDir = requireAdminWorkingDir(res, services);
289
- if (!workingDir)
285
+ const workspace = requireAdminWorkspace(res, services);
286
+ if (!workspace)
290
287
  return;
291
- const rows = listAdminOffices(workingDir)
292
- .flatMap((office) => listConversationSessionUsage(workingDir, office, conversationDisplayLabel(services, office)))
288
+ const rows = listAdminOffices(workspace)
289
+ .flatMap((office) => listConversationSessionUsage(workspace, office, conversationDisplayLabel(services, office)))
293
290
  .toSorted((a, b) => b.total - a.total)
294
291
  .slice(0, 20);
295
292
  jsonRes(res, 200, { sessions: rows });
296
293
  }
297
- function listConversationSessionUsage(workingDir, office, label) {
298
- const sessionDir = join(conversationOfficeDir(workingDir, office), "sessions");
294
+ function listConversationSessionUsage(workspace, office, label) {
295
+ const sessionDir = workspace.office(office).sessionsDir;
299
296
  try {
300
297
  return readdirSync(sessionDir, { withFileTypes: true })
301
298
  .filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl"))
@@ -359,12 +356,12 @@ function emptyBucket(date) {
359
356
  }
360
357
  /** Per-conversation daily token usage over the last N days (N clamped to 1..7). */
361
358
  function serveConversationUsage(res, url, services) {
362
- const workingDir = requireAdminWorkingDir(res, services);
363
- if (!workingDir)
359
+ const workspace = requireAdminWorkspace(res, services);
360
+ if (!workspace)
364
361
  return;
365
362
  const conversationId = (url.searchParams.get("conversationId") ?? "").trim();
366
363
  const platformParam = (url.searchParams.get("platform") ?? "").trim();
367
- const office = listAdminOffices(workingDir).find((candidate) => candidate.conversationId === conversationId &&
364
+ const office = listAdminOffices(workspace).find((candidate) => candidate.conversationId === conversationId &&
368
365
  (!platformParam || candidate.platform === platformParam));
369
366
  if (!office) {
370
367
  jsonRes(res, 400, { error: "Unknown conversationId" });
@@ -385,7 +382,7 @@ function serveConversationUsage(res, url, services) {
385
382
  const cutoff = new Date(today);
386
383
  cutoff.setDate(today.getDate() - (days - 1));
387
384
  const flags = { hasOlder: false };
388
- const sessionDir = join(conversationOfficeDir(workingDir, office), "sessions");
385
+ const sessionDir = workspace.office(office).sessionsDir;
389
386
  try {
390
387
  for (const entry of readdirSync(sessionDir, { withFileTypes: true })) {
391
388
  if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
@@ -461,8 +458,8 @@ function accumulateSessionUsageByDay(sessionFile, cutoff, buckets, flags) {
461
458
  }
462
459
  }
463
460
  function serveConversationState(res, url, services, token) {
464
- const workingDir = requireAdminWorkingDir(res, services);
465
- if (!workingDir)
461
+ const workspace = requireAdminWorkspace(res, services);
462
+ if (!workspace)
466
463
  return;
467
464
  const scope = resolveConversationFromQuery(url, token);
468
465
  if (scope.error) {
@@ -470,15 +467,12 @@ function serveConversationState(res, url, services, token) {
470
467
  return;
471
468
  }
472
469
  const conversationId = scope.conversationId;
473
- const dir = conversationOfficeDir(workingDir, scope.address);
470
+ const office = workspace.office(scope.address);
474
471
  const globalConfig = loadGlobalSettings();
475
- const conversationConfig = resolveConversationSettings({
476
- address: scope.address,
477
- conversationDir: dir,
478
- });
479
- const conversationWorkspace = resolveWorkspaceProjection(workingDir, scope.address);
472
+ const conversationConfig = resolveConversationSettings(office);
473
+ const conversationWorkspace = resolveWorkspaceProjection(office);
480
474
  const globalWorkspaceSettings = globalConfig.sandbox?.workspace;
481
- const autoReply = loadConversationAutoReplyConfig(dir);
475
+ const autoReply = loadConversationAutoReplyConfig(office.dir);
482
476
  jsonRes(res, 200, {
483
477
  conversationId,
484
478
  provider: conversationConfig.provider,
@@ -489,7 +483,7 @@ function serveConversationState(res, url, services, token) {
489
483
  globalThinkingLevel: globalConfig.thinkingLevel,
490
484
  workspaceDoorPolicy: conversationWorkspace.doorPolicy,
491
485
  workspaceLayout: conversationWorkspace.layout,
492
- workspaceOverride: doorPolicyChoiceKey(loadConversationWorkspaceOverride({ address: scope.address, conversationDir: dir })),
486
+ workspaceOverride: doorPolicyChoiceKey(loadConversationWorkspaceOverride(office)),
493
487
  globalWorkspaceDoorPolicy: globalWorkspaceSettings?.doorPolicy ?? "isolated",
494
488
  globalWorkspaceLayout: globalWorkspaceSettings?.layout ?? "conversation",
495
489
  autoReplyEnabled: autoReply.enabled,
@@ -560,11 +554,11 @@ function serveConversationModelUpdate(res, body, services, token) {
560
554
  jsonRes(res, 403, { error: scope.error });
561
555
  return;
562
556
  }
563
- const workingDir = requireAdminWorkingDir(res, services);
564
- if (!workingDir)
557
+ const workspace = requireAdminWorkspace(res, services);
558
+ if (!workspace)
565
559
  return;
566
560
  try {
567
- const result = applyConversationSettings(services.runtime, workingDir, scope.address, {
561
+ const result = applyConversationSettings(services.runtime, workspace.office(scope.address), {
568
562
  provider,
569
563
  model,
570
564
  ...(thinkingLevel ? { thinkingLevel } : {}),
@@ -616,11 +610,11 @@ function serveConversationSandboxUpdate(res, body, services, token) {
616
610
  jsonRes(res, 403, { error: scope.error });
617
611
  return;
618
612
  }
619
- const workingDir = requireAdminWorkingDir(res, services);
620
- if (!workingDir)
613
+ const workspace = requireAdminWorkspace(res, services);
614
+ if (!workspace)
621
615
  return;
622
616
  try {
623
- const result = applyConversationWorkspacePolicy(services.runtime, workingDir, scope.address, parsed.choice);
617
+ const result = applyConversationWorkspacePolicy(services.runtime, workspace.office(scope.address), parsed.choice);
624
618
  if (!result.ok) {
625
619
  jsonRes(res, 409, { error: "Conversation is busy; retry when the current run finishes" });
626
620
  return;
@@ -658,11 +652,11 @@ function serveConversationSlackUpdate(res, body, services, token) {
658
652
  jsonRes(res, 403, { error: scope.error });
659
653
  return;
660
654
  }
661
- const workingDir = requireAdminWorkingDir(res, services);
662
- if (!workingDir)
655
+ const workspace = requireAdminWorkspace(res, services);
656
+ if (!workspace)
663
657
  return;
664
658
  try {
665
- applyConversationSettings(services.runtime, workingDir, scope.address, {
659
+ applyConversationSettings(services.runtime, workspace.office(scope.address), {
666
660
  slack: { replyMode },
667
661
  });
668
662
  jsonRes(res, 200, { ok: true });
@@ -684,10 +678,10 @@ function serveConversationAutoReplyUpdate(res, body, services, token) {
684
678
  jsonRes(res, 403, { error: scope.error });
685
679
  return;
686
680
  }
687
- const workingDir = requireAdminWorkingDir(res, services);
688
- if (!workingDir)
681
+ const workspace = requireAdminWorkspace(res, services);
682
+ if (!workspace)
689
683
  return;
690
- const dir = conversationOfficeDir(workingDir, scope.address);
684
+ const dir = workspace.office(scope.address).dir;
691
685
  try {
692
686
  const existing = loadConversationAutoReplyConfig(dir);
693
687
  saveConversationAutoReplyConfig(dir, {
@@ -706,8 +700,8 @@ function serveConversationSessionLink(res, body, services, token) {
706
700
  jsonRes(res, 403, { error: scope.error });
707
701
  return;
708
702
  }
709
- const workingDir = requireAdminWorkingDir(res, services);
710
- if (!workingDir)
703
+ const workspace = requireAdminWorkspace(res, services);
704
+ if (!workspace)
711
705
  return;
712
706
  if (!services.sessionViewTokenStore) {
713
707
  jsonRes(res, 503, { error: "Session view token store not available" });
@@ -719,7 +713,7 @@ function serveConversationSessionLink(res, body, services, token) {
719
713
  });
720
714
  return;
721
715
  }
722
- const sessionFile = resolveExistingSessionFile(conversationOfficeDir(workingDir, scope.address), scope.conversationId);
716
+ const sessionFile = resolveExistingSessionFile(workspace.office(scope.address).dir, scope.conversationId);
723
717
  if (!sessionFile) {
724
718
  jsonRes(res, 404, { error: "No session file found for this conversation" });
725
719
  return;
@@ -957,10 +951,10 @@ function serveWorkspaceTree(res, url, services, token) {
957
951
  jsonRes(res, 403, { error: scope.error });
958
952
  return;
959
953
  }
960
- const workingDir = requireAdminWorkingDir(res, services);
961
- if (!workingDir)
954
+ const workspace = requireAdminWorkspace(res, services);
955
+ if (!workspace)
962
956
  return;
963
- const convDir = conversationOfficeDir(workingDir, scope.address);
957
+ const convDir = workspace.office(scope.address).dir;
964
958
  if (!existsSync(convDir)) {
965
959
  jsonRes(res, 200, { conversationId: scope.conversationId, tree: null });
966
960
  return;
@@ -1051,8 +1045,8 @@ function serveWorkspaceFile(res, url, services, token) {
1051
1045
  jsonRes(res, 403, { error: scope.error });
1052
1046
  return;
1053
1047
  }
1054
- const workingDir = requireAdminWorkingDir(res, services);
1055
- if (!workingDir)
1048
+ const workspace = requireAdminWorkspace(res, services);
1049
+ if (!workspace)
1056
1050
  return;
1057
1051
  const requestedPath = (url.searchParams.get("path") ?? "").trim();
1058
1052
  if (!requestedPath) {
@@ -1063,7 +1057,7 @@ function serveWorkspaceFile(res, url, services, token) {
1063
1057
  jsonRes(res, 403, { error: "Workspace path is not exposed" });
1064
1058
  return;
1065
1059
  }
1066
- const convDir = conversationOfficeDir(workingDir, scope.address);
1060
+ const convDir = workspace.office(scope.address).dir;
1067
1061
  const safe = safeJoinUnderRoot(convDir, requestedPath);
1068
1062
  if (safe.error) {
1069
1063
  jsonRes(res, 400, { error: safe.error });
@@ -1130,14 +1124,12 @@ async function servePackagesList(res, url, services, token) {
1130
1124
  jsonRes(res, 403, { error: scope.error });
1131
1125
  return;
1132
1126
  }
1133
- const workingDir = requireAdminWorkingDir(res, services);
1134
- if (!workingDir)
1127
+ const workspace = requireAdminWorkspace(res, services);
1128
+ if (!workspace)
1135
1129
  return;
1136
1130
  try {
1137
1131
  const inventory = await inspectConversationPackages({
1138
- address: scope.address,
1139
- stateDir: effectiveStateDir(),
1140
- conversationDir: conversationOfficeDir(workingDir, scope.address),
1132
+ office: workspace.office(scope.address),
1141
1133
  });
1142
1134
  jsonRes(res, 200, { conversationId: scope.conversationId, ...inventory });
1143
1135
  }
@@ -1167,14 +1159,11 @@ function servePackageMutation(res, body, services, token) {
1167
1159
  jsonRes(res, 403, { error: scope.error });
1168
1160
  return;
1169
1161
  }
1170
- const workingDir = requireAdminWorkingDir(res, services);
1171
- if (!workingDir)
1162
+ const workspace = requireAdminWorkspace(res, services);
1163
+ if (!workspace)
1172
1164
  return;
1173
1165
  const context = {
1174
- address: scope.address,
1175
- stateDir: effectiveStateDir(),
1176
- conversationDir: conversationOfficeDir(workingDir, scope.address),
1177
- workingDir,
1166
+ office: workspace.office(scope.address),
1178
1167
  runtime: services.runtime,
1179
1168
  };
1180
1169
  try {
@@ -1203,11 +1192,11 @@ function serveSkillsList(res, url, services, token) {
1203
1192
  jsonRes(res, 403, { error: scope.error });
1204
1193
  return;
1205
1194
  }
1206
- const workingDir = requireAdminWorkingDir(res, services);
1207
- if (!workingDir)
1195
+ const workspace = requireAdminWorkspace(res, services);
1196
+ if (!workspace)
1208
1197
  return;
1209
- const global = readSkillsFromDir(join(workingDir, "skills"), "global");
1210
- const conversation = readSkillsFromDir(join(conversationOfficeDir(workingDir, scope.address), "skills"), "conversation");
1198
+ const global = readSkillsFromDir(workspace.skillsDir, "global");
1199
+ const conversation = readSkillsFromDir(workspace.office(scope.address).skillsDir, "conversation");
1211
1200
  jsonRes(res, 200, {
1212
1201
  conversationId: scope.conversationId,
1213
1202
  skills: [...global, ...conversation],
@@ -1219,8 +1208,8 @@ function serveSkillFile(res, url, services, token) {
1219
1208
  jsonRes(res, 403, { error: scope.error });
1220
1209
  return;
1221
1210
  }
1222
- const workingDir = requireAdminWorkingDir(res, services);
1223
- if (!workingDir)
1211
+ const workspace = requireAdminWorkspace(res, services);
1212
+ if (!workspace)
1224
1213
  return;
1225
1214
  const source = (url.searchParams.get("source") ?? "").trim();
1226
1215
  const directory = (url.searchParams.get("directory") ?? "").trim();
@@ -1235,9 +1224,7 @@ function serveSkillFile(res, url, services, token) {
1235
1224
  jsonRes(res, 400, { error: "Invalid skill directory" });
1236
1225
  return;
1237
1226
  }
1238
- const skillsRoot = source === "global"
1239
- ? join(workingDir, "skills")
1240
- : join(conversationOfficeDir(workingDir, scope.address), "skills");
1227
+ const skillsRoot = source === "global" ? workspace.skillsDir : workspace.office(scope.address).skillsDir;
1241
1228
  const safe = safeJoinUnderRoot(skillsRoot, join(directory, "SKILL.md"));
1242
1229
  if (safe.error) {
1243
1230
  jsonRes(res, 400, { error: safe.error });
@@ -1297,15 +1284,15 @@ async function serveConversationEventsList(res, url, services, token) {
1297
1284
  jsonRes(res, 200, { conversationId: scope.conversationId, events });
1298
1285
  }
1299
1286
  function serveEventsFile(res, url, services) {
1300
- const workingDir = requireAdminWorkingDir(res, services);
1301
- if (!workingDir)
1287
+ const workspace = requireAdminWorkspace(res, services);
1288
+ if (!workspace)
1302
1289
  return;
1303
1290
  const name = (url.searchParams.get("name") ?? "").trim();
1304
1291
  if (!name || name.includes("/") || name.includes("\\") || name.includes("..")) {
1305
1292
  jsonRes(res, 400, { error: "Invalid name" });
1306
1293
  return;
1307
1294
  }
1308
- const filePath = join(workingDir, "events", name);
1295
+ const filePath = join(workspace.eventsDir, name);
1309
1296
  let stats;
1310
1297
  try {
1311
1298
  stats = statSync(filePath);