@huaweidevtools/aishell-dsh-e2b 0.0.11 → 0.0.12

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/lib/index.js CHANGED
@@ -1610,6 +1610,37 @@ function sessionOf(exec) {
1610
1610
  return exec.agent?.session?.id;
1611
1611
  }
1612
1612
  /**
1613
+ * Path-resolution options for a call, anchored at the session's directory.
1614
+ *
1615
+ * Without this a relative path resolves against the filesystem backend's own
1616
+ * default — `process.cwd()`, the directory the host was launched from — which
1617
+ * has nothing to do with the working directory the person picked for this
1618
+ * session. Every other filesystem tool in the product anchors at the session,
1619
+ * so a relative `localPath` means the same thing here as it does in a shell
1620
+ * running in that session.
1621
+ *
1622
+ * `ensure` rather than `get`: it returns an absolute directory and validates
1623
+ * that it still exists, restoring the original project when it has been
1624
+ * removed. `get` is cheaper but is a pure read, so a deleted directory would be
1625
+ * handed back and every write under it would fail.
1626
+ *
1627
+ * Both the service and the agent are optional, and their absence is not an
1628
+ * error: a call outside an agent, or a deployment without the service, falls
1629
+ * back to the backend's own default rather than refusing to write.
1630
+ *
1631
+ * @param deps - the tool dependencies, for the working-directory service.
1632
+ * @param exec - the call, for its owning agent and cancellation.
1633
+ */
1634
+ async function sessionResolveOptions(deps, exec) {
1635
+ const service = deps.resolveWorkingDirectory();
1636
+ const agent = exec.agent;
1637
+ const cwd = service === void 0 || agent === void 0 ? void 0 : await service.ensure(agent, exec.signal);
1638
+ return {
1639
+ ...cwd === void 0 ? {} : { cwd },
1640
+ signal: exec.signal
1641
+ };
1642
+ }
1643
+ /**
1613
1644
  * Register every sandbox tool.
1614
1645
  *
1615
1646
  * @param ctx - the plugin context, providing the tool registry.
@@ -2212,7 +2243,7 @@ function downloadFileTool(deps, ctx) {
2212
2243
  localPath: {
2213
2244
  type: "string",
2214
2245
  required: true,
2215
- description: "Destination path in the local workspace. Ignored for a binary file, which cannot be written there."
2246
+ description: "Destination in the local workspace. A relative path resolves against the session's working directory, and missing parent directories are created. Ignored for a binary file, which cannot be written there."
2216
2247
  }
2217
2248
  },
2218
2249
  output: {
@@ -2265,7 +2296,7 @@ function downloadFileTool(deps, ctx) {
2265
2296
  content: Buffer.from(bytes).toString("base64")
2266
2297
  };
2267
2298
  const text = Buffer.from(bytes).toString("utf8");
2268
- const target = await fs.resolve(input.localPath, { signal: exec.signal });
2299
+ const target = await fs.resolve(input.localPath, await sessionResolveOptions(deps, exec));
2269
2300
  await fs.writeText(target, text, void 0, exec.signal);
2270
2301
  return {
2271
2302
  path: input.path,
@@ -2533,7 +2564,8 @@ function apply(ctx, config) {
2533
2564
  const disposers = registerSandboxTools(ctx, {
2534
2565
  client,
2535
2566
  registry,
2536
- resolveFs: () => ctx.get("fs")
2567
+ resolveFs: () => ctx.get("fs"),
2568
+ resolveWorkingDirectory: () => ctx.get("workingDirectory")
2537
2569
  });
2538
2570
  ctx.effect(() => () => {
2539
2571
  for (const dispose of disposers) dispose();
@@ -34,6 +34,33 @@ export interface ToolDeps {
34
34
  readonly registry: SandboxRegistry;
35
35
  /** The filesystem the local workspace is reached through, when one is mounted. */
36
36
  readonly resolveFs: () => Context['fs'] | undefined;
37
+ /**
38
+ * The session working-directory service, when one is mounted.
39
+ *
40
+ * A thunk like {@link resolveFs}, and optional for the same reason: a
41
+ * deployment without it loses one behaviour (where a relative destination
42
+ * lands) rather than failing to mount.
43
+ */
44
+ readonly resolveWorkingDirectory: () => SessionDirectories | undefined;
45
+ }
46
+ /**
47
+ * The working-directory service, as this plugin needs it.
48
+ *
49
+ * Structural rather than imported, for the same reason {@link sessionOf} is:
50
+ * importing `@deepseek-ai/dsh-working-directory` for the type would add a
51
+ * framework dependency whose own `schemastery` pin differs from this package's,
52
+ * and the resulting duplicate copy leaks into the emitted `.d.ts` through a
53
+ * `.pnpm/…` path nobody installing this package has. One method is all that is
54
+ * used, so one method is all that is declared.
55
+ */
56
+ export interface SessionDirectories {
57
+ /**
58
+ * The session's effective absolute directory, validated.
59
+ *
60
+ * @param agent - the agent owning the session.
61
+ * @param signal - cancellation for the filesystem inspection.
62
+ */
63
+ readonly ensure: (agent: object, signal?: AbortSignal) => Promise<string>;
37
64
  }
38
65
  /**
39
66
  * Register every sandbox tool.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@huaweidevtools/aishell-dsh-e2b",
3
3
  "description": "Runs throwaway and preview deployments in E2B sandboxes on DSH — sandbox lifecycle, commands, and files as tools",
4
- "version": "0.0.11",
4
+ "version": "0.0.12",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,7 +27,7 @@
27
27
  "license": "Apache-2.0",
28
28
  "dependencies": {
29
29
  "e2b": "2.59.0",
30
- "@huaweidevtools/aishell-dsh-credentials-store": "0.0.11"
30
+ "@huaweidevtools/aishell-dsh-credentials-store": "0.0.12"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@deepseek-ai/cordis": "^4.0.4",