@xopcai/xopc 0.0.240 → 0.0.242

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 (158) 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-DLfkwJzZ.js → activity-store-MU5XrVv8.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DNqb8LGQ.js → agent-avatar-dicebear-B_Wc0wuL.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Cf7U2aUi.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-Ce9oOnwE.js +1 -0
  7. package/dist/gateway/static/root/assets/{api-IUm57Zse.js → api-DLyc8BQp.js} +1 -1
  8. package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +1 -0
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-4-eqCZG_.js → app-management-settings-panel-CACOOS-a.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-Dus5TPxo.js → appearance-settings-DB5gEQhN.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-BaTFOCmR.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-Bha1jUhj.js → archive-plugin-BOx0EJZs.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-CX2u191M.js → attachment-load-CYnYIyLr.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-page-BizspokZ.js → automations-page-ChTflpmA.js} +1 -1
  15. package/dist/gateway/static/root/assets/automations-workspace-DK6EreCr.js +6 -0
  16. package/dist/gateway/static/root/assets/{binary-plugins-CSn8R1EL.js → binary-plugins-BjbLfNwG.js} +1 -1
  17. package/dist/gateway/static/root/assets/{block-editor-D5MN7UPI.js → block-editor-DgAs5aJc.js} +46 -46
  18. package/dist/gateway/static/root/assets/browser-settings-page-CHStw5UW.js +8 -0
  19. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CeG3fWhC.js → browser-workflow-inputs-DGQxD0vD.js} +1 -1
  20. package/dist/gateway/static/root/assets/{browser-workflows-page-oqmPd1KI.js → browser-workflows-page-B9gfdd7L.js} +2 -2
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel-JGH6Kfkr.js +7 -0
  22. package/dist/gateway/static/root/assets/channels-settings-YkUaaWkY.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-CwUSKmeY.js → channels-status-swr-TkU42f-W.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-C0m-ie_q.js → chat-terminal-dock-CWMPcnoN.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-BI0FG3gA.js +2 -0
  26. package/dist/gateway/static/root/assets/{cron-expression-DJOvtnKf.js → cron-expression-3h3rR0cf.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-B06ZCEsb.js → date-picker-Bz1sLBEx.js} +1 -1
  28. package/dist/gateway/static/root/assets/dependency-picker-p9DWR8uU.js +1 -0
  29. package/dist/gateway/static/root/assets/{desktop-pet-INH03b4z.js → desktop-pet-D1TDB_gR.js} +1 -1
  30. package/dist/gateway/static/root/assets/desktop-pet-settings-DWPZpoB7.js +1 -0
  31. package/dist/gateway/static/root/assets/{extension-debug-page-BcEHXLQ2.js → extension-debug-page-BrRbK2rJ.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-CWefEHKN.js → extension-page-CD65czfS.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-CjBTLU5X.js → extension-settings-page-BRDDKhpi.js} +1 -1
  34. package/dist/gateway/static/root/assets/folder-open-CyzJ19I9.js +1 -0
  35. package/dist/gateway/static/root/assets/{gateway-config-api-4GYzRHAt.js → gateway-config-api-CjbBsr5M.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-swr-DfMY-MLf.js → gateway-config-swr-HT7sLeO9.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-settings-C8MQeYbR.js → gateway-settings-BQjmfYD4.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-startup-retry-S6aB0hVI.js → gateway-startup-retry-iBCtaAuT.js} +1 -1
  39. package/dist/gateway/static/root/assets/heartbeat-settings-BzZxLgrw.js +1 -0
  40. package/dist/gateway/static/root/assets/home-page--9fKq0mL.js +1 -0
  41. package/dist/gateway/static/root/assets/{image-generation-api-DOX5uq-R.js → image-generation-api-dj9TNEn2.js} +1 -1
  42. package/dist/gateway/static/root/assets/index-D499B1qS.css +2 -0
  43. package/dist/gateway/static/root/assets/index-J3FsIvTs.js +70 -0
  44. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-xvS2czSF.js → keyboard-shortcuts-settings-BEnuEPD3.js} +1 -1
  45. package/dist/gateway/static/root/assets/link-2-D_ZKYUW7.js +1 -0
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-FqG00zS1.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page-BAYQxS0S.js → local-apps-page-DXQtppWq.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-XDFAPNNu.js → locale-store-DVzTJSj2.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-c6CfZ8PA.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-DYmKy_2v.js → management-settings-DIpBMWrA.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-Cr32dNv1.js → markdown-split-BFHyGwNF.js} +1 -1
  52. package/dist/gateway/static/root/assets/{markdown-view-v-O3cOpk.js → markdown-view-DR3yVwtV.js} +1 -1
  53. package/dist/gateway/static/root/assets/{media-plugins-KPSjs3vW.js → media-plugins-BjjMxC5_.js} +1 -1
  54. package/dist/gateway/static/root/assets/message-square-plus-XP0tGdlV.js +1 -0
  55. package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +3 -0
  56. package/dist/gateway/static/root/assets/minimize-2-DtOGrlpo.js +1 -0
  57. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-pWsC7jcc.js → mobile-pairing-wizard-CHnXZTwb.js} +1 -1
  58. package/dist/gateway/static/root/assets/models-hub-cache-DiXjKuuY.js +1 -0
  59. package/dist/gateway/static/root/assets/{notes-page-DBBnJrFf.js → notes-page-BbvtelJa.js} +1 -1
  60. package/dist/gateway/static/root/assets/notes-workbench-DIR37b-K.js +4 -0
  61. package/dist/gateway/static/root/assets/{oauth-api-B_pcOUfT.js → oauth-api-BB-VYJ5j.js} +1 -1
  62. package/dist/gateway/static/root/assets/pencil-DmIY3Oa-.js +1 -0
  63. package/dist/gateway/static/root/assets/{product-open-page-B8cjLdm4.js → product-open-page-CRm9Q66h.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-DHiLTiRW.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-God7NCcI.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-DeVvBsl4.js → registry-api-DXsR8oGN.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-YpF0-mx2.js +1 -0
  68. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-DoEfLjPB.js +5 -0
  69. package/dist/gateway/static/root/assets/{schema-form-CW7qifxi.js → schema-form-BsqpbBDv.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-CP8O1TxR.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-DzdbK3j9.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-form-section-OMPX3Svb.js → settings-form-section-DjWzRk4z.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-page-CDKXJ12S.js → settings-page-CE7ZcCTK.js} +1 -1
  74. package/dist/gateway/static/root/assets/setup-status-panel-CGlne9i0.js +1 -0
  75. package/dist/gateway/static/root/assets/share-preview-page-Bn0qMX8V.js +2 -0
  76. package/dist/gateway/static/root/assets/shares-settings-B7NeVl4g.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-DDTmi4a7.js +1 -0
  78. package/dist/gateway/static/root/assets/{skills-page-DAAlmTSh.js → skills-page-dRkeYh5P.js} +1 -1
  79. package/dist/gateway/static/root/assets/{skills-page.utils-CiMRNDFM.js → skills-page.utils--q8p7MAn.js} +1 -1
  80. package/dist/gateway/static/root/assets/{system-settings-panel-Bq7niN-G.js → system-settings-panel-C0ZCuCM4.js} +1 -1
  81. package/dist/gateway/static/root/assets/task-detail-page-yiMzii2b.js +1 -0
  82. package/dist/gateway/static/root/assets/{theme-store-5-XHH7F0.js → theme-store-Cth-eChE.js} +1 -1
  83. package/dist/gateway/static/root/assets/tunnel-api-CC3jOB4n.js +1 -0
  84. package/dist/gateway/static/root/assets/{use-autosave-CkwILwYg.js → use-autosave-PSV89QuQ.js} +1 -1
  85. package/dist/gateway/static/root/assets/user-context-page-Vtwg7fQc.js +1 -0
  86. package/dist/gateway/static/root/assets/{voice-api-key-field-BG-kpmoU.js → voice-api-key-field-DXWdJ8cR.js} +1 -1
  87. package/dist/gateway/static/root/assets/{voice-config-api-Bk_bVeGX.js → voice-config-api-BDoeXgww.js} +1 -1
  88. package/dist/gateway/static/root/assets/{work-discovery-overlay-BOH2utuu.js → work-discovery-overlay-BV_Jj5iD.js} +1 -1
  89. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DNHbWGPq.js +3 -0
  90. package/dist/gateway/static/root/assets/workflows-page-BkFIbMrz.js +5 -0
  91. package/dist/gateway/static/root/index.html +18 -13
  92. package/dist/package.js +1 -1
  93. package/dist/src/agent/agent-manager.js +1 -0
  94. package/dist/src/agent/skills/installer.d.ts +1 -0
  95. package/dist/src/agent/skills/installer.js +9 -6
  96. package/dist/src/agent/tools/factory.d.ts +2 -0
  97. package/dist/src/agent/tools/factory.js +5 -1
  98. package/dist/src/config/schema.js +5 -3
  99. package/dist/src/extensions/install.js +1 -1
  100. package/dist/src/gateway/hono/routes/media.js +5 -14
  101. package/dist/src/gateway/hono/routes/runtime-tools.js +7 -1
  102. package/dist/src/gateway/hono/routes/shares.js +36 -8
  103. package/dist/src/gateway/media-access.d.ts +6 -0
  104. package/dist/src/gateway/media-access.js +19 -0
  105. package/dist/src/runtime-tools/archive.js +17 -3
  106. package/dist/src/runtime-tools/command.d.ts +1 -0
  107. package/dist/src/runtime-tools/command.js +29 -8
  108. package/dist/src/runtime-tools/environment.d.ts +1 -0
  109. package/dist/src/runtime-tools/environment.js +11 -16
  110. package/dist/src/runtime-tools/install-lock.d.ts +1 -1
  111. package/dist/src/runtime-tools/install-lock.js +34 -21
  112. package/dist/src/runtime-tools/manager.d.ts +1 -1
  113. package/dist/src/runtime-tools/manager.js +99 -64
  114. package/dist/src/runtime-tools/manifest-store.d.ts +2 -0
  115. package/dist/src/runtime-tools/manifest-store.js +29 -8
  116. package/dist/src/runtime-tools/paths.d.ts +2 -1
  117. package/dist/src/runtime-tools/paths.js +19 -8
  118. package/dist/src/runtime-tools/probe.d.ts +2 -0
  119. package/dist/src/runtime-tools/probe.js +13 -1
  120. package/dist/src/runtime-tools/prune.js +21 -7
  121. package/dist/src/share/share-store.js +3 -2
  122. package/dist/src/share/share-types.d.ts +2 -0
  123. package/package.json +3 -3
  124. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CDZBY8QF.js +0 -1
  125. package/dist/gateway/static/root/assets/agents-BpWZKFrQ.js +0 -1
  126. package/dist/gateway/static/root/assets/apps-page-DPacUrzS.js +0 -1
  127. package/dist/gateway/static/root/assets/automations-workspace-CudEcxwk.js +0 -6
  128. package/dist/gateway/static/root/assets/browser-settings-page-wKhgAIwg.js +0 -8
  129. package/dist/gateway/static/root/assets/capabilities-settings-panel-Dj_x6HTl.js +0 -7
  130. package/dist/gateway/static/root/assets/channels-settings-BpsJRsjG.js +0 -1
  131. package/dist/gateway/static/root/assets/connectors-page-B-Gdzfob.js +0 -2
  132. package/dist/gateway/static/root/assets/dependency-picker-BU8dmVCo.js +0 -1
  133. package/dist/gateway/static/root/assets/desktop-pet-settings-CzAGt3M_.js +0 -1
  134. package/dist/gateway/static/root/assets/heartbeat-settings-C_8vY0Eu.js +0 -1
  135. package/dist/gateway/static/root/assets/home-page-D1SM6UXd.js +0 -1
  136. package/dist/gateway/static/root/assets/index-BN4XPtJY.js +0 -70
  137. package/dist/gateway/static/root/assets/index-CCBexxKW.css +0 -2
  138. package/dist/gateway/static/root/assets/local-app-workbench-page-DAh4_rTj.js +0 -2
  139. package/dist/gateway/static/root/assets/logs-page-COS-Yb-N.js +0 -2
  140. package/dist/gateway/static/root/assets/messages-B1HDp_j8.js +0 -3
  141. package/dist/gateway/static/root/assets/models-hub-cache-Bngs8o1m.js +0 -1
  142. package/dist/gateway/static/root/assets/notes-api-BMhFpRmW.js +0 -1
  143. package/dist/gateway/static/root/assets/notes-workbench-CSAzL8Tf.js +0 -4
  144. package/dist/gateway/static/root/assets/project-detail-page-DHIJpssV.js +0 -1
  145. package/dist/gateway/static/root/assets/projects-page-BDoAwszu.js +0 -1
  146. package/dist/gateway/static/root/assets/remote-access-hub-DPi4SQVV.js +0 -1
  147. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-DFTHpNg6.js +0 -5
  148. package/dist/gateway/static/root/assets/sessions-page-VNrtwwV5.js +0 -1
  149. package/dist/gateway/static/root/assets/settings-advanced-gate-CUcTHMDp.js +0 -1
  150. package/dist/gateway/static/root/assets/setup-status-panel-Dnvfemeb.js +0 -1
  151. package/dist/gateway/static/root/assets/share-preview-page-BoSIu0WX.js +0 -2
  152. package/dist/gateway/static/root/assets/shares-settings-C87QeRxC.js +0 -1
  153. package/dist/gateway/static/root/assets/skill-reload-api-rY5ujr0j.js +0 -1
  154. package/dist/gateway/static/root/assets/task-detail-page-JtztFp2Y.js +0 -1
  155. package/dist/gateway/static/root/assets/tunnel-api-eBX1eb2v.js +0 -1
  156. package/dist/gateway/static/root/assets/user-context-page-CMH2GOGL.js +0 -1
  157. package/dist/gateway/static/root/assets/workflow-run-setup-panel-B92rr2yf.js +0 -3
  158. package/dist/gateway/static/root/assets/workflows-page-DXvdYJff.js +0 -5
@@ -8,8 +8,8 @@ import { collectExtensionPackageDependencyIssues } from "./package-contract.js";
8
8
  import { dirname, isAbsolute, join, resolve, sep } from "path";
9
9
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
10
10
  import { execFileSync } from "node:child_process";
11
- import AdmZip from "adm-zip";
12
11
  import semver from "semver";
12
+ import AdmZip from "adm-zip";
13
13
  import { tmpdir } from "os";
14
14
  //#region src/extensions/install.ts
15
15
  /**
@@ -1,12 +1,8 @@
1
- import { TaskRepository } from "../../../tasks/task-repository.js";
2
- import { parseMediaUri } from "../../../media/uri.js";
3
1
  import { mimeTypeFromMediaPath, saveMediaBuffer } from "../../../media/store.js";
4
2
  import { readMediaReference } from "../../../media/media-reference.js";
5
- import { TaskContextRepository } from "../../../tasks/task-context-repository.js";
6
- import { pendingTranscriptReferencesMediaUri } from "../../../agent/inbound/attachment-pipeline.js";
7
3
  import { MAX_WEBCHAT_ATTACHMENT_FILE_BYTES } from "../../chat-limits.js";
8
- import { messagesReferenceMediaUri } from "../../../media/session-references.js";
9
4
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
5
+ import { resolveScopedMediaReference } from "../../media-access.js";
10
6
  //#region src/gateway/hono/routes/media.ts
11
7
  const log = createGatewayRouteLogger("Media");
12
8
  function parseByteRange(header, size) {
@@ -30,7 +26,6 @@ function parseByteRange(header, size) {
30
26
  };
31
27
  }
32
28
  function registerMediaRoutes(authenticated, deps) {
33
- const tasks = new TaskRepository();
34
29
  authenticated.post("/api/media", deps.strictRateLimitMiddleware, async (c) => {
35
30
  const file = (await c.req.formData().catch(() => null))?.get("file");
36
31
  if (!(file instanceof Blob)) return c.json({
@@ -75,14 +70,10 @@ function registerMediaRoutes(authenticated, deps) {
75
70
  error: { message: "Missing media scope" }
76
71
  }, 400);
77
72
  try {
78
- const parsed = parseMediaUri(uriRaw.trim());
79
- const sessionReferencesUri = sessionKey ? messagesReferenceMediaUri(await deps.service.sessionIndexInstance.loadMessages(sessionKey), parsed.uri) || pendingTranscriptReferencesMediaUri(sessionKey, parsed.uri) : false;
80
- const taskReferencesUri = taskId && tasks.get(taskId) ? new TaskContextRepository().list(taskId).some((edge) => edge.targetKind === "file" && edge.targetId === parsed.uri) : false;
81
- if (!sessionReferencesUri && !taskReferencesUri) return c.json({
82
- ok: false,
83
- error: { message: "Not found" }
84
- }, 404);
85
- const { buffer, path } = await readMediaReference(parsed.uri);
73
+ const { buffer, path } = await readMediaReference((await resolveScopedMediaReference(deps.service, uriRaw.trim(), {
74
+ sessionKey,
75
+ taskId
76
+ })).uri);
86
77
  const contentType = mimeTypeFromMediaPath(path);
87
78
  const range = parseByteRange(c.req.header("Range"), buffer.byteLength);
88
79
  const commonHeaders = {
@@ -1,5 +1,6 @@
1
1
  import { init_paths_state, resolveStateDir } from "../../../config/paths-state.js";
2
2
  import { RuntimeToolsConfigSchema, init_schema } from "../../../config/schema.js";
3
+ import { normalizeRuntimeVersionRequest } from "../../../runtime-tools/probe.js";
3
4
  import { ManagedRuntimeManager } from "../../../runtime-tools/manager.js";
4
5
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
5
6
  import { pruneRuntimeTools } from "../../../runtime-tools/prune.js";
@@ -82,6 +83,11 @@ function registerRuntimeToolsRoutes(authenticated, deps) {
82
83
  }, 400);
83
84
  const body = await readJson(c);
84
85
  const version = typeof body.version === "string" && body.version.trim() ? body.version.trim() : void 0;
86
+ if (version && !normalizeRuntimeVersionRequest(version)) return c.json({
87
+ ok: false,
88
+ error: "invalid-version",
89
+ message: "Invalid runtime version"
90
+ }, 400);
85
91
  return streamSSE(c, async (stream) => {
86
92
  const manager = runtimeManager(service.currentConfig);
87
93
  let writes = Promise.resolve();
@@ -97,7 +103,7 @@ function registerRuntimeToolsRoutes(authenticated, deps) {
97
103
  };
98
104
  manager.on("progress", onProgress);
99
105
  try {
100
- const resolved = action === "repair" ? await manager.repair(runtime) : await manager.install(runtime, version);
106
+ const resolved = action === "repair" ? await manager.repair(runtime, version) : await manager.install(runtime, version);
101
107
  await writes;
102
108
  await stream.writeSSE({
103
109
  event: "result",
@@ -16,11 +16,13 @@ import { getGatewayFileSpaceService } from "../../file-space-service.js";
16
16
  import { getClientIpFromHeaders } from "../../security/loopback.js";
17
17
  import { SHARED_HTML_CSP } from "../../security/csp.js";
18
18
  import { renderFolderLandingPage, renderShareExpiredPage, renderShareLandingPage, renderSnapshotShareLandingPage } from "../../../share/share-landing.js";
19
+ import { resolveScopedMediaReference } from "../../media-access.js";
19
20
  import { SessionShareService, SessionShareSnapshotConflictError } from "../../../share/session-share-service.js";
20
21
  import { HostedSessionShareBuilder, HostedSessionSharePublisher, HostedShareAuthorizationError, HostedShareBindingStore } from "../../../share/hosted-session-share.js";
21
22
  import { NoteShareService } from "../../../share/note-share-service.js";
22
23
  import { consumeSharePublicLimit } from "../../../share/share-rate-limit.js";
23
24
  import { createZipStream, planDirectoryFiles } from "../../../share/share-zip.js";
25
+ import { basename, dirname } from "node:path";
24
26
  import { createReadStream } from "node:fs";
25
27
  import { createHash } from "node:crypto";
26
28
  import { stat } from "node:fs/promises";
@@ -819,18 +821,43 @@ function registerShareRoutes(authenticated, deps) {
819
821
  error: { message: "Invalid JSON" }
820
822
  }, 400);
821
823
  }
822
- const path = typeof body.path === "string" ? body.path.trim() : "";
823
- if (!path) return c.json({
824
+ let path = typeof body.path === "string" ? body.path.trim() : "";
825
+ const fileId = typeof body.fileId === "string" ? body.fileId.trim() : "";
826
+ const uri = typeof body.uri === "string" ? body.uri.trim() : "";
827
+ if ([
828
+ path,
829
+ fileId,
830
+ uri
831
+ ].filter(Boolean).length !== 1) return c.json({
824
832
  ok: false,
825
- error: { message: "Missing path" }
833
+ error: { message: "Provide exactly one of path, fileId or uri" }
826
834
  }, 400);
827
835
  const sessionKey = typeof body.sessionKey === "string" ? body.sessionKey.trim() : void 0;
828
836
  const agentId = typeof body.agentId === "string" ? body.agentId.trim() : void 0;
829
- const workspaceRoot = await resolveWorkspaceRootForShare(service, sessionKey, agentId);
830
- if (!workspaceRoot) return c.json({
831
- ok: false,
832
- error: { message: "Workspace not configured" }
833
- }, 400);
837
+ const taskId = typeof body.taskId === "string" ? body.taskId.trim() : void 0;
838
+ const fileName = typeof body.fileName === "string" ? basename(body.fileName.trim().replace(/\\/g, "/")) : void 0;
839
+ let workspaceRoot;
840
+ try {
841
+ if (fileId) {
842
+ const target = await getGatewayFileSpaceService(service).resource(fileId);
843
+ workspaceRoot = target.space.root;
844
+ path = target.resource.relativePath || ".";
845
+ } else if (uri) {
846
+ const media = await resolveScopedMediaReference(service, uri, {
847
+ sessionKey,
848
+ taskId
849
+ });
850
+ workspaceRoot = dirname(media.path);
851
+ path = basename(media.path);
852
+ } else workspaceRoot = await resolveWorkspaceRootForShare(service, sessionKey, agentId);
853
+ if (!workspaceRoot) throw new Error("Workspace not configured");
854
+ } catch (err) {
855
+ const message = err instanceof Error ? err.message : String(err);
856
+ return c.json({
857
+ ok: false,
858
+ error: { message }
859
+ }, err instanceof FileServiceError ? err.status : 400);
860
+ }
834
861
  const ttlMs = typeof body.ttlMs === "number" ? body.ttlMs : void 0;
835
862
  const maxViews = body.maxViews === null ? null : typeof body.maxViews === "number" ? body.maxViews : void 0;
836
863
  const description = typeof body.description === "string" ? body.description.trim() || void 0 : void 0;
@@ -844,6 +871,7 @@ function registerShareRoutes(authenticated, deps) {
844
871
  store.updateConfig(resolveShareConfig(service));
845
872
  const record = await store.create({
846
873
  path,
874
+ fileName,
847
875
  ttlMs,
848
876
  maxViews,
849
877
  description,
@@ -0,0 +1,6 @@
1
+ import type { GatewayService } from './service.js';
2
+ /** Resolve media only when the supplied session or task references it. */
3
+ export declare function resolveScopedMediaReference(service: GatewayService, uri: string, scope: {
4
+ sessionKey?: string;
5
+ taskId?: string;
6
+ }): Promise<import("../media/media-reference.js").ResolvedMediaReference>;
@@ -0,0 +1,19 @@
1
+ import { TaskRepository } from "../tasks/task-repository.js";
2
+ import { FileServiceError } from "../files/file-service.js";
3
+ import { resolveMediaReference } from "../media/media-reference.js";
4
+ import { TaskContextRepository } from "../tasks/task-context-repository.js";
5
+ import { pendingTranscriptReferencesMediaUri } from "../agent/inbound/attachment-pipeline.js";
6
+ import { messagesReferenceMediaUri } from "../media/session-references.js";
7
+ //#region src/gateway/media-access.ts
8
+ /** Resolve media only when the supplied session or task references it. */
9
+ async function resolveScopedMediaReference(service, uri, scope) {
10
+ const { sessionKey, taskId } = scope;
11
+ if (!sessionKey && !taskId) throw new FileServiceError(400, "Missing media scope");
12
+ const media = await resolveMediaReference(uri);
13
+ const sessionReferencesUri = sessionKey ? messagesReferenceMediaUri(await service.sessionIndexInstance.loadMessages(sessionKey), media.uri) || pendingTranscriptReferencesMediaUri(sessionKey, media.uri) : false;
14
+ const taskReferencesUri = taskId && new TaskRepository().get(taskId) ? new TaskContextRepository().list(taskId).some((edge) => edge.targetKind === "file" && edge.targetId === media.uri) : false;
15
+ if (!sessionReferencesUri && !taskReferencesUri) throw new FileServiceError(404, "Not found");
16
+ return media;
17
+ }
18
+ //#endregion
19
+ export { resolveScopedMediaReference };
@@ -5,12 +5,15 @@ import { lstat, mkdir, readdir, readlink, rename, rm, stat } from "node:fs/promi
5
5
  import AdmZip from "adm-zip";
6
6
  //#region src/runtime-tools/archive.ts
7
7
  const MAX_ARCHIVE_ENTRIES = 5e4;
8
+ const MAX_TAR_OUTPUT_BYTES = 16 * 1024 * 1024;
9
+ const MAX_EXTRACTED_BYTES = 2 * 1024 * 1024 * 1024;
8
10
  function validateMemberPath(memberPath) {
9
11
  const portablePath = memberPath.replaceAll("\\", "/");
10
12
  const normalized = posix.normalize(portablePath);
11
13
  if (!memberPath || isAbsolute(memberPath) || portablePath.startsWith("/") || normalized === ".." || normalized.startsWith("../")) throw new Error(`Unsafe archive member: ${memberPath}`);
12
14
  }
13
15
  async function validateExtractedTree(root, current = root) {
16
+ let totalBytes = 0;
14
17
  for (const entry of await readdir(current)) {
15
18
  const entryPath = join(current, entry);
16
19
  const details = await lstat(entryPath);
@@ -19,8 +22,10 @@ async function validateExtractedTree(root, current = root) {
19
22
  if (relativeTarget.split(/[\\/]/)[0] === ".." || isAbsolute(relativeTarget)) throw new Error(`Archive symlink escapes extraction root: ${entryPath}`);
20
23
  continue;
21
24
  }
22
- if (details.isDirectory()) await validateExtractedTree(root, entryPath);
25
+ totalBytes += details.isDirectory() ? await validateExtractedTree(root, entryPath) : details.size;
26
+ if (totalBytes > MAX_EXTRACTED_BYTES) throw new Error("Extracted archive exceeds size limit");
23
27
  }
28
+ return totalBytes;
24
29
  }
25
30
  async function runTar(args) {
26
31
  return await new Promise((resolvePromise, reject) => {
@@ -30,11 +35,19 @@ async function runTar(args) {
30
35
  shell: false,
31
36
  windowsHide: true
32
37
  });
38
+ const append = (current, chunk) => {
39
+ if (Buffer.byteLength(current) + chunk.byteLength > MAX_TAR_OUTPUT_BYTES) {
40
+ child.kill("SIGKILL");
41
+ reject(/* @__PURE__ */ new Error("tar output exceeds size limit"));
42
+ return current;
43
+ }
44
+ return current + chunk.toString();
45
+ };
33
46
  child.stdout?.on("data", (chunk) => {
34
- stdout += chunk.toString();
47
+ stdout = append(stdout, chunk);
35
48
  });
36
49
  child.stderr?.on("data", (chunk) => {
37
- stderr += chunk.toString();
50
+ stderr = append(stderr, chunk);
38
51
  });
39
52
  child.once("error", reject);
40
53
  child.once("close", (code) => {
@@ -47,6 +60,7 @@ async function extractZip(archivePath, destination) {
47
60
  const zip = new AdmZip(archivePath);
48
61
  const entries = zip.getEntries();
49
62
  if (entries.length > MAX_ARCHIVE_ENTRIES) throw new Error("Archive contains too many entries");
63
+ if (entries.reduce((total, entry) => total + entry.header.size, 0) > MAX_EXTRACTED_BYTES) throw new Error("Extracted archive exceeds size limit");
50
64
  for (const entry of entries) validateMemberPath(entry.entryName);
51
65
  zip.extractAllTo(destination, true, false);
52
66
  }
@@ -5,6 +5,7 @@ export interface RuntimeCommandResult {
5
5
  exitCode: number | null;
6
6
  timedOut: boolean;
7
7
  aborted: boolean;
8
+ outputTruncated: boolean;
8
9
  }
9
10
  export declare function runRuntimeCommand(params: {
10
11
  command: string;
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  //#region src/runtime-tools/command.ts
3
3
  const DEFAULT_COMMAND_TIMEOUT_MS = 5e3;
4
+ const MAX_COMMAND_OUTPUT_BYTES = 1024 * 1024;
4
5
  async function runRuntimeCommand(params) {
5
6
  return await new Promise((resolve) => {
6
7
  let stdout = "";
@@ -8,7 +9,10 @@ async function runRuntimeCommand(params) {
8
9
  let settled = false;
9
10
  let timedOut = false;
10
11
  let aborted = false;
12
+ let outputTruncated = false;
13
+ let timeout;
11
14
  const child = spawn(params.command, params.args, {
15
+ detached: process.platform !== "win32",
12
16
  env: params.env,
13
17
  shell: false,
14
18
  windowsHide: process.platform === "win32",
@@ -18,36 +22,53 @@ async function runRuntimeCommand(params) {
18
22
  "pipe"
19
23
  ]
20
24
  });
25
+ const killChild = () => {
26
+ if (process.platform !== "win32" && child.pid) try {
27
+ process.kill(-child.pid, "SIGKILL");
28
+ return;
29
+ } catch {}
30
+ child.kill("SIGKILL");
31
+ };
21
32
  const finish = (exitCode) => {
22
33
  if (settled) return;
23
34
  settled = true;
24
- clearTimeout(timeout);
35
+ if (timeout) clearTimeout(timeout);
25
36
  params.signal?.removeEventListener("abort", abort);
26
37
  resolve({
27
- ok: exitCode === 0 && !timedOut && !aborted,
38
+ ok: exitCode === 0 && !timedOut && !aborted && !outputTruncated,
28
39
  stdout: stdout.trim(),
29
40
  stderr: stderr.trim(),
30
41
  exitCode,
31
42
  timedOut,
32
- aborted
43
+ aborted,
44
+ outputTruncated
33
45
  });
34
46
  };
35
47
  const abort = () => {
36
48
  aborted = true;
37
- child.kill("SIGKILL");
49
+ killChild();
38
50
  finish(null);
39
51
  };
52
+ const appendOutput = (current, chunk) => {
53
+ const remaining = MAX_COMMAND_OUTPUT_BYTES - Buffer.byteLength(current);
54
+ if (remaining <= 0 || chunk.byteLength > remaining) {
55
+ outputTruncated = true;
56
+ killChild();
57
+ return remaining > 0 ? current + chunk.subarray(0, remaining).toString() : current;
58
+ }
59
+ return current + chunk.toString();
60
+ };
40
61
  child.stdout?.on("data", (chunk) => {
41
- stdout += chunk.toString();
62
+ stdout = appendOutput(stdout, chunk);
42
63
  });
43
64
  child.stderr?.on("data", (chunk) => {
44
- stderr += chunk.toString();
65
+ stderr = appendOutput(stderr, chunk);
45
66
  });
46
67
  child.once("error", () => finish(null));
47
68
  child.once("close", finish);
48
- const timeout = setTimeout(() => {
69
+ timeout = setTimeout(() => {
49
70
  timedOut = true;
50
- child.kill("SIGKILL");
71
+ killChild();
51
72
  finish(null);
52
73
  }, params.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);
53
74
  timeout.unref();
@@ -6,6 +6,7 @@ export interface RuntimeEnvironmentOptions {
6
6
  baseEnv: Record<string, string>;
7
7
  runtimes?: RuntimeKind[];
8
8
  extraBinDirs?: string[];
9
+ skillEnvironmentIds?: string[];
9
10
  }
10
11
  export interface RuntimeEnvironmentResult {
11
12
  env: Record<string, string>;
@@ -1,7 +1,7 @@
1
- import { applyPathPrepend } from "../infra/path-prepend.js";
1
+ import { applyPathPrepend, findPathKey, normalizePathPrepend } from "../infra/path-prepend.js";
2
2
  import { ManagedRuntimeManager } from "./manager.js";
3
- import { dirname, join } from "node:path";
4
- import { access, readdir } from "node:fs/promises";
3
+ import { delimiter, dirname, join } from "node:path";
4
+ import { access } from "node:fs/promises";
5
5
  //#region src/runtime-tools/environment.ts
6
6
  const POLLUTING_ENV_KEYS = [
7
7
  "NODE_OPTIONS",
@@ -19,14 +19,8 @@ const POLLUTING_ENV_KEYS = [
19
19
  "UV_CACHE_DIR",
20
20
  "UV_PYTHON_INSTALL_MIRROR"
21
21
  ];
22
- async function skillEnvironmentBinDirs(stateDir) {
22
+ async function skillEnvironmentBinDirs(stateDir, environmentIds) {
23
23
  const root = join(stateDir, "tools", "environments", "skills");
24
- let environmentIds;
25
- try {
26
- environmentIds = await readdir(root);
27
- } catch {
28
- return [];
29
- }
30
24
  const candidates = environmentIds.flatMap((id) => [join(root, id, "bin"), join(root, id, "node_modules", ".bin")]);
31
25
  return (await Promise.all(candidates.map(async (candidate) => {
32
26
  try {
@@ -37,6 +31,10 @@ async function skillEnvironmentBinDirs(stateDir) {
37
31
  }
38
32
  }))).filter((candidate) => candidate !== null);
39
33
  }
34
+ function appendPathEntries(env, entries) {
35
+ const pathKey = findPathKey(env);
36
+ env[pathKey] = normalizePathPrepend([...(env[pathKey] ?? "").split(delimiter).filter(Boolean), ...entries]).join(delimiter);
37
+ }
40
38
  async function buildRuntimeEnvironment(options) {
41
39
  const env = { ...options.baseEnv };
42
40
  for (const key of POLLUTING_ENV_KEYS) delete env[key];
@@ -60,12 +58,9 @@ async function buildRuntimeEnvironment(options) {
60
58
  }
61
59
  }))).filter((item) => item !== null);
62
60
  const managedBinDirs = resolved.filter((item) => item.source === "managed").map((item) => dirname(item.executable));
63
- const skillBinDirs = await skillEnvironmentBinDirs(options.stateDir);
64
- applyPathPrepend(env, [
65
- ...managedBinDirs,
66
- ...skillBinDirs,
67
- ...options.extraBinDirs ?? []
68
- ]);
61
+ const skillBinDirs = await skillEnvironmentBinDirs(options.stateDir, options.skillEnvironmentIds ?? []);
62
+ applyPathPrepend(env, [...managedBinDirs, ...options.extraBinDirs ?? []]);
63
+ appendPathEntries(env, skillBinDirs);
69
64
  if (resolved.some((item) => item.runtime === "python")) {
70
65
  env.PYTHONNOUSERSITE = "1";
71
66
  env.PIP_REQUIRE_VIRTUALENV = "1";
@@ -1 +1 @@
1
- export declare function withInstallLock<T>(path: string, metadata: Record<string, unknown>, fn: () => Promise<T>): Promise<T>;
1
+ export declare function withInstallLock<T>(path: string, metadata: Record<string, unknown>, fn: () => Promise<T>, signal?: AbortSignal): Promise<T>;
@@ -7,38 +7,51 @@ function isProcessAlive(pid) {
7
7
  try {
8
8
  process.kill(pid, 0);
9
9
  return true;
10
- } catch {
11
- return false;
10
+ } catch (error) {
11
+ return error.code === "EPERM";
12
12
  }
13
13
  }
14
14
  async function staleLock(path) {
15
15
  try {
16
16
  const value = JSON.parse(await readFile(path, "utf8"));
17
- const pid = typeof value.pid === "number" ? value.pid : 0;
18
- const createdAt = typeof value.createdAt === "number" ? value.createdAt : 0;
19
- return !isProcessAlive(pid) && Date.now() - createdAt > LOCK_STALE_MS;
17
+ return !isProcessAlive(typeof value.pid === "number" ? value.pid : 0);
20
18
  } catch {
21
19
  return true;
22
20
  }
23
21
  }
24
- async function withInstallLock(path, metadata, fn) {
22
+ async function withInstallLock(path, metadata, fn, signal) {
25
23
  await mkdir(dirname(path), { recursive: true });
26
- while (true) try {
27
- const handle = await open(path, "wx", 384);
28
- await handle.writeFile(JSON.stringify({
29
- pid: process.pid,
30
- createdAt: Date.now(),
31
- ...metadata
32
- }));
33
- await handle.close();
34
- break;
35
- } catch (error) {
36
- if (error.code !== "EEXIST") throw error;
37
- if (await staleLock(path)) {
38
- await unlink(path).catch(() => void 0);
39
- continue;
24
+ const waitStartedAt = Date.now();
25
+ while (true) {
26
+ if (signal?.aborted) throw signal.reason ?? /* @__PURE__ */ new Error("Runtime installation was aborted");
27
+ try {
28
+ const handle = await open(path, "wx", 384);
29
+ await handle.writeFile(JSON.stringify({
30
+ pid: process.pid,
31
+ createdAt: Date.now(),
32
+ ...metadata
33
+ }));
34
+ await handle.close();
35
+ break;
36
+ } catch (error) {
37
+ if (error.code !== "EEXIST") throw error;
38
+ if (await staleLock(path)) {
39
+ await unlink(path).catch(() => void 0);
40
+ continue;
41
+ }
42
+ if (Date.now() - waitStartedAt > LOCK_STALE_MS) throw new Error(`Timed out waiting for runtime installation lock: ${path}`);
43
+ await new Promise((resolve, reject) => {
44
+ const timeout = setTimeout(() => {
45
+ signal?.removeEventListener("abort", abort);
46
+ resolve();
47
+ }, LOCK_WAIT_MS);
48
+ const abort = () => {
49
+ clearTimeout(timeout);
50
+ reject(signal?.reason ?? /* @__PURE__ */ new Error("Runtime installation was aborted"));
51
+ };
52
+ signal?.addEventListener("abort", abort, { once: true });
53
+ });
40
54
  }
41
- await new Promise((resolve) => setTimeout(resolve, LOCK_WAIT_MS));
42
55
  }
43
56
  try {
44
57
  return await fn();
@@ -15,6 +15,6 @@ export declare class ManagedRuntimeManager extends EventEmitter {
15
15
  private uvEnvironment;
16
16
  status(runtime: RuntimeKind): Promise<RuntimeStatus>;
17
17
  statusAll(): Promise<RuntimeStatus[]>;
18
- repair(runtime: RuntimeKind): Promise<ResolvedRuntime>;
18
+ repair(runtime: RuntimeKind, requestedVersion?: string): Promise<ResolvedRuntime>;
19
19
  private progress;
20
20
  }