@deepstrike/wasm 0.2.43 → 0.2.44

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.
@@ -18,7 +18,6 @@ export function restoreKernelRuntime(runtime, snapshot) {
18
18
  }, 1);
19
19
  kernelWireStates.set(runtime, { operationId, nextEventSequence });
20
20
  }
21
- let nextOperationSequence = 1;
22
21
  const kernelWireStates = new WeakMap();
23
22
  function tryParseJson(s) {
24
23
  try {
@@ -267,7 +266,10 @@ function mapKernelAction(raw) {
267
266
  function stepInput(runtime, event) {
268
267
  let state = kernelWireStates.get(runtime);
269
268
  if (!state) {
270
- state = { operationId: `wasm-operation-${nextOperationSequence++}`, nextEventSequence: 1 };
269
+ // Globally unique, never a process-local counter: durable session logs key the kernel
270
+ // genesis/transaction chains by (sessionId, operationId) and outlive this isolate, so a
271
+ // counter that restarts at 1 collides with a prior chain on the same session.
272
+ state = { operationId: `wasm-operation-${crypto.randomUUID()}`, nextEventSequence: 1 };
271
273
  kernelWireStates.set(runtime, state);
272
274
  }
273
275
  const correlatedEvent = event.kind === "cancel_operation"
@@ -43,14 +43,15 @@ export declare class LargeResultSpool {
43
43
  private writeToDriver;
44
44
  private generatePreview;
45
45
  processToolResult(result: ToolResult): Promise<SpooledToolResult>;
46
- persistOutput(callId: string, content: string): Promise<string>;
46
+ private callKey;
47
+ persistOutput(sessionId: string, callId: string, content: string): Promise<string>;
47
48
  readSpooledResult(spoolRef: string): Promise<string>;
48
49
  /**
49
50
  * O7: locate a spooled output by the tool call's id (the `read_result` meta-tool only knows
50
51
  * `call_id`, not the content-hashed key `persistOutput` chose). Scans the driver's key list for
51
- * the `.spool/${callId}-*.txt` naming convention; returns `undefined` if nothing was ever
52
+ * the hashed session-scoped call-key prefix; returns `undefined` if nothing was ever
52
53
  * spooled for that call.
53
54
  */
54
- findByCallId(callId: string): Promise<string | undefined>;
55
+ findByCallId(sessionId: string, callId: string): Promise<string | undefined>;
55
56
  cleanup(maxAgeMs?: number): Promise<number>;
56
57
  }
@@ -92,9 +92,16 @@ omitted: ${omitted} chars
92
92
  wasSpooled: true,
93
93
  };
94
94
  }
95
- async persistOutput(callId, content) {
95
+ callKey(sessionId, callId) {
96
+ // Session-scoped and hashed: the driver's key space is shared across sessions and outlives
97
+ // runs, while vendor call ids can be index-style ("call_0") and repeat — an unscoped key
98
+ // lets read_result in one session fetch another session's spooled output. Hashing also keeps
99
+ // untrusted call-id characters out of driver keys (parity with Node/Python).
100
+ return simpleHash(`${sessionId}\u0000${callId}`);
101
+ }
102
+ async persistOutput(sessionId, callId, content) {
96
103
  const hash = simpleHash(content);
97
- const key = `.spool/${callId}-${hash.slice(0, 16)}.txt`;
104
+ const key = `.spool/${this.callKey(sessionId, callId)}-${hash.slice(0, 16)}.txt`;
98
105
  let promise = this.activeWrites.get(key);
99
106
  if (!promise) {
100
107
  promise = (async () => {
@@ -116,10 +123,10 @@ omitted: ${omitted} chars
116
123
  /**
117
124
  * O7: locate a spooled output by the tool call's id (the `read_result` meta-tool only knows
118
125
  * `call_id`, not the content-hashed key `persistOutput` chose). Scans the driver's key list for
119
- * the `.spool/${callId}-*.txt` naming convention; returns `undefined` if nothing was ever
126
+ * the hashed session-scoped call-key prefix; returns `undefined` if nothing was ever
120
127
  * spooled for that call.
121
128
  */
122
- async findByCallId(callId) {
129
+ async findByCallId(sessionId, callId) {
123
130
  let keys;
124
131
  try {
125
132
  keys = await this.driver.list();
@@ -127,7 +134,7 @@ omitted: ${omitted} chars
127
134
  catch {
128
135
  return undefined;
129
136
  }
130
- const prefix = `.spool/${callId}-`;
137
+ const prefix = `.spool/${this.callKey(sessionId, callId)}-`;
131
138
  const match = keys.find(k => k.startsWith(prefix) && k.endsWith('.txt'));
132
139
  if (!match)
133
140
  return undefined;
@@ -358,7 +358,7 @@ export class RuntimeRunner {
358
358
  let full;
359
359
  if (full === undefined && this.opts.resultSpool) {
360
360
  try {
361
- full = await this.opts.resultSpool.findByCallId(callId);
361
+ full = await this.opts.resultSpool.findByCallId(sessionId, callId);
362
362
  }
363
363
  catch {
364
364
  full = undefined;
@@ -807,7 +807,7 @@ export class RuntimeRunner {
807
807
  let spoolRef;
808
808
  let error;
809
809
  try {
810
- spoolRef = await spool.persistOutput(action.callId, action.output);
810
+ spoolRef = await spool.persistOutput(sessionId, action.callId, action.output);
811
811
  }
812
812
  catch (cause) {
813
813
  error = formatToolError(cause);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/wasm",
3
- "version": "0.2.43",
3
+ "version": "0.2.44",
4
4
  "description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "test": "node --experimental-vm-modules node_modules/.bin/jest"
16
16
  },
17
17
  "dependencies": {
18
- "@deepstrike/wasm-kernel": "0.2.43"
18
+ "@deepstrike/wasm-kernel": "0.2.44"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/jest": "^30.0.0",