@kuznai/inception-engine 0.23.0 → 0.24.0

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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ import assert from "node:assert/strict";
2
+ import { stripVTControlCharacters } from "node:util";
3
+ import { describe, it } from "node:test";
4
+ import { formatDryRunPlan } from "../../src/formatters.js";
5
+ function stripAnsi(value) {
6
+ return stripVTControlCharacters(value);
7
+ }
8
+ describe("formatDryRunPlan", () => {
9
+ it("returns an empty string when there are no planned changes", () => {
10
+ assert.equal(formatDryRunPlan([]), "");
11
+ });
12
+ it("groups changes by agent, sorts groups, and renders supported detail fields", () => {
13
+ const plan = [
14
+ {
15
+ agent: "opencode",
16
+ kind: "config-patch",
17
+ skill: "beta",
18
+ target: "/targets/opencode.json",
19
+ verb: "patch-config",
20
+ patch: { enabled: true },
21
+ },
22
+ {
23
+ agent: "claude-code",
24
+ kind: "file-write",
25
+ skill: "alpha",
26
+ source: "/source/alpha.md",
27
+ target: "/targets/alpha.md",
28
+ verb: "write-file",
29
+ },
30
+ {
31
+ agent: "claude-code",
32
+ kind: "config-patch",
33
+ skill: "gamma",
34
+ target: "/targets/gamma.json",
35
+ verb: "unapply-patch",
36
+ patch: { enabled: null },
37
+ },
38
+ {
39
+ agent: "claude-code",
40
+ kind: "toml-patch",
41
+ skill: "delta",
42
+ target: "/targets/delta.toml",
43
+ verb: "patch-toml",
44
+ patch: { approval_policy: "suggest" },
45
+ },
46
+ {
47
+ agent: "claude-code",
48
+ kind: "frontmatter-emit",
49
+ skill: "epsilon",
50
+ target: "/targets/epsilon.md",
51
+ verb: "emit-frontmatter",
52
+ frontmatter: { tools: ["github"] },
53
+ },
54
+ {
55
+ agent: "claude-code",
56
+ kind: "file-write",
57
+ skill: "zeta",
58
+ target: "/targets/zeta.md",
59
+ verb: "remove",
60
+ },
61
+ ];
62
+ const output = stripAnsi(formatDryRunPlan(plan));
63
+ assert.match(output, /^claude-code\n(?:[\s\S]*?)\nopencode\n/m, `expected claude-code group before opencode, got:\n${output}`);
64
+ assert.match(output, /write-file alpha/);
65
+ assert.match(output, /source: \/source\/alpha\.md/);
66
+ assert.match(output, /target: \/targets\/alpha\.md/);
67
+ assert.match(output, /undo:\s+\{"enabled":null\}/);
68
+ assert.match(output, /patch:\s+\{"approval_policy":"suggest"\}/);
69
+ assert.match(output, /frontmatter: \{"tools":\["github"\]\}/);
70
+ assert.match(output, /remove zeta/);
71
+ assert.doesNotMatch(output, /source: \/targets\/zeta\.md/);
72
+ assert.match(output, /patch-config beta/);
73
+ });
74
+ });
@@ -1,8 +1,8 @@
1
1
  import assert from "node:assert/strict";
2
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { describe, it } from "node:test";
5
- import { defaultRegistryPersistence, lookupDeployment, registerDeployment, registryPath, unregisterDeployment, verifyDeployment, } from "../../src/core/ownership.js";
5
+ import { defaultRegistryPersistence, lookupDeployment, registerDeployment, registryDirPath, registryPath, unregisterDeployment, verifyDeployment, } from "../../src/core/ownership.js";
6
6
  import { exists, makeTmpDir } from "../helpers/fs.js";
7
7
  describe("registerDeployment", () => {
8
8
  it("creates registry file and adds entry", async () => {
@@ -56,7 +56,7 @@ describe("registerDeployment", () => {
56
56
  await rm(home, { recursive: true });
57
57
  }
58
58
  });
59
- it("sets registry file permissions to 0o644 on POSIX", {
59
+ it("sets registry file permissions to 0o600 on POSIX", {
60
60
  skip: process.platform === "win32",
61
61
  }, async () => {
62
62
  const home = await makeTmpDir();
@@ -70,7 +70,27 @@ describe("registerDeployment", () => {
70
70
  });
71
71
  const { stat } = await import("node:fs/promises");
72
72
  const statResult = await stat(registryPath(home));
73
- assert.equal(statResult.mode & 0o777, 0o644);
73
+ assert.equal(statResult.mode & 0o777, 0o600);
74
+ }
75
+ finally {
76
+ await rm(home, { recursive: true });
77
+ }
78
+ });
79
+ it("sets registry directory permissions to 0o700 on POSIX", {
80
+ skip: process.platform === "win32",
81
+ }, async () => {
82
+ const home = await makeTmpDir();
83
+ try {
84
+ await registerDeployment(home, "/fake/target", {
85
+ kind: "skill-dir",
86
+ source: "/fake/source",
87
+ skill: "my-skill",
88
+ agent: "claude-code",
89
+ method: "symlink",
90
+ });
91
+ const { stat } = await import("node:fs/promises");
92
+ const statResult = await stat(registryDirPath(home));
93
+ assert.equal(statResult.mode & 0o777, 0o700);
74
94
  }
75
95
  finally {
76
96
  await rm(home, { recursive: true });
@@ -121,6 +141,26 @@ describe("registerDeployment", () => {
121
141
  await rm(home, { recursive: true, force: true });
122
142
  }
123
143
  });
144
+ it("refuses to write the registry through a symlinked state directory", {
145
+ skip: process.platform === "win32",
146
+ }, async () => {
147
+ const home = await makeTmpDir();
148
+ const elsewhere = await makeTmpDir();
149
+ try {
150
+ await symlink(elsewhere, registryDirPath(home), "dir");
151
+ await assert.rejects(registerDeployment(home, "/fake/target", {
152
+ kind: "skill-dir",
153
+ source: "/fake/source",
154
+ skill: "my-skill",
155
+ agent: "claude-code",
156
+ method: "copy",
157
+ }), /Refusing to use registry directory symlink/);
158
+ }
159
+ finally {
160
+ await rm(home, { recursive: true, force: true });
161
+ await rm(elsewhere, { recursive: true, force: true });
162
+ }
163
+ });
124
164
  });
125
165
  describe("unregisterDeployment", () => {
126
166
  it("removes the entry for the given target", async () => {
@@ -219,6 +259,23 @@ describe("lookupDeployment", () => {
219
259
  await rm(home, { recursive: true });
220
260
  }
221
261
  });
262
+ it("returns null when the registry file path is a symlink", {
263
+ skip: process.platform === "win32",
264
+ }, async () => {
265
+ const home = await makeTmpDir();
266
+ const elsewhere = await makeTmpDir();
267
+ try {
268
+ await mkdir(registryDirPath(home), { recursive: true });
269
+ await writeFile(path.join(elsewhere, "registry.json"), "{}");
270
+ await symlink(path.join(elsewhere, "registry.json"), registryPath(home), "file");
271
+ const entry = await lookupDeployment(home, "/anything");
272
+ assert.equal(entry, null);
273
+ }
274
+ finally {
275
+ await rm(home, { recursive: true, force: true });
276
+ await rm(elsewhere, { recursive: true, force: true });
277
+ }
278
+ });
222
279
  });
223
280
  describe("verifyDeployment", () => {
224
281
  it("returns entry when all fields match", async () => {
@@ -124,6 +124,65 @@ describe("runPreflight", () => {
124
124
  const implementationOnlyWarning = warnings.find((w) => w.kind === "config-authority" && /implementation-only/.test(w.message));
125
125
  assert.equal(implementationOnlyWarning, undefined, `expected no implementation-only warning, got: ${implementationOnlyWarning?.message}`);
126
126
  });
127
+ it("emits shared-surface config-authority guidance when github-copilot agentRules ride through claude-code", async () => {
128
+ const manifest = {
129
+ ...emptyManifest,
130
+ agentRules: [
131
+ {
132
+ name: "shared-rules",
133
+ path: "CLAUDE.md",
134
+ agents: ["claude-code", "github-copilot"],
135
+ scope: "repo",
136
+ },
137
+ ],
138
+ };
139
+ const warnings = await runPreflight(baseOptions, manifest, "/home/test", [
140
+ "claude-code",
141
+ "github-copilot",
142
+ ]);
143
+ const warning = warnings.find((w) => w.kind === "config-authority" &&
144
+ w.message.includes('shared through "claude-code"'));
145
+ assert.ok(warning, `expected shared-surface warning, got: ${JSON.stringify(warnings)}`);
146
+ assert.match(warning.message, /requires the primary target to deploy/);
147
+ });
148
+ it("emits shared-surface config-authority guidance for antigravity repo rules", async () => {
149
+ const manifest = {
150
+ ...emptyManifest,
151
+ agentRules: [
152
+ {
153
+ name: "gemini-rules",
154
+ path: "GEMINI.md",
155
+ agents: ["antigravity"],
156
+ scope: "repo",
157
+ },
158
+ ],
159
+ };
160
+ const warnings = await runPreflight(baseOptions, manifest, "/home/test", [
161
+ "antigravity",
162
+ ]);
163
+ const warning = warnings.find((w) => w.kind === "config-authority" &&
164
+ w.message.includes('shared through "gemini-cli"'));
165
+ assert.ok(warning, `expected antigravity shared-via warning, got: ${JSON.stringify(warnings)}`);
166
+ assert.doesNotMatch(warning.message, /requires the primary target to deploy/);
167
+ });
168
+ it("emits provisional config-authority warning for supported gemini executionConfigs", async () => {
169
+ const manifest = {
170
+ ...emptyManifest,
171
+ executionConfigs: [
172
+ {
173
+ name: "safe-mode",
174
+ agents: ["gemini-cli"],
175
+ config: { sandbox: "workspace-write" },
176
+ },
177
+ ],
178
+ };
179
+ const warnings = await runPreflight(baseOptions, manifest, "/home/test", [
180
+ "gemini-cli",
181
+ ]);
182
+ const capabilityWarning = warnings.find((w) => w.kind === "config-authority" && /execution-config/.test(w.message));
183
+ assert.ok(capabilityWarning, `expected executionConfig warning, got: ${JSON.stringify(warnings)}`);
184
+ assert.match(capabilityWarning.message, /provisional/);
185
+ });
127
186
  });
128
187
  describe("github-copilot devcontainer support", () => {
129
188
  it("emits no capability warning for devcontainer MCP when Copilot is detected and devcontainer scope is targeted", async () => {
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { describe, it } from "node:test";
5
5
  import { AGENT_REGISTRY } from "../../src/config/agents.js";
6
6
  import { resolveAgentDetectPath, resolveAgentSkillPath, resolveHome, } from "../../src/core/resolve.js";
7
- import { resolveTargetTemplate } from "../../src/core/runtime-paths.js";
7
+ import { resolveRuntimePaths, resolveTargetTemplate, } from "../../src/core/runtime-paths.js";
8
8
  import { UserError } from "../../src/errors.js";
9
9
  const posixJoin = path.posix.join;
10
10
  function getAgent(id) {
@@ -113,7 +113,73 @@ describe("resolveTargetTemplate", () => {
113
113
  const result = resolveTargetTemplate("{home}/.claude/settings.json", home);
114
114
  assert.equal(result, `${home}/.claude/settings.json`);
115
115
  });
116
+ it("resolves appdata, local_appdata, xdg_config, repo, and workspace roots", () => {
117
+ const savedAppData = process.env.APPDATA;
118
+ const savedLocalAppData = process.env.LOCALAPPDATA;
119
+ const savedXdg = process.env.XDG_CONFIG_HOME;
120
+ try {
121
+ process.env.APPDATA = "/env/appdata";
122
+ process.env.LOCALAPPDATA = "/env/local";
123
+ process.env.XDG_CONFIG_HOME = "/env/xdg";
124
+ assert.equal(resolveTargetTemplate("{appdata}/opencode/opencode.json", "/home/user"), "/env/appdata/opencode/opencode.json");
125
+ assert.equal(resolveTargetTemplate("{local_appdata}/Temp/config.json", "/home/user"), "/env/local/Temp/config.json");
126
+ assert.equal(resolveTargetTemplate("{xdg_config}/opencode/config.json", "/home/user"), "/env/xdg/opencode/config.json");
127
+ assert.equal(resolveTargetTemplate("{repo}/.claude/mcp.json", "/home/user", "/repo"), "/repo/.claude/mcp.json");
128
+ assert.equal(resolveTargetTemplate("{workspace}/CLAUDE.md", "/home/user", "/repo"), "/repo/CLAUDE.md");
129
+ assert.equal(resolveTargetTemplate("{workspace}/CLAUDE.md", "/home/user", "/repo", "/workspace"), "/workspace/CLAUDE.md");
130
+ assert.equal(resolveTargetTemplate("{home}", "/home/user"), "/home/user");
131
+ }
132
+ finally {
133
+ if (savedAppData === undefined)
134
+ delete process.env.APPDATA;
135
+ else
136
+ process.env.APPDATA = savedAppData;
137
+ if (savedLocalAppData === undefined)
138
+ delete process.env.LOCALAPPDATA;
139
+ else
140
+ process.env.LOCALAPPDATA = savedLocalAppData;
141
+ if (savedXdg === undefined)
142
+ delete process.env.XDG_CONFIG_HOME;
143
+ else
144
+ process.env.XDG_CONFIG_HOME = savedXdg;
145
+ }
146
+ });
147
+ it("throws for invalid templates and missing repo or workspace roots", () => {
148
+ assert.throws(() => resolveTargetTemplate("relative/path.txt", "/home/user"), /Invalid target template/);
149
+ assert.throws(() => resolveTargetTemplate("{repo}/x", "/home/user"), /no repo directory was provided/);
150
+ assert.throws(() => resolveTargetTemplate("{workspace}/x", "/home/user"), /no workspace directory was provided/);
151
+ });
116
152
  it("throws when the template escapes the placeholder root", () => {
117
153
  assert.throws(() => resolveTargetTemplate("{home}/../.ssh/config", "/home/user"), /outside its placeholder root/);
118
154
  });
119
155
  });
156
+ describe("resolveRuntimePaths", () => {
157
+ it("uses absolute env vars and ignores relative overrides", () => {
158
+ const savedAppData = process.env.APPDATA;
159
+ const savedLocalAppData = process.env.LOCALAPPDATA;
160
+ const savedXdg = process.env.XDG_CONFIG_HOME;
161
+ try {
162
+ process.env.APPDATA = "/custom/appdata";
163
+ process.env.LOCALAPPDATA = "relative/local";
164
+ process.env.XDG_CONFIG_HOME = "relative/xdg";
165
+ const paths = resolveRuntimePaths("/home/user");
166
+ assert.equal(paths.appdata, "/custom/appdata");
167
+ assert.equal(paths.localAppdata, "/home/user/AppData/Local");
168
+ assert.equal(paths.xdgConfig, "/home/user/.config");
169
+ }
170
+ finally {
171
+ if (savedAppData === undefined)
172
+ delete process.env.APPDATA;
173
+ else
174
+ process.env.APPDATA = savedAppData;
175
+ if (savedLocalAppData === undefined)
176
+ delete process.env.LOCALAPPDATA;
177
+ else
178
+ process.env.LOCALAPPDATA = savedLocalAppData;
179
+ if (savedXdg === undefined)
180
+ delete process.env.XDG_CONFIG_HOME;
181
+ else
182
+ process.env.XDG_CONFIG_HOME = savedXdg;
183
+ }
184
+ });
185
+ });
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { chmod, mkdir, readFile, rm, symlink, writeFile, } from "node:fs/promises";
2
+ import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { describe, it } from "node:test";
5
5
  import { lookupDeployment, registerDeployment, } from "../../src/core/ownership.js";
@@ -153,192 +153,28 @@ describe("planRevertAll", () => {
153
153
  action.skill === "gemini-safety"), "expected planRevertAll to include Gemini execution config revert action");
154
154
  });
155
155
  });
156
- describe("executeRevert", { skip: process.platform === "win32" }, () => {
157
- it("removes a symlink registered in the deployment registry", async () => {
156
+ describe("executeRevert reserved state protections", () => {
157
+ it("refuses to modify inception-engine state paths from manifest-managed actions", async () => {
158
158
  const home = await makeTmpDir();
159
- const sourceDir = await makeTmpDir();
160
159
  try {
161
- const actions = planRevert(testManifest, ["claude-code"], home);
162
- const target = actions[0]?.target;
163
- // Create symlink and register in registry
160
+ const target = path.join(home, ".inception-engine", "registry.json");
164
161
  await mkdir(path.dirname(target), { recursive: true });
165
- await symlink(sourceDir, target, "dir");
166
- await registerDeployment(home, target, {
167
- kind: "skill-dir",
168
- source: sourceDir,
169
- skill: "test-skill",
170
- agent: "claude-code",
171
- method: "symlink",
172
- });
173
- assert.ok(await exists(target));
174
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
175
- assert.equal(succeeded, 1);
176
- assert.equal(skipped, 0);
177
- assert.ok(!(await exists(target)));
178
- // Registry entry should be removed
179
- const entry = await lookupDeployment(home, target);
180
- assert.equal(entry, null);
181
- }
182
- finally {
183
- await rm(home, { recursive: true, force: true });
184
- await rm(sourceDir, { recursive: true });
185
- }
186
- });
187
- it("removes a copied directory registered in the deployment registry", async () => {
188
- const home = await makeTmpDir();
189
- try {
190
- const actions = planRevert(testManifest, ["claude-code"], home);
191
- const target = actions[0]?.target;
192
- await mkdir(target, { recursive: true });
193
- await writeFile(path.join(target, "SKILL.md"), "test");
194
- await registerDeployment(home, target, {
195
- kind: "skill-dir",
196
- source: "/original/source",
197
- skill: "test-skill",
198
- agent: "claude-code",
199
- method: "copy",
200
- });
201
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
202
- assert.equal(succeeded, 1);
203
- assert.equal(skipped, 0);
204
- assert.ok(!(await exists(target)));
205
- // Registry entry should be removed
206
- const entry = await lookupDeployment(home, target);
207
- assert.equal(entry, null);
208
- }
209
- finally {
210
- await rm(home, { recursive: true, force: true });
211
- }
212
- });
213
- it("skips missing targets", async () => {
214
- const home = await makeTmpDir();
215
- try {
216
- const actions = planRevert(testManifest, ["claude-code"], home);
217
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
218
- assert.equal(succeeded, 0);
219
- assert.equal(skipped, 1);
220
- }
221
- finally {
222
- await rm(home, { recursive: true });
223
- }
224
- });
225
- it("records a failure when removal is blocked by permissions", async () => {
226
- const home = await makeTmpDir();
227
- const sourceDir = await makeTmpDir();
228
- const actions = planRevert(testManifest, ["claude-code"], home);
229
- const target = actions[0]?.target ?? "";
230
- const targetParent = path.dirname(target);
231
- try {
232
- // Create the target directory and register it
233
- await mkdir(target, { recursive: true });
234
- await writeFile(path.join(target, "SKILL.md"), "test");
235
- await registerDeployment(home, target, {
236
- kind: "skill-dir",
237
- source: sourceDir,
238
- skill: "test-skill",
239
- agent: "claude-code",
240
- method: "copy",
241
- });
242
- // Make the parent directory non-writable so rm() fails
243
- await chmod(targetParent, 0o555);
244
- const { succeeded, skipped, failed } = await executeRevert(actions, false, false, home);
162
+ await writeFile(target, "{}");
163
+ const { failed, succeeded } = await executeRevert([
164
+ {
165
+ kind: "file-write",
166
+ skill: "state-target",
167
+ agent: "claude-code",
168
+ target,
169
+ },
170
+ ], false, false, home);
245
171
  assert.equal(succeeded, 0);
246
- assert.equal(skipped, 0);
247
172
  assert.equal(failed.length, 1);
248
- }
249
- finally {
250
- await chmod(targetParent, 0o755);
251
- await rm(home, { recursive: true, force: true });
252
- await rm(sourceDir, { recursive: true, force: true });
253
- }
254
- });
255
- it("does not remove in dry-run mode", async () => {
256
- const home = await makeTmpDir();
257
- const sourceDir = await makeTmpDir();
258
- try {
259
- const actions = planRevert(testManifest, ["claude-code"], home);
260
- const target = actions[0]?.target;
261
- await mkdir(path.dirname(target), { recursive: true });
262
- await symlink(sourceDir, target, "dir");
263
- await registerDeployment(home, target, {
264
- kind: "skill-dir",
265
- source: sourceDir,
266
- skill: "test-skill",
267
- agent: "claude-code",
268
- method: "symlink",
269
- });
270
- const { succeeded } = await executeRevert(actions, true, false, home);
271
- assert.equal(succeeded, 1);
272
- assert.ok(await exists(target), "symlink should still exist after dry-run");
273
- // Registry entry should still exist after dry-run
274
- const entry = await lookupDeployment(home, target);
275
- assert.ok(entry, "registry entry should still exist after dry-run");
276
- }
277
- finally {
278
- await rm(home, { recursive: true, force: true });
279
- await rm(sourceDir, { recursive: true });
280
- }
281
- });
282
- it("skips target that exists but is not in registry", async () => {
283
- const home = await makeTmpDir();
284
- const sourceDir = await makeTmpDir();
285
- try {
286
- const actions = planRevert(testManifest, ["claude-code"], home);
287
- const target = actions[0]?.target;
288
- // Create symlink but do NOT register — should be treated as unmanaged
289
- await writeFile(path.join(sourceDir, "SKILL.md"), "---");
290
- await mkdir(path.dirname(target), { recursive: true });
291
- await symlink(sourceDir, target, "dir");
292
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
293
- assert.equal(succeeded, 0);
294
- assert.equal(skipped, 1);
295
- assert.ok(await exists(target), "symlink should still exist — not managed");
296
- }
297
- finally {
298
- await rm(home, { recursive: true, force: true });
299
- await rm(sourceDir, { recursive: true });
300
- }
301
- });
302
- it("skips directory that exists but is not in registry", async () => {
303
- const home = await makeTmpDir();
304
- try {
305
- const actions = planRevert(testManifest, ["claude-code"], home);
306
- const target = actions[0]?.target;
307
- await mkdir(target, { recursive: true });
308
- await writeFile(path.join(target, "SKILL.md"), "user content");
309
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
310
- assert.equal(succeeded, 0);
311
- assert.equal(skipped, 1);
312
- assert.ok(await exists(target), "directory should still exist — not in registry");
313
- }
314
- finally {
315
- await rm(home, { recursive: true, force: true });
316
- }
317
- });
318
- it("skips target whose registry entry has mismatched skill or agent", async () => {
319
- const home = await makeTmpDir();
320
- const sourceDir = await makeTmpDir();
321
- try {
322
- const actions = planRevert(testManifest, ["claude-code"], home);
323
- const target = actions[0]?.target;
324
- // Create symlink and register under a different skill/agent
325
- await mkdir(path.dirname(target), { recursive: true });
326
- await symlink(sourceDir, target, "dir");
327
- await registerDeployment(home, target, {
328
- kind: "skill-dir",
329
- source: sourceDir,
330
- skill: "different-skill",
331
- agent: "codex",
332
- method: "symlink",
333
- });
334
- const { succeeded, skipped } = await executeRevert(actions, false, false, home);
335
- assert.equal(succeeded, 0);
336
- assert.equal(skipped, 1);
337
- assert.ok(await exists(target), "symlink should still exist — registry entry does not match");
173
+ assert.match(failed[0]?.error ?? "", /Refusing to modify inception-engine state directory/);
174
+ assert.equal(await readFile(target, "utf-8"), "{}");
338
175
  }
339
176
  finally {
340
177
  await rm(home, { recursive: true, force: true });
341
- await rm(sourceDir, { recursive: true });
342
178
  }
343
179
  });
344
180
  });
@@ -905,9 +741,7 @@ describe("planRevertAll — mcpServers and agentRules", () => {
905
741
  assert.ok(agents.includes("codex"));
906
742
  });
907
743
  });
908
- describe("executeRevert — mcpServer and agentRule integration", {
909
- skip: process.platform === "win32",
910
- }, () => {
744
+ describe("executeRevert — mcpServer and agentRule integration", () => {
911
745
  it("reverts a deployed mcpServer config-patch and unregisters it", async () => {
912
746
  const home = await makeTmpDir();
913
747
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuznai/inception-engine",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Deploy AI agent skills from a git repo to user home directories",
5
5
  "license": "MIT",
6
6
  "author": "Damian Piątkowski",