@kuznai/inception-engine 0.22.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.
Files changed (43) hide show
  1. package/README.md +50 -9
  2. package/dist/src/config/agents.js +39 -0
  3. package/dist/src/core/adapters/execution-config.d.ts +14 -0
  4. package/dist/src/core/adapters/execution-config.js +60 -0
  5. package/dist/src/core/adapters/index.d.ts +4 -3
  6. package/dist/src/core/adapters/index.js +7 -5
  7. package/dist/src/core/adapters/rules.js +50 -19
  8. package/dist/src/core/capabilities.d.ts +1 -1
  9. package/dist/src/core/capabilities.js +18 -2
  10. package/dist/src/core/deploy.js +66 -2
  11. package/dist/src/core/init.js +69 -13
  12. package/dist/src/core/ownership.d.ts +1 -0
  13. package/dist/src/core/ownership.js +34 -4
  14. package/dist/src/core/preflight.js +28 -0
  15. package/dist/src/core/revert.js +86 -18
  16. package/dist/src/core/validation.d.ts +1 -1
  17. package/dist/src/core/validation.js +56 -3
  18. package/dist/src/schemas/manifest.d.ts +31 -0
  19. package/dist/src/schemas/manifest.js +39 -3
  20. package/dist/src/types.d.ts +6 -2
  21. package/dist/test/helpers/path.d.ts +2 -2
  22. package/dist/test/helpers/path.js +3 -3
  23. package/dist/test/os/posix/deploy.test.js +395 -0
  24. package/dist/test/os/posix/revert.test.js +188 -0
  25. package/dist/test/os/windows/deploy.test.d.ts +1 -0
  26. package/dist/test/os/windows/deploy.test.js +238 -0
  27. package/dist/test/unit/adapters.test.js +402 -2
  28. package/dist/test/unit/capabilities.test.js +44 -1
  29. package/dist/test/unit/cli.test.js +162 -0
  30. package/dist/test/unit/deploy.test.js +88 -647
  31. package/dist/test/unit/formatters.test.d.ts +1 -0
  32. package/dist/test/unit/formatters.test.js +74 -0
  33. package/dist/test/unit/init-fixture.test.js +85 -1
  34. package/dist/test/unit/manifest.test.js +72 -0
  35. package/dist/test/unit/ownership.test.js +61 -4
  36. package/dist/test/unit/preflight.test.js +145 -0
  37. package/dist/test/unit/resolve.test.js +67 -1
  38. package/dist/test/unit/revert.test.js +81 -182
  39. package/package.json +1 -1
  40. package/dist/test/os/windows/agentRules-integration.test.js +0 -245
  41. package/dist/test/os/windows/revert-integration.test.js +0 -72
  42. /package/dist/test/os/{windows/agentRules-integration.test.d.ts → posix/deploy.test.d.ts} +0 -0
  43. /package/dist/test/os/{windows/revert-integration.test.d.ts → posix/revert.test.d.ts} +0 -0
@@ -244,6 +244,21 @@ describe("init command", () => {
244
244
  await rm(dir, { recursive: true });
245
245
  }
246
246
  });
247
+ it("skips skill directories whose folder name is not a valid skill name", async () => {
248
+ const dir = await makeTmpDir();
249
+ try {
250
+ await mkdir(path.join(dir, "-bad-skill"), { recursive: true });
251
+ await writeFile(path.join(dir, "-bad-skill", "SKILL.md"), "---\nname: bad\ndescription: test\n---\n");
252
+ const { stdout, code } = await run(["init", dir]);
253
+ assert.equal(code, 0);
254
+ assert.ok(stdout.includes("not a valid skill name"), `expected invalid-skill warning, got: ${stdout}`);
255
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
256
+ assert.deepEqual(manifest.skills, []);
257
+ }
258
+ finally {
259
+ await rm(dir, { recursive: true });
260
+ }
261
+ });
247
262
  it("generated manifest always includes all five section keys", async () => {
248
263
  const dir = await makeTmpDir();
249
264
  try {
@@ -348,6 +363,20 @@ describe("init command", () => {
348
363
  await rm(dir, { recursive: true });
349
364
  }
350
365
  });
366
+ it("skips agentRules files whose basename cannot derive a valid name", async () => {
367
+ const dir = await makeTmpDir();
368
+ try {
369
+ await writeFile(path.join(dir, "-.md"), "# invalid rules\n");
370
+ const { code, stdout } = await run(["init", dir]);
371
+ assert.equal(code, 0);
372
+ assert.ok(stdout.includes("could not derive a valid agentRules name"), `expected invalid agentRules warning, got: ${stdout}`);
373
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
374
+ assert.deepEqual(manifest.agentRules, []);
375
+ }
376
+ finally {
377
+ await rm(dir, { recursive: true });
378
+ }
379
+ });
351
380
  it("agentRules name collision with skill gets -rules suffix", async () => {
352
381
  const dir = await makeTmpDir();
353
382
  try {
@@ -831,4 +860,137 @@ describe("init command", () => {
831
860
  await rm(dir, { recursive: true });
832
861
  }
833
862
  });
863
+ it("skips invalid agentDefinition file names and renames colliding discovered definitions", async () => {
864
+ const dir = await makeTmpDir();
865
+ try {
866
+ await mkdir(path.join(dir, "helper"), { recursive: true });
867
+ await writeFile(path.join(dir, "helper", "SKILL.md"), "---\nname: helper\ndescription: helper skill\n---\n");
868
+ await mkdir(path.join(dir, ".claude", "agents"), { recursive: true });
869
+ await writeFile(path.join(dir, ".claude", "agents", "helper.md"), "---\nname: helper\ndescription: helper agent\n---\n# Helper\n");
870
+ await writeFile(path.join(dir, ".claude", "agents", "-.md"), "---\nname: invalid\ndescription: invalid agent\n---\n# Invalid\n");
871
+ const { code, stdout } = await run(["init", dir]);
872
+ assert.equal(code, 0);
873
+ assert.ok(stdout.includes('agentDefinitions name "helper" collides'), `expected collision warning, got: ${stdout}`);
874
+ assert.ok(stdout.includes("could not derive a valid agentDefinitions name"), `expected invalid agentDefinitions warning, got: ${stdout}`);
875
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
876
+ assert.deepEqual(manifest.agentDefinitions.map((entry) => entry.name), ["helper-agent"]);
877
+ assert.ok(normalizeSlashes(manifest.agentDefinitions[0]?.path ?? "").includes(".claude/agents/helper.md"));
878
+ }
879
+ finally {
880
+ await rm(dir, { recursive: true });
881
+ }
882
+ });
883
+ it("agent-definitions-manifest.json takes precedence over discovered definitions", async () => {
884
+ const dir = await makeTmpDir();
885
+ try {
886
+ await mkdir(path.join(dir, ".claude", "agents"), { recursive: true });
887
+ await writeFile(path.join(dir, ".claude", "agents", "discovered.md"), "---\nname: discovered\ndescription: discovered agent\n---\n# Discovered\n");
888
+ await writeFile(path.join(dir, "agent-definitions-manifest.json"), JSON.stringify([
889
+ {
890
+ name: "sidecar-agent",
891
+ path: "agents/sidecar-agent.md",
892
+ agents: ["opencode"],
893
+ scope: "repo",
894
+ },
895
+ ]));
896
+ const { code } = await run(["init", dir]);
897
+ assert.equal(code, 0);
898
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
899
+ assert.deepEqual(manifest.agentDefinitions, [
900
+ {
901
+ name: "sidecar-agent",
902
+ path: "agents/sidecar-agent.md",
903
+ agents: ["opencode"],
904
+ scope: "repo",
905
+ },
906
+ ]);
907
+ }
908
+ finally {
909
+ await rm(dir, { recursive: true });
910
+ }
911
+ });
912
+ it("invalid JSON in agent-definitions-manifest.json produces discovered definitions and a warning", async () => {
913
+ const dir = await makeTmpDir();
914
+ try {
915
+ await mkdir(path.join(dir, ".claude", "agents"), { recursive: true });
916
+ await writeFile(path.join(dir, ".claude", "agents", "discovered.md"), "---\nname: discovered\ndescription: discovered agent\n---\n# Discovered\n");
917
+ await writeFile(path.join(dir, "agent-definitions-manifest.json"), "{not json}");
918
+ const { code, stdout } = await run(["init", dir]);
919
+ assert.equal(code, 0);
920
+ assert.ok(stdout.includes("agent-definitions-manifest.json"), "stdout should mention agent-definitions-manifest.json warning");
921
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
922
+ assert.equal(manifest.agentDefinitions.length, 1);
923
+ assert.equal(manifest.agentDefinitions[0]?.name, "discovered");
924
+ }
925
+ finally {
926
+ await rm(dir, { recursive: true });
927
+ }
928
+ });
929
+ it("non-array agent-definitions-manifest.json produces discovered definitions and a warning", async () => {
930
+ const dir = await makeTmpDir();
931
+ try {
932
+ await mkdir(path.join(dir, ".claude", "agents"), { recursive: true });
933
+ await writeFile(path.join(dir, ".claude", "agents", "discovered.md"), "---\nname: discovered\ndescription: discovered agent\n---\n# Discovered\n");
934
+ await writeFile(path.join(dir, "agent-definitions-manifest.json"), JSON.stringify({ name: "not-an-array" }));
935
+ const { code, stdout } = await run(["init", dir]);
936
+ assert.equal(code, 0);
937
+ assert.ok(stdout.includes("agent-definitions-manifest.json"), "stdout should mention agent-definitions-manifest.json warning");
938
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
939
+ assert.equal(manifest.agentDefinitions.length, 1);
940
+ assert.equal(manifest.agentDefinitions[0]?.name, "discovered");
941
+ }
942
+ finally {
943
+ await rm(dir, { recursive: true });
944
+ }
945
+ });
946
+ it("agent-definitions-manifest.json with mixed valid and invalid entries keeps only valid sidecar entries", async () => {
947
+ const dir = await makeTmpDir();
948
+ try {
949
+ await writeFile(path.join(dir, "agent-definitions-manifest.json"), JSON.stringify([
950
+ {
951
+ name: "valid-agent",
952
+ path: "agents/valid-agent.md",
953
+ agents: ["claude-code"],
954
+ scope: "repo",
955
+ },
956
+ { name: "invalid-agent" },
957
+ ]));
958
+ const { code, stdout } = await run(["init", dir]);
959
+ assert.equal(code, 0);
960
+ assert.ok(stdout.includes("agent-definitions-manifest.json"), "stdout should mention invalid agent-definitions-manifest.json entry");
961
+ const manifest = JSON.parse((await import("node:fs/promises").then((m) => m.readFile(path.join(dir, "inception.json"), "utf-8"))).toString());
962
+ assert.equal(manifest.agentDefinitions.length, 1);
963
+ assert.equal(manifest.agentDefinitions[0]?.name, "valid-agent");
964
+ assert.deepEqual(manifest.agentDefinitions[0]?.agents, ["claude-code"]);
965
+ }
966
+ finally {
967
+ await rm(dir, { recursive: true });
968
+ }
969
+ });
970
+ it("verbose init output includes detailed discovered sections", async () => {
971
+ const dir = await makeTmpDir();
972
+ try {
973
+ await mkdir(path.join(dir, "alpha"), { recursive: true });
974
+ await writeFile(path.join(dir, "alpha", "SKILL.md"), "---\nname: alpha\ndescription: test\n---\n");
975
+ await writeFile(path.join(dir, "CLAUDE.md"), "# rules\n");
976
+ await mkdir(path.join(dir, ".claude", "agents"), { recursive: true });
977
+ await writeFile(path.join(dir, ".claude", "agents", "reviewer.md"), "---\nname: reviewer\ndescription: test\n---\n# Agent\n");
978
+ await writeFile(path.join(dir, "mcp-servers.json"), JSON.stringify([
979
+ {
980
+ name: "my-server",
981
+ agents: ["claude-code"],
982
+ config: { command: "npx" },
983
+ },
984
+ ]));
985
+ const { code, stdout } = await run(["init", dir, "--verbose"]);
986
+ assert.equal(code, 0);
987
+ assert.ok(stdout.includes("alpha → alpha"), stdout);
988
+ assert.ok(stdout.includes("agentRules:"), stdout);
989
+ assert.ok(stdout.includes("agentDefinitions:"), stdout);
990
+ assert.ok(stdout.includes("mcpServers:"), stdout);
991
+ }
992
+ finally {
993
+ await rm(dir, { recursive: true });
994
+ }
995
+ });
834
996
  });