@dsh-electron/dsh-plugin-multi-root-workspace 0.1.8 → 0.1.9
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/CHANGELOG.en.md +9 -1
- package/CHANGELOG.md +9 -1
- package/README.en.md +21 -13
- package/README.md +29 -21
- package/cordis.patch.yml +6 -0
- package/lib/auto-review-packages-nRjnb4pU.js +15 -0
- package/lib/auto-review.js +166 -0
- package/lib/{command-CESuwlVt.js → command-Bwd6EGNV.js} +3 -3
- package/lib/command.js +1 -1
- package/lib/compat.js +1 -1
- package/lib/fork-CzbeWxHp.js +670 -0
- package/lib/fs.js +1 -1
- package/lib/index.js +7 -7
- package/lib/{instructions-D19jRxN0.js → instructions-CGNS3H0H.js} +211 -57
- package/lib/instructions.js +1 -1
- package/lib/lsp.js +1 -1
- package/lib/{registry-DCxC5Lay.js → registry-BClm6wfh.js} +6 -6
- package/lib/registry.js +1 -1
- package/lib/review-context-D-ohSVmA.js +98 -0
- package/lib/review-context.js +2 -0
- package/lib/{roots-B-0l8mNG.js → roots-Ca_W1S9n.js} +1 -1
- package/lib/{sandbox-CVAcT_gy.js → sandbox-CXk5h-ct.js} +3 -3
- package/lib/sandbox.js +1 -1
- package/lib/scope.js +14 -5
- package/lib/types/auto-review/entry.d.ts +5 -0
- package/lib/types/compat/auto-review-contract.d.ts +3 -0
- package/lib/types/compat/auto-review-loader.d.ts +33 -0
- package/lib/types/compat/auto-review-packages.d.ts +1 -0
- package/lib/types/compat/instruction-activity.d.ts +17 -0
- package/lib/types/compat/review-session.d.ts +2 -0
- package/lib/types/instructions.d.ts +18 -1
- package/lib/types/review-context.d.ts +49 -0
- package/lib/types/scope.d.ts +5 -0
- package/lib/windows-runner.js +2 -2
- package/lib/workspace-files.js +2 -2
- package/package.json +47 -7
- package/src/auto-review/FORK.md +26 -0
- package/src/auto-review/LICENSE +21 -0
- package/src/auto-review/README.en.md +22 -0
- package/src/auto-review/README.md +22 -0
- package/lib/{compat-DR2LvmYZ.js → compat-CagUNzRB.js} +1 -1
- package/lib/{fs-Nlp2AiRX.js → fs-BTXySwSG.js} +1 -1
- package/lib/{registry-lease-win32-DTO6QpT9.js → registry-lease-win32-DVTq9d4D.js} +1 -1
- package/lib/{windows-runner-contract-CEfmZzu0.js → windows-runner-contract-B5R2K3mM.js} +1 -1
package/lib/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
1
|
+
import { a as composeInstructionMessage, c as createInstructionMessage, l as instructionsApi, r as PLUGIN_SOURCE, t as DEFAULT_MAX_BYTES, u as renderInstructions } from "./instructions-CGNS3H0H.js";
|
|
2
|
+
import { a as classifyStoredRoots, c as indexedStatuses, i as canonicalRoot, l as isCanonicallyUnder, m as validateRootCandidate, n as additionalRootId, p as resolveRootRef, r as availableRoots, s as expandRootInput, t as RootValidationError, u as removeStatusAt } from "./roots-Ca_W1S9n.js";
|
|
3
|
+
import { _ as classifyInstallation, c as agentPtyMarkerVerdict, d as HOST_SERVICE_PACKAGES, f as OPTIONAL_CORE_PACKAGES, g as SUPPORTED_DSH_RELEASES, h as RUNTIME_OPTIONAL_PACKAGES, i as assertSupportedInstallation, l as assertAgentPtyMarker, m as RUNNER_ANCHORED_PACKAGES, n as MultiRootCompatService, o as AGENT_PTY_MARKER, p as REQUIRED_CORE_PACKAGES, s as PtyMarkerContractError, t as DshCompatUnsupportedError, u as CORE_PACKAGES, v as compatEnforcement, y as readInstalledVersion } from "./compat-CagUNzRB.js";
|
|
4
|
+
import { n as widenConfined, t as MultiRootSandboxProvider } from "./sandbox-CXk5h-ct.js";
|
|
5
5
|
import { MULTI_ROOT_PROVIDER_BRAND, MultiRootProviders, brandMultiRootProvider, isMultiRootProvider } from "./providers.js";
|
|
6
|
-
import { t as MultiRootFileSystem } from "./fs-
|
|
6
|
+
import { t as MultiRootFileSystem } from "./fs-BTXySwSG.js";
|
|
7
7
|
import { a as parseRevealedView, i as parsePanelCall, n as PANEL_ENDPOINTS, o as parseRootsView, t as PANEL_CHANNEL } from "./contract-DZ4zczDT.js";
|
|
8
8
|
import { MultiRootScopeService, renderWorkspaceRootsContext, sanitizeAdditionalRoots } from "./scope.js";
|
|
9
|
-
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, l as RegistryAuthorityLease, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, t as DEFAULT_MAX_ADDITIONAL_ROOTS, u as RegistryLeaseContendedError } from "./registry-
|
|
10
|
-
import { a as renderRootsReport, c as revealArgv, i as parseFoldersCommand, o as resolvePanelPrimaryRoot, t as COMMAND_NAME } from "./command-
|
|
9
|
+
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, l as RegistryAuthorityLease, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, t as DEFAULT_MAX_ADDITIONAL_ROOTS, u as RegistryLeaseContendedError } from "./registry-BClm6wfh.js";
|
|
10
|
+
import { a as renderRootsReport, c as revealArgv, i as parseFoldersCommand, o as resolvePanelPrimaryRoot, t as COMMAND_NAME } from "./command-Bwd6EGNV.js";
|
|
11
11
|
//#region src/index.ts
|
|
12
12
|
/**
|
|
13
13
|
* Carrier plugin face for the bare-package-name loader row (see the module
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { t as effectiveDirectory } from "./session-directory-BLOstut1.js";
|
|
2
2
|
import { t as aroundTool } from "./tool-context-CpgIFcCB.js";
|
|
3
|
-
import { l as isCanonicallyUnder } from "./roots-
|
|
3
|
+
import { l as isCanonicallyUnder } from "./roots-Ca_W1S9n.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
|
-
import "@deepseek-ai/cordis";
|
|
6
|
-
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
7
5
|
import { createHash } from "node:crypto";
|
|
8
|
-
import {
|
|
6
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
7
|
+
import "@deepseek-ai/cordis";
|
|
9
8
|
import { canonicalPath } from "@deepseek-ai/dsh-sandbox";
|
|
9
|
+
import { stat } from "node:fs/promises";
|
|
10
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
11
|
//#region src/compat/agent-instructions.ts
|
|
11
12
|
/**
|
|
12
13
|
* Compatibility adapter for upstream's instruction discovery and rendering.
|
|
@@ -224,6 +225,95 @@ function toolResultFailed(message) {
|
|
|
224
225
|
return block.isError === true;
|
|
225
226
|
}
|
|
226
227
|
//#endregion
|
|
228
|
+
//#region src/compat/instruction-activity.ts
|
|
229
|
+
/** Public durable file activity, normalized without loading an optional tool runtime. */
|
|
230
|
+
function ptcFileActivity(event) {
|
|
231
|
+
const row = event;
|
|
232
|
+
const data = row.data;
|
|
233
|
+
if (typeof data?.subCallId !== "string") return void 0;
|
|
234
|
+
const id = `ptc:${data.subCallId}`;
|
|
235
|
+
if (row.type === "tool/ptc-dispatch-start" && typeof data.name === "string") {
|
|
236
|
+
const args = JSON.stringify(data.arguments);
|
|
237
|
+
if (args === void 0) throw new Error("review-context: incomplete durable PTC action");
|
|
238
|
+
return {
|
|
239
|
+
kind: "start",
|
|
240
|
+
id,
|
|
241
|
+
name: data.name,
|
|
242
|
+
arguments: args
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
if (row.type === "tool/ptc-dispatch") return {
|
|
246
|
+
kind: "end",
|
|
247
|
+
id,
|
|
248
|
+
failed: data.isError !== false || data.error !== void 0
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** Rebuild read-only discovery candidates from successful durable activity after resume. */
|
|
252
|
+
function replayedInstructionTargets(events, origin) {
|
|
253
|
+
let cwd = origin;
|
|
254
|
+
const pending = /* @__PURE__ */ new Map();
|
|
255
|
+
const paths = /* @__PURE__ */ new Set();
|
|
256
|
+
for (const raw of events) {
|
|
257
|
+
const event = raw;
|
|
258
|
+
if (event.type === "working-directory/change" && typeof event.data.cwd === "string") {
|
|
259
|
+
cwd = event.data.cwd;
|
|
260
|
+
for (const call of pending.values()) call.directories.add(cwd);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const ptc = ptcFileActivity(event);
|
|
264
|
+
if (event.type === "tool/call" || ptc?.kind === "start") {
|
|
265
|
+
const call = ptc?.kind === "start" ? {
|
|
266
|
+
callId: ptc.id,
|
|
267
|
+
name: ptc.name,
|
|
268
|
+
arguments: ptc.arguments
|
|
269
|
+
} : event.data;
|
|
270
|
+
if (typeof call.callId !== "string" || typeof call.name !== "string" || typeof call.arguments !== "string") throw new Error("review-context: incomplete durable file activity");
|
|
271
|
+
pending.set(call.callId, {
|
|
272
|
+
name: call.name,
|
|
273
|
+
arguments: call.arguments,
|
|
274
|
+
directories: new Set(cwd === void 0 ? [] : [cwd])
|
|
275
|
+
});
|
|
276
|
+
if (pending.size > 512) throw new Error("review-context: durable activity index exceeded");
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (event.type !== "tool/result" && ptc?.kind !== "end") continue;
|
|
280
|
+
const message = event.data.message;
|
|
281
|
+
const id = ptc?.kind === "end" ? ptc.id : message?.source?.callId;
|
|
282
|
+
if (typeof id !== "string") throw new Error("review-context: incomplete durable result");
|
|
283
|
+
const call = pending.get(id);
|
|
284
|
+
pending.delete(id);
|
|
285
|
+
if (call === void 0) continue;
|
|
286
|
+
if (ptc?.kind === "end" ? ptc.failed : event.data.error !== void 0 || toolResultFailed(message ?? {})) continue;
|
|
287
|
+
const path = touchedPathOfToolCall(call.name, call.arguments);
|
|
288
|
+
if (path === void 0) continue;
|
|
289
|
+
if (isAbsolute(path)) paths.add(path);
|
|
290
|
+
else {
|
|
291
|
+
if (call.directories.size === 0) throw new Error("review-context: durable file activity has no cwd");
|
|
292
|
+
for (const directory of call.directories) paths.add(resolve(directory, path));
|
|
293
|
+
}
|
|
294
|
+
if (paths.size > 512) throw new Error("review-context: durable work index exceeded");
|
|
295
|
+
}
|
|
296
|
+
return [...paths];
|
|
297
|
+
}
|
|
298
|
+
/** fs tools whose success touches the file at their `file_path` argument. */
|
|
299
|
+
const FILE_TOUCH_TOOL_NAMES = {
|
|
300
|
+
read: true,
|
|
301
|
+
write: true,
|
|
302
|
+
edit: true
|
|
303
|
+
};
|
|
304
|
+
/** One explicit fs-tool target, shared with live touch capture. */
|
|
305
|
+
function touchedPathOfToolCall(name, argumentsJson) {
|
|
306
|
+
if (FILE_TOUCH_TOOL_NAMES[name] !== true) return void 0;
|
|
307
|
+
let parsed;
|
|
308
|
+
try {
|
|
309
|
+
parsed = JSON.parse(argumentsJson);
|
|
310
|
+
} catch {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (typeof parsed !== "object" || parsed === null || !("file_path" in parsed) || typeof parsed.file_path !== "string") return void 0;
|
|
314
|
+
return parsed.file_path.trim() || void 0;
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
227
317
|
//#region src/compat/instruction-overlap.ts
|
|
228
318
|
/** Recognize files already represented by the native instruction baseline in this step. */
|
|
229
319
|
function nativeInstructionCopies(messages, cwd) {
|
|
@@ -327,12 +417,6 @@ const PLUGIN_SOURCE = "@dsh-electron/dsh-plugin-multi-root-workspace";
|
|
|
327
417
|
const DEFAULT_MAX_BYTES = 65536;
|
|
328
418
|
/** Largest instruction file this row will read; larger files are ignored. */
|
|
329
419
|
const DEFAULT_MAX_SOURCE_BYTES = 32768;
|
|
330
|
-
/** Tools whose SUCCESS makes the directories on the path to the file relevant. */
|
|
331
|
-
const FILE_TOUCH_TOOL_NAMES = {
|
|
332
|
-
read: true,
|
|
333
|
-
write: true,
|
|
334
|
-
edit: true
|
|
335
|
-
};
|
|
336
420
|
/** Cap on unanswered `tool/call` records remembered per session. */
|
|
337
421
|
const MAX_PENDING_CALLS = 128;
|
|
338
422
|
/** Cap on touched paths remembered per session; beyond it, touches are dropped. */
|
|
@@ -362,31 +446,6 @@ function relativeDirectoryOf(root, directory) {
|
|
|
362
446
|
return suffix.length === 0 ? "." : suffix;
|
|
363
447
|
}
|
|
364
448
|
/**
|
|
365
|
-
* The path one RAW tool call touched.
|
|
366
|
-
*
|
|
367
|
-
* `arguments` is the model-produced JSON string, so the path is only known after
|
|
368
|
-
* parsing it; a call that names no `file_path`, or is not one of the tools whose
|
|
369
|
-
* success makes a directory relevant, touched nothing this row cares about.
|
|
370
|
-
* @param name - the tool name the model called.
|
|
371
|
-
* @param argumentsJson - the tool call's raw arguments, exactly as produced.
|
|
372
|
-
* @returns the trimmed absolute-or-relative path, or `undefined`.
|
|
373
|
-
*/
|
|
374
|
-
function touchedPathOfToolCall(name, argumentsJson) {
|
|
375
|
-
if (FILE_TOUCH_TOOL_NAMES[name] !== true) return void 0;
|
|
376
|
-
let parsed;
|
|
377
|
-
try {
|
|
378
|
-
parsed = JSON.parse(argumentsJson);
|
|
379
|
-
} catch {
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
383
|
-
if (!("file_path" in parsed)) return void 0;
|
|
384
|
-
const path = parsed.file_path;
|
|
385
|
-
if (typeof path !== "string") return void 0;
|
|
386
|
-
const trimmed = path.trim();
|
|
387
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
449
|
* The directory a touched path's instructions would live in.
|
|
391
450
|
*
|
|
392
451
|
* Tool arguments are the model's raw input, so a relative `file_path` is
|
|
@@ -460,7 +519,9 @@ function apply(ctx, config = {}) {
|
|
|
460
519
|
if (existing !== void 0) return existing;
|
|
461
520
|
const created = {
|
|
462
521
|
scopes: /* @__PURE__ */ new Map(),
|
|
463
|
-
|
|
522
|
+
provenanceRoots: /* @__PURE__ */ new Set(),
|
|
523
|
+
touched: /* @__PURE__ */ new Set(),
|
|
524
|
+
worked: /* @__PURE__ */ new Set()
|
|
464
525
|
};
|
|
465
526
|
states.set(session, created);
|
|
466
527
|
return created;
|
|
@@ -468,36 +529,88 @@ function apply(ctx, config = {}) {
|
|
|
468
529
|
ctx.on("session/event", (session, event) => {
|
|
469
530
|
const pendingCalls = callsBySession.get(session) ?? /* @__PURE__ */ new Map();
|
|
470
531
|
callsBySession.set(session, pendingCalls);
|
|
471
|
-
|
|
532
|
+
const ptc = ptcFileActivity(event);
|
|
533
|
+
if (event.type === "tool/call" || ptc?.kind === "start") {
|
|
472
534
|
if (pendingCalls.size >= MAX_PENDING_CALLS) {
|
|
473
535
|
const oldest = pendingCalls.keys().next();
|
|
474
536
|
if (!oldest.done) pendingCalls.delete(oldest.value);
|
|
475
537
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
538
|
+
const call = ptc?.kind === "start" ? {
|
|
539
|
+
callId: ptc.id,
|
|
540
|
+
name: ptc.name,
|
|
541
|
+
arguments: ptc.arguments
|
|
542
|
+
} : event.type === "tool/call" ? event.data : void 0;
|
|
543
|
+
if (call !== void 0) pendingCalls.set(call.callId, {
|
|
544
|
+
name: call.name,
|
|
545
|
+
arguments: call.arguments,
|
|
479
546
|
cwd: effectiveDirectory(ctx, session)
|
|
480
547
|
});
|
|
481
548
|
return;
|
|
482
549
|
}
|
|
483
|
-
if (event.type !== "tool/result") return;
|
|
484
|
-
const callId = event.data.message.source.callId;
|
|
550
|
+
if (event.type !== "tool/result" && ptc?.kind !== "end") return;
|
|
551
|
+
const callId = ptc?.kind === "end" ? ptc.id : event.type === "tool/result" ? event.data.message.source.callId : "";
|
|
485
552
|
const call = pendingCalls.get(callId);
|
|
486
553
|
pendingCalls.delete(callId);
|
|
487
554
|
if (call === void 0) return;
|
|
488
|
-
if (event.data.error !== void 0 || toolResultFailed(event.data.message)) return;
|
|
555
|
+
if (ptc?.kind === "end" ? ptc.failed : event.type === "tool/result" && (event.data.error !== void 0 || toolResultFailed(event.data.message))) return;
|
|
489
556
|
const path = call.observedPath ?? touchedPathOfToolCall(call.name, call.arguments);
|
|
490
557
|
if (path === void 0) return;
|
|
491
558
|
const state = stateOf(session);
|
|
559
|
+
const absolute = isAbsolute(path) ? path : call.cwd === void 0 ? void 0 : resolve(call.cwd, path);
|
|
560
|
+
if (absolute !== void 0) {
|
|
561
|
+
if (state.worked.size >= MAX_DELIVERED_SCOPES && !state.worked.has(absolute)) state.overflow = true;
|
|
562
|
+
else state.worked.add(absolute);
|
|
563
|
+
}
|
|
492
564
|
if (state.touched.size >= MAX_TOUCHED_PATHS) return;
|
|
493
565
|
if (isAbsolute(path)) state.touched.add(path);
|
|
494
566
|
else if (call.cwd !== void 0) state.touched.add(resolve(call.cwd, path));
|
|
495
567
|
});
|
|
496
568
|
ctx.inject(["fs"], (scope) => {
|
|
569
|
+
scope.provide("multiRootInstructions", {
|
|
570
|
+
knownRoots(session) {
|
|
571
|
+
return [...states.get(session)?.provenanceRoots ?? []];
|
|
572
|
+
},
|
|
573
|
+
async snapshot(agent, roots, target, signal) {
|
|
574
|
+
signal.throwIfAborted();
|
|
575
|
+
if (roots.length === 0) return [];
|
|
576
|
+
const api = await instructionsApi();
|
|
577
|
+
if (api === void 0) throw new Error("review-context: instruction discovery unavailable");
|
|
578
|
+
const existing = states.get(agent.session);
|
|
579
|
+
if (existing?.overflow) throw new Error("review-context: successful work index exceeded");
|
|
580
|
+
const state = {
|
|
581
|
+
scopes: new Map([...existing?.scopes ?? []].map(([key, value]) => [key, {
|
|
582
|
+
...value,
|
|
583
|
+
digest: void 0
|
|
584
|
+
}])),
|
|
585
|
+
provenanceRoots: new Set(existing?.provenanceRoots),
|
|
586
|
+
touched: /* @__PURE__ */ new Set([...existing?.touched ?? [], ...existing?.worked ?? []]),
|
|
587
|
+
worked: /* @__PURE__ */ new Set()
|
|
588
|
+
};
|
|
589
|
+
for (const path of replayedInstructionTargets(agent.session.snapshotEvents(), agent.session.header.cwd)) state.touched.add(path);
|
|
590
|
+
if (target !== void 0) state.touched.add(target);
|
|
591
|
+
const cwd = effectiveDirectory(scope, agent.session);
|
|
592
|
+
const reviewCwd = cwd === void 0 ? void 0 : canonicalPath(cwd);
|
|
593
|
+
const result = [];
|
|
594
|
+
for (const root of roots) {
|
|
595
|
+
const plan = await planRoot(scope, api, root, config, state, signal, true, reviewCwd);
|
|
596
|
+
for (const { file } of plan.deliveries) result.push({
|
|
597
|
+
root,
|
|
598
|
+
path: file.absolutePath,
|
|
599
|
+
relativeDirectory: relativeDirectoryOf(root, dirname(file.absolutePath)),
|
|
600
|
+
digest: digestOf(file.content),
|
|
601
|
+
text: file.content
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
signal.throwIfAborted();
|
|
605
|
+
if (Buffer.byteLength(JSON.stringify(result), "utf8") > maxBytes) throw new Error("review-context: instruction budget exceeded");
|
|
606
|
+
return result;
|
|
607
|
+
}
|
|
608
|
+
});
|
|
497
609
|
scope.on("fs/observed", (target, _observation, actor) => {
|
|
498
610
|
const exec = executions.getStore();
|
|
499
611
|
if (exec?.agent === void 0 || FILE_TOUCH_TOOL_NAMES[exec.name] !== true || actor !== exec) return;
|
|
500
|
-
const
|
|
612
|
+
const calls = callsBySession.get(exec.agent.session);
|
|
613
|
+
const call = calls?.get(exec.callId) ?? calls?.get(`ptc:${exec.callId}`);
|
|
501
614
|
if (call !== void 0) call.observedPath = scope.fs.processPath(target);
|
|
502
615
|
});
|
|
503
616
|
scope.on("agent/pre-step", async ({ agent, messages, signal }, next) => {
|
|
@@ -531,7 +644,9 @@ async function pending(ctx, states, agent, config, maxBytes, signal, messages) {
|
|
|
531
644
|
const session = agent.session;
|
|
532
645
|
const state = states.get(session) ?? {
|
|
533
646
|
scopes: /* @__PURE__ */ new Map(),
|
|
534
|
-
|
|
647
|
+
provenanceRoots: /* @__PURE__ */ new Set(),
|
|
648
|
+
touched: /* @__PURE__ */ new Set(),
|
|
649
|
+
worked: /* @__PURE__ */ new Set()
|
|
535
650
|
};
|
|
536
651
|
states.set(session, state);
|
|
537
652
|
const evaluatedTouches = new Set(state.touched);
|
|
@@ -610,7 +725,10 @@ async function pending(ctx, states, agent, config, maxBytes, signal, messages) {
|
|
|
610
725
|
if (text !== void 0 || liveUpdates.length > 0) {
|
|
611
726
|
for (const root of revoked) for (const [key, entry] of state.scopes) if (entry.root === root) state.scopes.delete(key);
|
|
612
727
|
for (const entry of gone) state.scopes.delete(entry.key);
|
|
613
|
-
for (const entry of liveUpdates)
|
|
728
|
+
for (const entry of liveUpdates) {
|
|
729
|
+
state.scopes.set(entry.key, entry.scope);
|
|
730
|
+
state.provenanceRoots.add(entry.scope.root);
|
|
731
|
+
}
|
|
614
732
|
}
|
|
615
733
|
return message;
|
|
616
734
|
}
|
|
@@ -626,15 +744,19 @@ async function pending(ctx, states, agent, config, maxBytes, signal, messages) {
|
|
|
626
744
|
* of that directory's ancestors up to the root, because discovery reports an
|
|
627
745
|
* intermediate directory's file but only the exact directory's candidates
|
|
628
746
|
* survive the filter below.
|
|
747
|
+
* A strict review can also seed its effective cwd chain without recording a
|
|
748
|
+
* successful touch; ordinary pre-step delivery never supplies that seed.
|
|
629
749
|
* @param ctx - the row's context, for `fs` and the logger.
|
|
630
750
|
* @param api - the adapted upstream instruction surface.
|
|
631
751
|
* @param root - the canonical additional root.
|
|
632
752
|
* @param config - the row's configuration.
|
|
633
753
|
* @param state - the session's delivery state.
|
|
634
754
|
* @param signal - the turn's cancellation signal.
|
|
755
|
+
* @param strict - fail on incomplete review discovery instead of deferring delivery.
|
|
756
|
+
* @param reviewCwd - review-only directory seed; never a successful touch.
|
|
635
757
|
* @returns the files to send and the deliveries to withdraw.
|
|
636
758
|
*/
|
|
637
|
-
async function planRoot(ctx, api, root, config, state, signal) {
|
|
759
|
+
async function planRoot(ctx, api, root, config, state, signal, strict = false, reviewCwd) {
|
|
638
760
|
const delivered = /* @__PURE__ */ new Map();
|
|
639
761
|
for (const [key, entry] of state.scopes) if (entry.root === root) delivered.set(key, entry);
|
|
640
762
|
const dirs = /* @__PURE__ */ new Set([root]);
|
|
@@ -642,8 +764,9 @@ async function planRoot(ctx, api, root, config, state, signal) {
|
|
|
642
764
|
const dir = dirname(entry.path);
|
|
643
765
|
if (dir !== root) dirs.add(dir);
|
|
644
766
|
}
|
|
645
|
-
|
|
646
|
-
|
|
767
|
+
const parents = [...state.touched].map(parentDirectoryOf);
|
|
768
|
+
if (reviewCwd !== void 0) parents.push(reviewCwd);
|
|
769
|
+
for (const parent of parents) {
|
|
647
770
|
if (parent === void 0 || !isCanonicallyUnder(parent, root)) continue;
|
|
648
771
|
let dir = parent;
|
|
649
772
|
for (;;) {
|
|
@@ -659,7 +782,7 @@ async function planRoot(ctx, api, root, config, state, signal) {
|
|
|
659
782
|
signal.throwIfAborted();
|
|
660
783
|
walks.push({
|
|
661
784
|
relativeDirectory: relativeDirectoryOf(root, dir),
|
|
662
|
-
read: await loadDirectory(ctx.fs, api, root, config, signal, dir)
|
|
785
|
+
read: await loadDirectory(ctx.fs, api, root, config, signal, dir, strict)
|
|
663
786
|
});
|
|
664
787
|
}
|
|
665
788
|
walks.sort((left, right) => left.relativeDirectory.split(sep).length - right.relativeDirectory.split(sep).length || (left.relativeDirectory < right.relativeDirectory ? -1 : left.relativeDirectory > right.relativeDirectory ? 1 : 0));
|
|
@@ -678,7 +801,7 @@ async function planRoot(ctx, api, root, config, state, signal) {
|
|
|
678
801
|
const previous = delivered.get(key);
|
|
679
802
|
if (previous !== void 0 && previous.digest === digestOf(file.content)) continue;
|
|
680
803
|
if (previous === void 0 && walk.relativeDirectory !== ".") {
|
|
681
|
-
if (state.scopes.size >= MAX_DELIVERED_SCOPES) {
|
|
804
|
+
if (!strict && state.scopes.size >= MAX_DELIVERED_SCOPES) {
|
|
682
805
|
if (!scopeCapWarned) {
|
|
683
806
|
scopeCapWarned = true;
|
|
684
807
|
ctx.logger.warn("multi-root workspace: additional-root instruction scopes capped at %d", MAX_DELIVERED_SCOPES);
|
|
@@ -708,6 +831,18 @@ async function planRoot(ctx, api, root, config, state, signal) {
|
|
|
708
831
|
gone
|
|
709
832
|
};
|
|
710
833
|
}
|
|
834
|
+
/** Bounded provider read; an over-budget source never becomes a partial constraint. */
|
|
835
|
+
async function readReviewInstruction(fs, target, signal, maxBytes) {
|
|
836
|
+
const chunks = [];
|
|
837
|
+
let bytes = 0;
|
|
838
|
+
for await (const chunk of await fs.streamText(target, signal)) {
|
|
839
|
+
signal.throwIfAborted();
|
|
840
|
+
bytes += Buffer.byteLength(chunk, "utf8");
|
|
841
|
+
if (bytes > maxBytes) throw new Error("review-context: instruction source budget exceeded");
|
|
842
|
+
chunks.push(chunk);
|
|
843
|
+
}
|
|
844
|
+
return chunks.join("");
|
|
845
|
+
}
|
|
711
846
|
/**
|
|
712
847
|
* Walk from `cwd` up to `root` and read the instruction candidates it reports.
|
|
713
848
|
*
|
|
@@ -734,9 +869,21 @@ async function planRoot(ctx, api, root, config, state, signal) {
|
|
|
734
869
|
* @param cwd - the directory the walk starts from; always inside `root`.
|
|
735
870
|
* @returns the directory read.
|
|
736
871
|
*/
|
|
737
|
-
async function loadDirectory(fs, api, root, config, signal, cwd) {
|
|
738
|
-
const
|
|
872
|
+
async function loadDirectory(fs, api, root, config, signal, cwd, strict = false) {
|
|
873
|
+
const configuredSourceBytes = config.maxSourceBytes ?? 32768;
|
|
874
|
+
if (strict && (!Number.isFinite(configuredSourceBytes) || configuredSourceBytes <= 0)) throw new Error("review-context: invalid source budget");
|
|
875
|
+
const maxSourceBytes = strict ? Math.min(configuredSourceBytes, DEFAULT_MAX_BYTES) : configuredSourceBytes;
|
|
739
876
|
let candidates;
|
|
877
|
+
if (strict) for (const name of [...config.instructionFileCandidates ?? ["AGENTS.md", "CLAUDE.md"], ...config.localInstructionFileCandidates ?? ["AGENTS.local.md", "CLAUDE.local.md"]]) {
|
|
878
|
+
if (basename(name) !== name || name === "." || name === "..") throw new Error("review-context: invalid instruction candidate");
|
|
879
|
+
signal.throwIfAborted();
|
|
880
|
+
try {
|
|
881
|
+
await stat(resolve(cwd, name));
|
|
882
|
+
} catch (error) {
|
|
883
|
+
const code = error.code;
|
|
884
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") throw new Error("review-context: instruction probe failed");
|
|
885
|
+
}
|
|
886
|
+
}
|
|
740
887
|
try {
|
|
741
888
|
candidates = await api.discover({
|
|
742
889
|
cwd,
|
|
@@ -745,7 +892,8 @@ async function loadDirectory(fs, api, root, config, signal, cwd) {
|
|
|
745
892
|
...config.instructionFileCandidates === void 0 ? {} : { instructionFileCandidates: config.instructionFileCandidates },
|
|
746
893
|
...config.localInstructionFileCandidates === void 0 ? {} : { localInstructionFileCandidates: config.localInstructionFileCandidates }
|
|
747
894
|
});
|
|
748
|
-
} catch {
|
|
895
|
+
} catch (error) {
|
|
896
|
+
if (strict) throw error;
|
|
749
897
|
return {
|
|
750
898
|
candidates: [],
|
|
751
899
|
files: [],
|
|
@@ -762,15 +910,21 @@ async function loadDirectory(fs, api, root, config, signal, cwd) {
|
|
|
762
910
|
if (!isCanonicallyUnder(path, root)) continue;
|
|
763
911
|
const info = await fs.stat(target, signal);
|
|
764
912
|
if (info === void 0 || info.type !== "file") continue;
|
|
765
|
-
if (info.size !== void 0 && info.size > maxSourceBytes)
|
|
766
|
-
|
|
913
|
+
if (info.size !== void 0 && info.size > maxSourceBytes) {
|
|
914
|
+
if (strict) throw new Error("review-context: instruction source budget exceeded");
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
const content = strict ? await readReviewInstruction(fs, target, signal, maxSourceBytes) : await fs.readText(target, signal);
|
|
918
|
+
if (strict && Buffer.byteLength(content, "utf8") > maxSourceBytes) throw new Error("review-context: instruction source budget exceeded");
|
|
919
|
+
if (strict && canonicalPath(candidate.absolutePath) !== path) throw new Error("review-context: instruction identity changed");
|
|
767
920
|
if (canonicalPath(candidate.absolutePath) !== path || !isCanonicallyUnder(path, root)) continue;
|
|
768
921
|
files.push({
|
|
769
922
|
...candidate,
|
|
770
923
|
displayPath: candidate.absolutePath,
|
|
771
924
|
content
|
|
772
925
|
});
|
|
773
|
-
} catch {
|
|
926
|
+
} catch (error) {
|
|
927
|
+
if (strict) throw error;
|
|
774
928
|
continue;
|
|
775
929
|
}
|
|
776
930
|
}
|
package/lib/instructions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as composeInstructionMessage, i as apply, n as DEFAULT_MAX_SOURCE_BYTES, o as inject, r as PLUGIN_SOURCE, s as touchedPathOfToolCall, t as DEFAULT_MAX_BYTES } from "./instructions-
|
|
1
|
+
import { a as composeInstructionMessage, i as apply, n as DEFAULT_MAX_SOURCE_BYTES, o as inject, r as PLUGIN_SOURCE, s as touchedPathOfToolCall, t as DEFAULT_MAX_BYTES } from "./instructions-CGNS3H0H.js";
|
|
2
2
|
export { DEFAULT_MAX_BYTES, DEFAULT_MAX_SOURCE_BYTES, PLUGIN_SOURCE, apply, composeInstructionMessage, inject, touchedPathOfToolCall };
|
package/lib/lsp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { t as wrapMethod } from "./method-wrapper-CFY3p3j2.js";
|
|
1
2
|
import { t as aroundTool } from "./tool-context-CpgIFcCB.js";
|
|
2
3
|
import { t as routeWorkspacePath } from "./workspace-routing-YPxaQ4V3.js";
|
|
3
|
-
import { t as wrapMethod } from "./method-wrapper-CFY3p3j2.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
//#region src/lsp.ts
|
|
6
6
|
const inject = [
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { i as isWindowsNetworkOrDevicePath } from "./windows-runner-contract-
|
|
2
|
-
import { a as classifyStoredRoots, d as reservedRootBoundary, f as resolveRootIndex, i as canonicalRoot, m as validateRootCandidate, n as additionalRootId, r as availableRoots, s as expandRootInput, t as RootValidationError, u as removeStatusAt } from "./roots-
|
|
1
|
+
import { i as isWindowsNetworkOrDevicePath } from "./windows-runner-contract-B5R2K3mM.js";
|
|
2
|
+
import { a as classifyStoredRoots, d as reservedRootBoundary, f as resolveRootIndex, i as canonicalRoot, m as validateRootCandidate, n as additionalRootId, r as availableRoots, s as expandRootInput, t as RootValidationError, u as removeStatusAt } from "./roots-Ca_W1S9n.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import { Service } from "@deepseek-ai/cordis";
|
|
5
4
|
import { closeSync, fstatSync, mkdirSync, openSync, statSync } from "node:fs";
|
|
6
|
-
import { dirname, isAbsolute } from "node:path";
|
|
7
5
|
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { dirname, isAbsolute } from "node:path";
|
|
7
|
+
import { Service } from "@deepseek-ai/cordis";
|
|
8
8
|
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
9
9
|
import { tryLockExclusive } from "@deepseek-ai/node-addon-system/flock";
|
|
10
10
|
//#region src/compat/storage-zod.ts
|
|
@@ -123,7 +123,7 @@ var RegistryAuthorityLease = class RegistryAuthorityLease {
|
|
|
123
123
|
mode: 448
|
|
124
124
|
});
|
|
125
125
|
if (process.platform === "win32") {
|
|
126
|
-
const { acquireLockHandleWin32 } = await import("./registry-lease-win32-
|
|
126
|
+
const { acquireLockHandleWin32 } = await import("./registry-lease-win32-DVTq9d4D.js");
|
|
127
127
|
let handle;
|
|
128
128
|
try {
|
|
129
129
|
handle = await acquireLockHandleWin32(leasePath);
|
|
@@ -175,7 +175,7 @@ var RegistryAuthorityLease = class RegistryAuthorityLease {
|
|
|
175
175
|
if (this.released) return;
|
|
176
176
|
this.released = true;
|
|
177
177
|
if (this.held.kind === "win32") {
|
|
178
|
-
const { releaseLockHandleWin32 } = await import("./registry-lease-win32-
|
|
178
|
+
const { releaseLockHandleWin32 } = await import("./registry-lease-win32-DVTq9d4D.js");
|
|
179
179
|
await releaseLockHandleWin32(this.held.handle);
|
|
180
180
|
return;
|
|
181
181
|
}
|
package/lib/registry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, s as TABLE_NAME, t as DEFAULT_MAX_ADDITIONAL_ROOTS } from "./registry-
|
|
1
|
+
import { a as MultiRootRegistry, c as multiRootDomainSpec, i as MAX_ALIAS_LENGTH, n as DOMAIN_NAME, o as REGISTRY_CONTENDED_MESSAGE, r as MAX_ADDITIONAL_ROOTS_CEILING, s as TABLE_NAME, t as DEFAULT_MAX_ADDITIONAL_ROOTS } from "./registry-BClm6wfh.js";
|
|
2
2
|
export { DEFAULT_MAX_ADDITIONAL_ROOTS, DOMAIN_NAME, MAX_ADDITIONAL_ROOTS_CEILING, MAX_ALIAS_LENGTH, MultiRootRegistry, MultiRootRegistry as default, REGISTRY_CONTENDED_MESSAGE, TABLE_NAME, multiRootDomainSpec };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { t as effectiveDirectory } from "./session-directory-BLOstut1.js";
|
|
2
|
+
import { s as touchedPathOfToolCall } from "./instructions-CGNS3H0H.js";
|
|
3
|
+
import { l as isCanonicallyUnder } from "./roots-Ca_W1S9n.js";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { Service } from "@deepseek-ai/cordis";
|
|
7
|
+
import { canonicalPath } from "@deepseek-ai/dsh-sandbox";
|
|
8
|
+
//#region src/compat/auto-review-contract.ts
|
|
9
|
+
/** The companion's joint support contract is deliberately narrower than the ordinary bundle. */
|
|
10
|
+
const AUTO_REVIEW_RELEASE = "0.2.1-rc.2";
|
|
11
|
+
function assertAutoReviewRelease(release) {
|
|
12
|
+
if (release !== "0.2.1-rc.2") throw new Error(`multi-root Auto Review requires exactly DSH ${AUTO_REVIEW_RELEASE}`);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/compat/review-session.ts
|
|
16
|
+
/** Fingerprint only the native instruction producer's visible authority data. */
|
|
17
|
+
function nativeInstructionFingerprint(session) {
|
|
18
|
+
const rows = [];
|
|
19
|
+
for (const seq of session.surface.nodes) {
|
|
20
|
+
const event = session.eventAt(seq);
|
|
21
|
+
if (event?.type === "user/message" && event.data.source.kind === "agent-instructions") rows.push(event.data);
|
|
22
|
+
}
|
|
23
|
+
return createHash("sha256").update(JSON.stringify(rows)).digest("hex");
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/review-context.ts
|
|
27
|
+
/** Read-only, current host context for the optional Auto Review companion. */
|
|
28
|
+
/** All authority remains in the existing Registry/scope and instruction index. */
|
|
29
|
+
var MultiRootReviewContext = class extends Service {
|
|
30
|
+
static inject = [
|
|
31
|
+
"multiRootCompat",
|
|
32
|
+
"multiRootProviders",
|
|
33
|
+
"multiRootScope",
|
|
34
|
+
"multiRootRegistry",
|
|
35
|
+
"multiRootInstructions",
|
|
36
|
+
"sandboxPolicy",
|
|
37
|
+
"workingDirectory",
|
|
38
|
+
"fs"
|
|
39
|
+
];
|
|
40
|
+
constructor(ctx) {
|
|
41
|
+
super(ctx, "multiRootReviewContext");
|
|
42
|
+
}
|
|
43
|
+
assertCompatible() {
|
|
44
|
+
assertAutoReviewRelease(this.ctx.multiRootCompat.release);
|
|
45
|
+
}
|
|
46
|
+
async build(exec, signal) {
|
|
47
|
+
signal.throwIfAborted();
|
|
48
|
+
const agent = exec.agent;
|
|
49
|
+
if (agent === void 0) throw new Error("review-context: missing session");
|
|
50
|
+
const policy = this.ctx.sandboxPolicy.resolve({ session: agent.session });
|
|
51
|
+
const primary = canonicalPath(policy.workspaceRoot);
|
|
52
|
+
if (agent.session.header.cwd !== void 0 && canonicalPath(agent.session.header.cwd) !== primary) throw new Error("review-context: inconsistent session origin");
|
|
53
|
+
await this.ctx.multiRootRegistry.refresh(primary);
|
|
54
|
+
signal.throwIfAborted();
|
|
55
|
+
const cwd = effectiveDirectory(this.ctx, agent.session);
|
|
56
|
+
if (cwd === void 0) throw new Error("review-context: missing effective cwd");
|
|
57
|
+
const scope = this.ctx.multiRootScope.previewForTool(policy, exec.name);
|
|
58
|
+
const environment = {
|
|
59
|
+
sessionOrigin: scope.primaryRoot,
|
|
60
|
+
effectiveCwd: cwd,
|
|
61
|
+
sandboxMode: policy.mode,
|
|
62
|
+
registryAuthority: scope.authority,
|
|
63
|
+
roots: scope.roots.map((root) => ({
|
|
64
|
+
path: root.path,
|
|
65
|
+
access: root.access,
|
|
66
|
+
effectiveWritable: scope.writableRoots.includes(root.path) && !scope.deniedRoots.some((deny) => isCanonicallyUnder(root.path, deny))
|
|
67
|
+
})),
|
|
68
|
+
writableRoots: scope.writableRoots,
|
|
69
|
+
deniedRoots: scope.deniedRoots,
|
|
70
|
+
...scope.protectedHome === void 0 ? {} : { protectedHome: scope.protectedHome },
|
|
71
|
+
ambientWrites: policy.mode === "danger-full-access" && scope.authority === "available",
|
|
72
|
+
readConfinement: false,
|
|
73
|
+
primaryRootWritable: policy.mode !== "read-only" && !scope.deniedRoots.some((deny) => isCanonicallyUnder(scope.primaryRoot, deny)),
|
|
74
|
+
writeBoundary: scope.authority === "unavailable" && policy.mode !== "read-only" ? "primary-root-only; no shared temp grants; explicit denies take precedence" : policy.mode === "danger-full-access" ? "ambient host writes minus explicit deny boundaries; membership is not an access allowlist" : policy.mode === "workspace-write" ? "primary root, effective writable additional roots and upstream host temp grants; explicit denies take precedence" : "only effective writable additional roots; explicit denies take precedence"
|
|
75
|
+
};
|
|
76
|
+
const path = touchedPathOfToolCall(exec.name, JSON.stringify(exec.arguments));
|
|
77
|
+
const target = path === void 0 ? void 0 : this.ctx.fs.processPath(await this.ctx.fs.resolve(resolve(cwd, path), { signal }));
|
|
78
|
+
const constraints = await this.ctx.multiRootInstructions.snapshot(agent, scope.authority === "available" ? scope.additionalRoots : [], target, signal);
|
|
79
|
+
signal.throwIfAborted();
|
|
80
|
+
const payload = {
|
|
81
|
+
schemaVersion: 1,
|
|
82
|
+
environment,
|
|
83
|
+
instructionProvenanceRoots: [.../* @__PURE__ */ new Set([...scope.additionalRoots, ...this.ctx.multiRootInstructions.knownRoots(agent.session)])],
|
|
84
|
+
constraints,
|
|
85
|
+
completeness: "complete"
|
|
86
|
+
};
|
|
87
|
+
if (Buffer.byteLength(JSON.stringify(payload), "utf8") > 65536) throw new Error("review-context: context budget exceeded");
|
|
88
|
+
return {
|
|
89
|
+
...payload,
|
|
90
|
+
fingerprint: createHash("sha256").update(JSON.stringify([payload, nativeInstructionFingerprint(agent.session)])).digest("hex")
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async assertCurrent(exec, snapshot, signal) {
|
|
94
|
+
if ((await this.build(exec, signal)).fingerprint !== snapshot.fingerprint) throw new Error("review-context: snapshot changed; retry the tool call");
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
98
|
+
export { assertAutoReviewRelease as n, MultiRootReviewContext as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as isWindowsNetworkOrDevicePath } from "./windows-runner-contract-
|
|
1
|
+
import { i as isWindowsNetworkOrDevicePath } from "./windows-runner-contract-B5R2K3mM.js";
|
|
2
2
|
import { statSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, sep } from "node:path";
|
|
4
4
|
import { canonicalPath } from "@deepseek-ai/dsh-sandbox";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as parseWindowsProfile, i as isWindowsNetworkOrDevicePath, n as assertWindowsDenyCapacity, t as DialectUnrecognizedError } from "./windows-runner-contract-
|
|
2
|
-
import { l as isCanonicallyUnder } from "./roots-
|
|
1
|
+
import { a as parseWindowsProfile, i as isWindowsNetworkOrDevicePath, n as assertWindowsDenyCapacity, t as DialectUnrecognizedError } from "./windows-runner-contract-B5R2K3mM.js";
|
|
2
|
+
import { l as isCanonicallyUnder } from "./roots-Ca_W1S9n.js";
|
|
3
3
|
import { brandMultiRootProvider } from "./providers.js";
|
|
4
4
|
import { posix } from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
5
|
import { SandboxUnavailableError, canonicalPath } from "@deepseek-ai/dsh-sandbox";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { LocalSandboxProvider } from "@deepseek-ai/dsh-sandbox-local";
|
|
8
8
|
//#region src/compat/sandbox-confine.ts
|
|
9
9
|
/** Whether a value is a thenable, i.e. whether the installed `confine` is async. */
|
package/lib/sandbox.js
CHANGED