@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-DLfkwJzZ.js → activity-store-MU5XrVv8.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DNqb8LGQ.js → agent-avatar-dicebear-B_Wc0wuL.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Cf7U2aUi.js +1 -0
- package/dist/gateway/static/root/assets/agents-Ce9oOnwE.js +1 -0
- package/dist/gateway/static/root/assets/{api-IUm57Zse.js → api-DLyc8BQp.js} +1 -1
- package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +1 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-4-eqCZG_.js → app-management-settings-panel-CACOOS-a.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Dus5TPxo.js → appearance-settings-DB5gEQhN.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BaTFOCmR.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Bha1jUhj.js → archive-plugin-BOx0EJZs.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CX2u191M.js → attachment-load-CYnYIyLr.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BizspokZ.js → automations-page-ChTflpmA.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-DK6EreCr.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CSn8R1EL.js → binary-plugins-BjbLfNwG.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D5MN7UPI.js → block-editor-DgAs5aJc.js} +46 -46
- package/dist/gateway/static/root/assets/browser-settings-page-CHStw5UW.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CeG3fWhC.js → browser-workflow-inputs-DGQxD0vD.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-oqmPd1KI.js → browser-workflows-page-B9gfdd7L.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-JGH6Kfkr.js +7 -0
- package/dist/gateway/static/root/assets/channels-settings-YkUaaWkY.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-CwUSKmeY.js → channels-status-swr-TkU42f-W.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-C0m-ie_q.js → chat-terminal-dock-CWMPcnoN.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-BI0FG3gA.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-DJOvtnKf.js → cron-expression-3h3rR0cf.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-B06ZCEsb.js → date-picker-Bz1sLBEx.js} +1 -1
- package/dist/gateway/static/root/assets/dependency-picker-p9DWR8uU.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-INH03b4z.js → desktop-pet-D1TDB_gR.js} +1 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-DWPZpoB7.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BcEHXLQ2.js → extension-debug-page-BrRbK2rJ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CWefEHKN.js → extension-page-CD65czfS.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CjBTLU5X.js → extension-settings-page-BRDDKhpi.js} +1 -1
- package/dist/gateway/static/root/assets/folder-open-CyzJ19I9.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-4GYzRHAt.js → gateway-config-api-CjbBsr5M.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-DfMY-MLf.js → gateway-config-swr-HT7sLeO9.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-C8MQeYbR.js → gateway-settings-BQjmfYD4.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-S6aB0hVI.js → gateway-startup-retry-iBCtaAuT.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-BzZxLgrw.js +1 -0
- package/dist/gateway/static/root/assets/home-page--9fKq0mL.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-DOX5uq-R.js → image-generation-api-dj9TNEn2.js} +1 -1
- package/dist/gateway/static/root/assets/index-D499B1qS.css +2 -0
- package/dist/gateway/static/root/assets/index-J3FsIvTs.js +70 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-xvS2czSF.js → keyboard-shortcuts-settings-BEnuEPD3.js} +1 -1
- package/dist/gateway/static/root/assets/link-2-D_ZKYUW7.js +1 -0
- package/dist/gateway/static/root/assets/local-app-workbench-page-FqG00zS1.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-BAYQxS0S.js → local-apps-page-DXQtppWq.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-XDFAPNNu.js → locale-store-DVzTJSj2.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-c6CfZ8PA.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-DYmKy_2v.js → management-settings-DIpBMWrA.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-Cr32dNv1.js → markdown-split-BFHyGwNF.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-v-O3cOpk.js → markdown-view-DR3yVwtV.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-KPSjs3vW.js → media-plugins-BjjMxC5_.js} +1 -1
- package/dist/gateway/static/root/assets/message-square-plus-XP0tGdlV.js +1 -0
- package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +3 -0
- package/dist/gateway/static/root/assets/minimize-2-DtOGrlpo.js +1 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-pWsC7jcc.js → mobile-pairing-wizard-CHnXZTwb.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-DiXjKuuY.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-DBBnJrFf.js → notes-page-BbvtelJa.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DIR37b-K.js +4 -0
- package/dist/gateway/static/root/assets/{oauth-api-B_pcOUfT.js → oauth-api-BB-VYJ5j.js} +1 -1
- package/dist/gateway/static/root/assets/pencil-DmIY3Oa-.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-B8cjLdm4.js → product-open-page-CRm9Q66h.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DHiLTiRW.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-God7NCcI.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-DeVvBsl4.js → registry-api-DXsR8oGN.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-YpF0-mx2.js +1 -0
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-DoEfLjPB.js +5 -0
- package/dist/gateway/static/root/assets/{schema-form-CW7qifxi.js → schema-form-BsqpbBDv.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CP8O1TxR.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DzdbK3j9.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-OMPX3Svb.js → settings-form-section-DjWzRk4z.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CDKXJ12S.js → settings-page-CE7ZcCTK.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CGlne9i0.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-Bn0qMX8V.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-B7NeVl4g.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DDTmi4a7.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-DAAlmTSh.js → skills-page-dRkeYh5P.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-CiMRNDFM.js → skills-page.utils--q8p7MAn.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-Bq7niN-G.js → system-settings-panel-C0ZCuCM4.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-yiMzii2b.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-5-XHH7F0.js → theme-store-Cth-eChE.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-CC3jOB4n.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-CkwILwYg.js → use-autosave-PSV89QuQ.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-Vtwg7fQc.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BG-kpmoU.js → voice-api-key-field-DXWdJ8cR.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-Bk_bVeGX.js → voice-config-api-BDoeXgww.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BOH2utuu.js → work-discovery-overlay-BV_Jj5iD.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DNHbWGPq.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-BkFIbMrz.js +5 -0
- package/dist/gateway/static/root/index.html +18 -13
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/skills/installer.d.ts +1 -0
- package/dist/src/agent/skills/installer.js +9 -6
- package/dist/src/agent/tools/factory.d.ts +2 -0
- package/dist/src/agent/tools/factory.js +5 -1
- package/dist/src/config/schema.js +5 -3
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/gateway/hono/routes/media.js +5 -14
- package/dist/src/gateway/hono/routes/runtime-tools.js +7 -1
- package/dist/src/gateway/hono/routes/shares.js +36 -8
- package/dist/src/gateway/media-access.d.ts +6 -0
- package/dist/src/gateway/media-access.js +19 -0
- package/dist/src/runtime-tools/archive.js +17 -3
- package/dist/src/runtime-tools/command.d.ts +1 -0
- package/dist/src/runtime-tools/command.js +29 -8
- package/dist/src/runtime-tools/environment.d.ts +1 -0
- package/dist/src/runtime-tools/environment.js +11 -16
- package/dist/src/runtime-tools/install-lock.d.ts +1 -1
- package/dist/src/runtime-tools/install-lock.js +34 -21
- package/dist/src/runtime-tools/manager.d.ts +1 -1
- package/dist/src/runtime-tools/manager.js +99 -64
- package/dist/src/runtime-tools/manifest-store.d.ts +2 -0
- package/dist/src/runtime-tools/manifest-store.js +29 -8
- package/dist/src/runtime-tools/paths.d.ts +2 -1
- package/dist/src/runtime-tools/paths.js +19 -8
- package/dist/src/runtime-tools/probe.d.ts +2 -0
- package/dist/src/runtime-tools/probe.js +13 -1
- package/dist/src/runtime-tools/prune.js +21 -7
- package/dist/src/share/share-store.js +3 -2
- package/dist/src/share/share-types.d.ts +2 -0
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CDZBY8QF.js +0 -1
- package/dist/gateway/static/root/assets/agents-BpWZKFrQ.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-DPacUrzS.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CudEcxwk.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-wKhgAIwg.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Dj_x6HTl.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-BpsJRsjG.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-B-Gdzfob.js +0 -2
- package/dist/gateway/static/root/assets/dependency-picker-BU8dmVCo.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-CzAGt3M_.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-C_8vY0Eu.js +0 -1
- package/dist/gateway/static/root/assets/home-page-D1SM6UXd.js +0 -1
- package/dist/gateway/static/root/assets/index-BN4XPtJY.js +0 -70
- package/dist/gateway/static/root/assets/index-CCBexxKW.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-DAh4_rTj.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-COS-Yb-N.js +0 -2
- package/dist/gateway/static/root/assets/messages-B1HDp_j8.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-Bngs8o1m.js +0 -1
- package/dist/gateway/static/root/assets/notes-api-BMhFpRmW.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-CSAzL8Tf.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-DHIJpssV.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BDoAwszu.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DPi4SQVV.js +0 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-DFTHpNg6.js +0 -5
- package/dist/gateway/static/root/assets/sessions-page-VNrtwwV5.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CUcTHMDp.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Dnvfemeb.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-BoSIu0WX.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-C87QeRxC.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-rY5ujr0j.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-JtztFp2Y.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-eBX1eb2v.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CMH2GOGL.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-B92rr2yf.js +0 -3
- 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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
823
|
-
|
|
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: "
|
|
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
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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
|
-
|
|
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
|
|
47
|
+
stdout = append(stdout, chunk);
|
|
35
48
|
});
|
|
36
49
|
child.stderr?.on("data", (chunk) => {
|
|
37
|
-
stderr
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
|
62
|
+
stdout = appendOutput(stdout, chunk);
|
|
42
63
|
});
|
|
43
64
|
child.stderr?.on("data", (chunk) => {
|
|
44
|
-
stderr
|
|
65
|
+
stderr = appendOutput(stderr, chunk);
|
|
45
66
|
});
|
|
46
67
|
child.once("error", () => finish(null));
|
|
47
68
|
child.once("close", finish);
|
|
48
|
-
|
|
69
|
+
timeout = setTimeout(() => {
|
|
49
70
|
timedOut = true;
|
|
50
|
-
|
|
71
|
+
killChild();
|
|
51
72
|
finish(null);
|
|
52
73
|
}, params.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);
|
|
53
74
|
timeout.unref();
|
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
}
|