@diffexai/diffex 0.3.0 → 0.3.2

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 (96) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/cli/args.d.ts +2 -0
  3. package/dist/cli/args.js +39 -0
  4. package/dist/core/agent-session-services.d.ts +1 -0
  5. package/dist/core/agent-session-services.js +1 -0
  6. package/dist/core/agent-session.d.ts +4 -5
  7. package/dist/core/agent-session.js +11 -62
  8. package/dist/core/compaction/branch-summarization.js +3 -2
  9. package/dist/core/compaction/compaction.js +9 -7
  10. package/dist/core/compaction/utils.d.ts +3 -0
  11. package/dist/core/compaction/utils.js +21 -0
  12. package/dist/core/current-plan-state.d.ts +3 -2
  13. package/dist/core/current-plan-state.js +23 -6
  14. package/dist/core/plan-snapshot.d.ts +3 -0
  15. package/dist/core/plan-snapshot.js +23 -0
  16. package/dist/core/sdk.d.ts +3 -0
  17. package/dist/core/sdk.js +1 -0
  18. package/dist/core/session-manager.js +21 -1
  19. package/dist/core/subagents/services.d.ts +2 -0
  20. package/dist/core/subagents/services.js +2 -0
  21. package/dist/core/tools/bash.js +47 -12
  22. package/dist/core/tools/update-plan.d.ts +27 -6
  23. package/dist/core/tools/update-plan.js +122 -18
  24. package/dist/index.d.ts +1 -0
  25. package/dist/main.js +4 -0
  26. package/dist/modes/interactive/components/footer.js +16 -5
  27. package/dist/modes/interactive/components/tool-group.d.ts +1 -0
  28. package/dist/modes/interactive/components/tool-group.js +26 -7
  29. package/dist/modes/print-mode.js +16 -13
  30. package/dist/node_modules/@diffexai/diffex-agent-core/dist/agent-loop.js +21 -3
  31. package/dist/node_modules/@diffexai/diffex-agent-core/dist/types.d.ts +17 -10
  32. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-components.json +4 -4
  33. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-files.json +3 -3
  34. package/dist/node_modules/@diffexai/diffex-agent-core/package.json +1 -1
  35. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/.manifest.json +1 -1
  36. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/amazon-bedrock.json +1 -1
  37. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/anthropic.json +1 -1
  38. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/azure-openai-responses.json +1 -1
  39. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cerebras.json +1 -1
  40. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  41. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  42. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/fireworks.json +1 -1
  43. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/github-copilot.json +1 -1
  44. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google-vertex.json +1 -1
  45. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google.json +1 -1
  46. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/huggingface.json +1 -1
  47. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax-cn.json +1 -1
  48. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax.json +1 -1
  49. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/mistral.json +1 -1
  50. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai-cn.json +1 -1
  51. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai.json +1 -1
  52. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/nvidia.json +1 -1
  53. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openai.json +1 -1
  54. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode-go.json +1 -1
  55. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode.json +1 -1
  56. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openrouter.json +1 -1
  57. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/together.json +1 -1
  58. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  59. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xai.json +1 -1
  60. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  61. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  62. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  63. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi.json +1 -1
  64. package/dist/node_modules/@diffexai/diffex-ai/distribution-components.json +3 -3
  65. package/dist/node_modules/@diffexai/diffex-ai/distribution-files.json +30 -30
  66. package/dist/node_modules/@diffexai/diffex-ai/package.json +1 -1
  67. package/dist/node_modules/@diffexai/diffex-client/distribution-components.json +3 -3
  68. package/dist/node_modules/@diffexai/diffex-client/distribution-files.json +1 -1
  69. package/dist/node_modules/@diffexai/diffex-client/package.json +1 -1
  70. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-components.json +2 -2
  71. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-files.json +1 -1
  72. package/dist/node_modules/@diffexai/diffex-harness-state/package.json +1 -1
  73. package/dist/node_modules/@diffexai/diffex-protocol/distribution-components.json +2 -2
  74. package/dist/node_modules/@diffexai/diffex-protocol/distribution-files.json +1 -1
  75. package/dist/node_modules/@diffexai/diffex-protocol/package.json +1 -1
  76. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-components.json +2 -2
  77. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-files.json +1 -1
  78. package/dist/node_modules/@diffexai/diffex-telemetry/package.json +1 -1
  79. package/dist/node_modules/@diffexai/diffex-tui/distribution-components.json +2 -2
  80. package/dist/node_modules/@diffexai/diffex-tui/distribution-files.json +1 -1
  81. package/dist/node_modules/@diffexai/diffex-tui/package.json +1 -1
  82. package/dist/utils/child-process.d.ts +5 -1
  83. package/dist/utils/child-process.js +9 -1
  84. package/dist/utils/owned-shell-processes.d.ts +23 -2
  85. package/dist/utils/owned-shell-processes.js +149 -39
  86. package/dist/utils/shell-process-identity.d.ts +11 -0
  87. package/dist/utils/shell-process-identity.js +61 -0
  88. package/dist/utils/shell.d.ts +1 -1
  89. package/dist/utils/shell.js +5 -5
  90. package/distribution-components.json +11 -11
  91. package/distribution-files.json +101 -85
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +1 -1
  94. package/release/distribution-manifest.json +4 -4
  95. package/release/install-package-lock.json +5 -5
  96. package/release/install-package.json +2 -2
@@ -1,61 +1,171 @@
1
- import { spawnSync } from "node:child_process";
1
+ import { randomUUID } from "node:crypto";
2
+ import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { isAbsolute, join } from "node:path";
2
4
  import { setTimeout as delay } from "node:timers/promises";
3
5
  import { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from "./shell.js";
4
- function isAlive(pid) {
5
- try {
6
- process.kill(process.platform === "win32" ? pid : -pid, 0);
7
- return true;
8
- }
9
- catch (error) {
10
- if (error.code === "ESRCH")
11
- return false;
12
- if (error.code === "EPERM")
13
- return true;
14
- throw error;
15
- }
16
- }
17
- /** A session owns the process groups it launches, including background jobs. */
6
+ import { hasShellExecutionToken, readShellProcessGroup } from "./shell-process-identity.js";
7
+ /** Session ownership ends only after a successful, durably published handoff. */
18
8
  export class OwnedShellProcesses {
19
- #pids = new Set();
20
- track(pid) {
21
- this.#pids.add(pid);
22
- trackDetachedChildPid(pid);
9
+ policy;
10
+ #executions = new Map();
11
+ constructor(policy = { lifetime: "session" }) {
12
+ if (policy.lifetime !== "session" && policy.lifetime !== "environment") {
13
+ throw new Error("Invalid background process lifetime");
14
+ }
15
+ if (policy.lifetime === "environment") {
16
+ if (process.platform !== "linux" && process.platform !== "darwin") {
17
+ throw new Error("Environment background process ownership requires Linux or macOS");
18
+ }
19
+ if (!policy.ownershipDirectory || !isAbsolute(policy.ownershipDirectory)) {
20
+ throw new Error("Environment background process ownership requires an absolute ownershipDirectory");
21
+ }
22
+ mkdirSync(policy.ownershipDirectory, { recursive: true, mode: 0o700 });
23
+ }
24
+ this.policy = Object.freeze({ ...policy });
25
+ }
26
+ track(pid, executionId) {
27
+ const execution = { id: executionId, state: "active", members: [] };
28
+ this.#executions.set(pid, execution);
29
+ trackDetachedChildPid(pid, () => this.terminate(pid));
30
+ try {
31
+ execution.members = process.platform === "win32" ? [] : readShellProcessGroup(pid);
32
+ this.#publish(pid, execution, "session", "active");
33
+ }
34
+ catch (error) {
35
+ this.terminate(pid);
36
+ throw error;
37
+ }
38
+ }
39
+ /** Called synchronously on shell exit, before output draining or another event can cancel it. */
40
+ complete(pid, successful) {
41
+ const execution = this.#executions.get(pid);
42
+ if (!execution || execution.state !== "active")
43
+ return;
44
+ // This callback belongs to the ChildProcess just reaped by Node. Capture the
45
+ // surviving group now; later cleanup must validate these process identities.
46
+ execution.members = process.platform === "win32" ? [] : readShellProcessGroup(pid);
47
+ execution.state = "background";
48
+ if (!successful || this.policy.lifetime === "session")
49
+ return;
50
+ const members = this.#members(pid, execution);
51
+ if (members.length === 0) {
52
+ this.releaseIfExited(pid);
53
+ return;
54
+ }
55
+ execution.members = members;
56
+ // No await between publication and removing both cleanup registrations.
57
+ // Atomic rename is the ownership commit point, including after a forced CLI death.
58
+ this.#publish(pid, execution, "environment", "background");
59
+ this.#executions.delete(pid);
60
+ untrackDetachedChildPid(pid);
61
+ }
62
+ #publish(pid, execution, owner, state) {
63
+ if (this.policy.lifetime !== "environment")
64
+ return;
65
+ const record = {
66
+ version: 1,
67
+ executionId: execution.id,
68
+ owner,
69
+ state,
70
+ processGroupId: pid,
71
+ supervisorPid: process.pid,
72
+ members: execution.members,
73
+ };
74
+ const path = join(this.policy.ownershipDirectory, `${execution.id}.json`);
75
+ const temporary = `${path}.${randomUUID()}.tmp`;
76
+ const fd = openSync(temporary, "wx", 0o600);
77
+ try {
78
+ try {
79
+ writeFileSync(fd, `${JSON.stringify(record)}\n`);
80
+ fsyncSync(fd);
81
+ }
82
+ finally {
83
+ closeSync(fd);
84
+ }
85
+ renameSync(temporary, path);
86
+ }
87
+ finally {
88
+ try {
89
+ unlinkSync(temporary);
90
+ }
91
+ catch { }
92
+ }
93
+ }
94
+ #members(pid, execution) {
95
+ const members = readShellProcessGroup(pid);
96
+ if (members.length === 0)
97
+ return [];
98
+ const known = members.some((member) => execution.members.some((previous) => previous.pid === member.pid && previous.startTime === member.startTime));
99
+ if (!known && !members.some((member) => hasShellExecutionToken(member.pid, execution.id))) {
100
+ throw new Error(`Cannot verify ownership of shell process group ${pid}`);
101
+ }
102
+ return members;
103
+ }
104
+ terminate(pid) {
105
+ const execution = this.#executions.get(pid);
106
+ if (!execution)
107
+ return;
108
+ if (execution.state === "active" && process.platform !== "win32") {
109
+ // The launching ChildProcess has not delivered its exit event yet.
110
+ execution.members = readShellProcessGroup(pid);
111
+ }
112
+ execution.state = "terminating";
113
+ if (process.platform === "win32") {
114
+ killProcessTree(pid);
115
+ }
116
+ else if (this.#members(pid, execution).length > 0) {
117
+ // Never fall back to a recycled leader PID when its group has disappeared.
118
+ try {
119
+ process.kill(-pid, "SIGKILL");
120
+ }
121
+ catch (error) {
122
+ if (error.code !== "ESRCH")
123
+ throw error;
124
+ }
125
+ }
23
126
  }
24
127
  releaseIfExited(pid) {
25
- if (!isAlive(pid)) {
26
- this.#pids.delete(pid);
128
+ const execution = this.#executions.get(pid);
129
+ if (!execution)
130
+ return;
131
+ let alive;
132
+ if (process.platform === "win32") {
133
+ try {
134
+ process.kill(pid, 0);
135
+ alive = true;
136
+ }
137
+ catch {
138
+ alive = false;
139
+ }
140
+ }
141
+ else {
142
+ alive = this.#members(pid, execution).length > 0;
143
+ }
144
+ if (!alive) {
145
+ this.#publish(pid, execution, "session", "terminated");
146
+ this.#executions.delete(pid);
27
147
  untrackDetachedChildPid(pid);
28
148
  }
29
149
  }
30
150
  get count() {
31
- for (const pid of this.#pids)
151
+ for (const pid of this.#executions.keys())
32
152
  this.releaseIfExited(pid);
33
- return this.#pids.size;
153
+ return this.#executions.size;
34
154
  }
35
155
  async terminateAll() {
36
- const pids = [...this.#pids];
156
+ const pids = [...this.#executions.keys()];
37
157
  for (const pid of pids)
38
- killProcessTree(pid);
158
+ this.terminate(pid);
39
159
  const deadline = performance.now() + 5_000;
40
160
  for (const pid of pids) {
41
- while (isAlive(pid)) {
42
- // Linux PID 1 may leave orphaned zombies unreaped. Zombies are terminated,
43
- // but kill(0) still sees their process group until the parent reaps them.
44
- if (process.platform !== "win32") {
45
- const result = spawnSync("ps", ["-eo", "pgid=,stat="], { encoding: "utf8", timeout: 1_000 });
46
- if (result.status === 0 &&
47
- !result.stdout.split("\n").some((line) => {
48
- const [group, state] = line.trim().split(/\s+/);
49
- return Number(group) === pid && state && !state.startsWith("Z");
50
- }))
51
- break;
52
- }
161
+ while (this.#executions.has(pid)) {
162
+ this.releaseIfExited(pid);
163
+ if (!this.#executions.has(pid))
164
+ break;
53
165
  if (performance.now() >= deadline)
54
166
  throw new Error(`Shell process group ${pid} did not terminate`);
55
167
  await delay(25);
56
168
  }
57
- this.#pids.delete(pid);
58
- untrackDetachedChildPid(pid);
59
169
  }
60
170
  }
61
171
  }
@@ -0,0 +1,11 @@
1
+ export declare const SHELL_EXECUTION_ID_ENV = "DIFFEX_SHELL_EXECUTION_ID";
2
+ export interface ShellProcessIdentity {
3
+ readonly pid: number;
4
+ readonly processGroupId: number;
5
+ /** Linux boot ID and start ticks, or macOS ps lstart in UTC and the C locale. */
6
+ readonly startTime: string;
7
+ }
8
+ /** Read live group members without treating orphaned zombies as running work. */
9
+ export declare function readShellProcessGroup(processGroupId: number): ShellProcessIdentity[];
10
+ /** The launch token prevents a recycled group ID from authorizing a signal. */
11
+ export declare function hasShellExecutionToken(pid: number, executionId: string): boolean;
@@ -0,0 +1,61 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ export const SHELL_EXECUTION_ID_ENV = "DIFFEX_SHELL_EXECUTION_ID";
4
+ /** Read live group members without treating orphaned zombies as running work. */
5
+ export function readShellProcessGroup(processGroupId) {
6
+ if (process.platform === "linux") {
7
+ const bootId = readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
8
+ const members = [];
9
+ for (const name of readdirSync("/proc")) {
10
+ if (!/^\d+$/.test(name))
11
+ continue;
12
+ try {
13
+ const stat = readFileSync(`/proc/${name}/stat`, "utf8");
14
+ const fields = stat
15
+ .slice(stat.lastIndexOf(")") + 2)
16
+ .trim()
17
+ .split(/\s+/);
18
+ if (Number(fields[2]) !== processGroupId || fields[0] === "Z")
19
+ continue;
20
+ members.push({ pid: Number(name), processGroupId, startTime: `${bootId}:${fields[19]}` });
21
+ }
22
+ catch (error) {
23
+ if (["ENOENT", "ESRCH"].includes(error.code ?? ""))
24
+ continue;
25
+ throw error;
26
+ }
27
+ }
28
+ return members;
29
+ }
30
+ const result = spawnSync("ps", ["-axo", "pid=,pgid=,stat=,lstart="], {
31
+ encoding: "utf8",
32
+ timeout: 1_000,
33
+ env: { ...process.env, LC_ALL: "C", TZ: "UTC" },
34
+ });
35
+ if (result.status !== 0)
36
+ throw new Error("Cannot inspect shell process groups", { cause: result.error });
37
+ return result.stdout.split("\n").flatMap((line) => {
38
+ const [pid, group, state, ...started] = line.trim().split(/\s+/);
39
+ return Number(group) === processGroupId && state && !state.startsWith("Z")
40
+ ? [{ pid: Number(pid), processGroupId, startTime: started.join(" ") }]
41
+ : [];
42
+ });
43
+ }
44
+ /** The launch token prevents a recycled group ID from authorizing a signal. */
45
+ export function hasShellExecutionToken(pid, executionId) {
46
+ try {
47
+ const token = `${SHELL_EXECUTION_ID_ENV}=${executionId}`;
48
+ if (process.platform === "linux") {
49
+ return readFileSync(`/proc/${pid}/environ`, "utf8").split("\0").includes(token);
50
+ }
51
+ const result = spawnSync("ps", ["-Eww", "-p", String(pid), "-o", "command="], {
52
+ encoding: "utf8",
53
+ timeout: 1_000,
54
+ maxBuffer: 4 * 1024 * 1024,
55
+ });
56
+ return result.status === 0 && result.stdout.split(/\s+/).includes(token);
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
@@ -21,7 +21,7 @@ export declare function getShellEnv(): NodeJS.ProcessEnv;
21
21
  * - Characters with undefined code points
22
22
  */
23
23
  export declare function sanitizeBinaryOutput(str: string): string;
24
- export declare function trackDetachedChildPid(pid: number): void;
24
+ export declare function trackDetachedChildPid(pid: number, terminate?: () => void): void;
25
25
  export declare function untrackDetachedChildPid(pid: number): void;
26
26
  export declare function killTrackedDetachedChildren(): void;
27
27
  /**
@@ -153,16 +153,16 @@ export function sanitizeBinaryOutput(str) {
153
153
  * Detached child processes must be tracked so they can be killed on parent
154
154
  * shutdown signals (SIGHUP/SIGTERM).
155
155
  */
156
- const trackedDetachedChildPids = new Set();
157
- export function trackDetachedChildPid(pid) {
158
- trackedDetachedChildPids.add(pid);
156
+ const trackedDetachedChildPids = new Map();
157
+ export function trackDetachedChildPid(pid, terminate = () => killProcessTree(pid)) {
158
+ trackedDetachedChildPids.set(pid, terminate);
159
159
  }
160
160
  export function untrackDetachedChildPid(pid) {
161
161
  trackedDetachedChildPids.delete(pid);
162
162
  }
163
163
  export function killTrackedDetachedChildren() {
164
- for (const pid of trackedDetachedChildPids) {
165
- killProcessTree(pid);
164
+ for (const terminate of trackedDetachedChildPids.values()) {
165
+ terminate();
166
166
  }
167
167
  trackedDetachedChildPids.clear();
168
168
  }
@@ -1,8 +1,8 @@
1
1
  [
2
2
  {
3
3
  "name": "@diffexai/diffex",
4
- "version": "0.3.0",
5
- "sourceCommit": "c8cec4d3820393131eaae7b43d56ac5f75d8041a",
4
+ "version": "0.3.2",
5
+ "sourceCommit": "57dbba8a810d2e4cc81e48a30a4f5736e0e2d5bf",
6
6
  "license": "Apache-2.0",
7
7
  "portions": "Diffex contributions; Pi-derived portions retain MIT terms in LICENSE",
8
8
  "notice": "LICENSE",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  {
12
12
  "name": "@diffexai/diffex-evolution",
13
- "version": "0.3.0",
13
+ "version": "0.3.2",
14
14
  "license": "Apache-2.0",
15
15
  "portions": "dist/vendor/evolution: runtime JavaScript and declarations",
16
16
  "notice": "LICENSE",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "@diffexai/diffex-harness-trace",
21
- "version": "0.3.0",
21
+ "version": "0.3.2",
22
22
  "license": "Apache-2.0",
23
23
  "portions": "dist/vendor/harness-trace: runtime JavaScript and declarations",
24
24
  "notice": "LICENSE",
@@ -134,7 +134,7 @@
134
134
  },
135
135
  {
136
136
  "name": "@diffexai/diffex-agent-core",
137
- "version": "0.3.0",
137
+ "version": "0.3.2",
138
138
  "license": "Apache-2.0",
139
139
  "portions": "dist/node_modules/@diffexai/diffex-agent-core: bundled runtime, declarations, approved assets and native prebuilds",
140
140
  "notice": "dist/node_modules/@diffexai/diffex-agent-core/LICENSE",
@@ -142,7 +142,7 @@
142
142
  },
143
143
  {
144
144
  "name": "@diffexai/diffex-ai",
145
- "version": "0.3.0",
145
+ "version": "0.3.2",
146
146
  "license": "Apache-2.0",
147
147
  "portions": "dist/node_modules/@diffexai/diffex-ai: bundled runtime, declarations, approved assets and native prebuilds",
148
148
  "notice": "dist/node_modules/@diffexai/diffex-ai/LICENSE",
@@ -150,7 +150,7 @@
150
150
  },
151
151
  {
152
152
  "name": "@diffexai/diffex-client",
153
- "version": "0.3.0",
153
+ "version": "0.3.2",
154
154
  "license": "Apache-2.0",
155
155
  "portions": "dist/node_modules/@diffexai/diffex-client: bundled runtime, declarations, approved assets and native prebuilds",
156
156
  "notice": "dist/node_modules/@diffexai/diffex-client/LICENSE",
@@ -158,7 +158,7 @@
158
158
  },
159
159
  {
160
160
  "name": "@diffexai/diffex-harness-state",
161
- "version": "0.3.0",
161
+ "version": "0.3.2",
162
162
  "license": "Apache-2.0",
163
163
  "portions": "dist/node_modules/@diffexai/diffex-harness-state: bundled runtime, declarations, approved assets and native prebuilds",
164
164
  "notice": "dist/node_modules/@diffexai/diffex-harness-state/LICENSE",
@@ -166,7 +166,7 @@
166
166
  },
167
167
  {
168
168
  "name": "@diffexai/diffex-protocol",
169
- "version": "0.3.0",
169
+ "version": "0.3.2",
170
170
  "license": "Apache-2.0",
171
171
  "portions": "dist/node_modules/@diffexai/diffex-protocol: bundled runtime, declarations, approved assets and native prebuilds",
172
172
  "notice": "dist/node_modules/@diffexai/diffex-protocol/LICENSE",
@@ -174,7 +174,7 @@
174
174
  },
175
175
  {
176
176
  "name": "@diffexai/diffex-telemetry",
177
- "version": "0.3.0",
177
+ "version": "0.3.2",
178
178
  "license": "Apache-2.0",
179
179
  "portions": "dist/node_modules/@diffexai/diffex-telemetry: bundled runtime, declarations, approved assets and native prebuilds",
180
180
  "notice": "dist/node_modules/@diffexai/diffex-telemetry/LICENSE",
@@ -182,7 +182,7 @@
182
182
  },
183
183
  {
184
184
  "name": "@diffexai/diffex-tui",
185
- "version": "0.3.0",
185
+ "version": "0.3.2",
186
186
  "license": "Apache-2.0",
187
187
  "portions": "dist/node_modules/@diffexai/diffex-tui: bundled runtime, declarations, approved assets and native prebuilds",
188
188
  "notice": "dist/node_modules/@diffexai/diffex-tui/LICENSE",