@kuznai/inception-engine 0.19.0 → 0.20.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 (105) hide show
  1. package/README.md +48 -22
  2. package/dist/{config → src/config}/agents.js +87 -14
  3. package/dist/{core → src/core}/adapters/agent-definitions.d.ts +0 -12
  4. package/dist/src/core/adapters/agent-definitions.js +162 -0
  5. package/dist/{core → src/core}/adapters/frontmatter.d.ts +10 -0
  6. package/dist/{core → src/core}/adapters/frontmatter.js +23 -6
  7. package/dist/{core → src/core}/adapters/mcp.js +17 -20
  8. package/dist/{core → src/core}/adapters/permissions.js +16 -20
  9. package/dist/{core → src/core}/adapters/rules.js +26 -50
  10. package/dist/src/core/capabilities.d.ts +47 -0
  11. package/dist/src/core/capabilities.js +280 -0
  12. package/dist/{core → src/core}/deploy.js +70 -41
  13. package/dist/{core → src/core}/init.js +18 -24
  14. package/dist/src/core/merge-patch.d.ts +4 -0
  15. package/dist/src/core/merge-patch.js +46 -0
  16. package/dist/{core → src/core}/ownership.js +13 -0
  17. package/dist/{core → src/core}/preflight.js +141 -29
  18. package/dist/{core → src/core}/revert.js +86 -26
  19. package/dist/{core → src/core}/validation.js +20 -0
  20. package/dist/{schemas → src/schemas}/manifest.d.ts +20 -0
  21. package/dist/{schemas → src/schemas}/manifest.js +11 -0
  22. package/dist/{schemas → src/schemas}/registry.d.ts +36 -0
  23. package/dist/{schemas → src/schemas}/registry.js +12 -4
  24. package/dist/{types.d.ts → src/types.d.ts} +13 -0
  25. package/dist/test/helpers/fs.d.ts +2 -0
  26. package/dist/test/helpers/fs.js +17 -0
  27. package/dist/test/helpers/path.d.ts +10 -0
  28. package/dist/test/helpers/path.js +15 -0
  29. package/dist/test/helpers/skill-dir-scenarios.d.ts +7 -0
  30. package/dist/test/helpers/skill-dir-scenarios.js +206 -0
  31. package/dist/test/helpers/skill-dir.d.ts +7 -0
  32. package/dist/test/helpers/skill-dir.js +46 -0
  33. package/dist/test/os/cross-platform/cross-platform.test.d.ts +1 -0
  34. package/dist/test/os/cross-platform/cross-platform.test.js +328 -0
  35. package/dist/test/os/posix/skill-dir.test.d.ts +1 -0
  36. package/dist/test/os/posix/skill-dir.test.js +19 -0
  37. package/dist/test/os/windows/revert-integration.test.d.ts +1 -0
  38. package/dist/test/os/windows/revert-integration.test.js +72 -0
  39. package/dist/test/os/windows/skill-dir.test.d.ts +1 -0
  40. package/dist/test/os/windows/skill-dir.test.js +19 -0
  41. package/dist/test/unit/adapters.test.d.ts +1 -0
  42. package/dist/test/unit/adapters.test.js +947 -0
  43. package/dist/test/unit/capabilities.test.d.ts +1 -0
  44. package/dist/test/unit/capabilities.test.js +71 -0
  45. package/dist/test/unit/cli.test.d.ts +1 -0
  46. package/dist/test/unit/cli.test.js +834 -0
  47. package/dist/test/unit/deploy.test.d.ts +1 -0
  48. package/dist/test/unit/deploy.test.js +2481 -0
  49. package/dist/test/unit/detect.test.d.ts +1 -0
  50. package/dist/test/unit/detect.test.js +192 -0
  51. package/dist/test/unit/enterprise.test.d.ts +1 -0
  52. package/dist/test/unit/enterprise.test.js +106 -0
  53. package/dist/test/unit/frontmatter.test.d.ts +1 -0
  54. package/dist/test/unit/frontmatter.test.js +102 -0
  55. package/dist/test/unit/gemini-north-star.test.d.ts +1 -0
  56. package/dist/test/unit/gemini-north-star.test.js +243 -0
  57. package/dist/test/unit/manifest.test.d.ts +1 -0
  58. package/dist/test/unit/manifest.test.js +737 -0
  59. package/dist/test/unit/migration-golden.test.d.ts +1 -0
  60. package/dist/test/unit/migration-golden.test.js +197 -0
  61. package/dist/test/unit/ownership.test.d.ts +1 -0
  62. package/dist/test/unit/ownership.test.js +587 -0
  63. package/dist/test/unit/preflight.test.d.ts +1 -0
  64. package/dist/test/unit/preflight.test.js +501 -0
  65. package/dist/test/unit/resolve.test.d.ts +1 -0
  66. package/dist/test/unit/resolve.test.js +119 -0
  67. package/dist/test/unit/revert.test.d.ts +1 -0
  68. package/dist/test/unit/revert.test.js +1004 -0
  69. package/dist/test/unit/toml.test.d.ts +1 -0
  70. package/dist/test/unit/toml.test.js +55 -0
  71. package/package.json +1 -1
  72. package/dist/core/adapters/agent-definitions.js +0 -91
  73. /package/dist/{config → src/config}/agents.d.ts +0 -0
  74. /package/dist/{config → src/config}/manifest.d.ts +0 -0
  75. /package/dist/{config → src/config}/manifest.js +0 -0
  76. /package/dist/{core → src/core}/adapters/index.d.ts +0 -0
  77. /package/dist/{core → src/core}/adapters/index.js +0 -0
  78. /package/dist/{core → src/core}/adapters/mcp.d.ts +0 -0
  79. /package/dist/{core → src/core}/adapters/permissions.d.ts +0 -0
  80. /package/dist/{core → src/core}/adapters/rules.d.ts +0 -0
  81. /package/dist/{core → src/core}/adapters/toml.d.ts +0 -0
  82. /package/dist/{core → src/core}/adapters/toml.js +0 -0
  83. /package/dist/{core → src/core}/deploy.d.ts +0 -0
  84. /package/dist/{core → src/core}/detect.d.ts +0 -0
  85. /package/dist/{core → src/core}/detect.js +0 -0
  86. /package/dist/{core → src/core}/init.d.ts +0 -0
  87. /package/dist/{core → src/core}/ownership.d.ts +0 -0
  88. /package/dist/{core → src/core}/preflight.d.ts +0 -0
  89. /package/dist/{core → src/core}/resolve.d.ts +0 -0
  90. /package/dist/{core → src/core}/resolve.js +0 -0
  91. /package/dist/{core → src/core}/revert.d.ts +0 -0
  92. /package/dist/{core → src/core}/runtime-paths.d.ts +0 -0
  93. /package/dist/{core → src/core}/runtime-paths.js +0 -0
  94. /package/dist/{core → src/core}/validation.d.ts +0 -0
  95. /package/dist/{errors.d.ts → src/errors.d.ts} +0 -0
  96. /package/dist/{errors.js → src/errors.js} +0 -0
  97. /package/dist/{formatters.d.ts → src/formatters.d.ts} +0 -0
  98. /package/dist/{formatters.js → src/formatters.js} +0 -0
  99. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  100. /package/dist/{index.js → src/index.js} +0 -0
  101. /package/dist/{logger.d.ts → src/logger.d.ts} +0 -0
  102. /package/dist/{logger.js → src/logger.js} +0 -0
  103. /package/dist/{schemas → src/schemas}/errors.d.ts +0 -0
  104. /package/dist/{schemas → src/schemas}/errors.js +0 -0
  105. /package/dist/{types.js → src/types.js} +0 -0
@@ -3,6 +3,7 @@ import { AGENT_REGISTRY_BY_ID } from "../config/agents.js";
3
3
  import { logger } from "../logger.js";
4
4
  import { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, } from "./adapters/index.js";
5
5
  import { revertTomlMcpPatch } from "./adapters/toml.js";
6
+ import { applyUndoPatch } from "./merge-patch.js";
6
7
  import { lookupDeployment, unregisterDeployment, } from "./ownership.js";
7
8
  import { resolveAgentSkillPath } from "./resolve.js";
8
9
  import { resolveTargetTemplate } from "./runtime-paths.js";
@@ -112,24 +113,6 @@ async function readJsonConfig(filePath) {
112
113
  }
113
114
  return parsed;
114
115
  }
115
- function isPlainObject(v) {
116
- return typeof v === "object" && v !== null && !Array.isArray(v);
117
- }
118
- function applyUndoPatch(current, undoPatch) {
119
- const restored = { ...current };
120
- for (const [key, originalValue] of Object.entries(undoPatch)) {
121
- if (originalValue === null) {
122
- delete restored[key];
123
- }
124
- else if (isPlainObject(originalValue) && isPlainObject(restored[key])) {
125
- restored[key] = applyUndoPatch(restored[key], originalValue);
126
- }
127
- else {
128
- restored[key] = originalValue;
129
- }
130
- }
131
- return restored;
132
- }
133
116
  function lstatOutcome(err) {
134
117
  if (err.code === "ENOENT") {
135
118
  return { outcome: "skip" };
@@ -157,14 +140,7 @@ export async function executeRevert(actions, dryRun, verbose, home, deps = {}) {
157
140
  result = await revertTomlPatch(action, dryRun, verbose, home, planned, deps);
158
141
  break;
159
142
  case "frontmatter-emit":
160
- // Frontmatter-emit files are fully managed by inception — revert
161
- // deletes the file, same as a file-write revert.
162
- result = await revertFileWrite({
163
- kind: "file-write",
164
- skill: action.skill,
165
- agent: action.agent,
166
- target: action.target,
167
- }, dryRun, verbose, home, planned, deps);
143
+ result = await revertFrontmatterEmit(action, dryRun, verbose, home, planned, deps);
168
144
  break;
169
145
  default: {
170
146
  throw new Error(`Unhandled revert action kind: ${action.kind}`);
@@ -179,6 +155,90 @@ export async function executeRevert(actions, dryRun, verbose, home, deps = {}) {
179
155
  planned,
180
156
  };
181
157
  }
158
+ function isManagedFrontmatterEntry(entry, action) {
159
+ return (entry !== null &&
160
+ entry.kind === "frontmatter-emit" &&
161
+ entry.skill === action.skill &&
162
+ entry.agent === action.agent);
163
+ }
164
+ async function loadManagedFrontmatterEntry(action, home, deps) {
165
+ const entry = await lookupDeployment(home, action.target, deps.registry);
166
+ return isManagedFrontmatterEntry(entry, action) ? entry : null;
167
+ }
168
+ function planFrontmatterRevert(action, frontmatterEntry, planned) {
169
+ planned.push({
170
+ verb: "unapply-patch",
171
+ kind: "frontmatter-emit",
172
+ skill: action.skill,
173
+ agent: action.agent,
174
+ target: action.target,
175
+ patch: frontmatterEntry.undoPatch,
176
+ });
177
+ return { outcome: "ok" };
178
+ }
179
+ async function applyFrontmatterRevert(action, frontmatterEntry) {
180
+ const frontmatterAdapter = await import("./adapters/frontmatter.js");
181
+ const current = await frontmatterAdapter.readFrontmatterDocumentFile(action.target);
182
+ const restoredFrontmatter = applyUndoPatch(current.attributes, frontmatterEntry.undoPatch ?? {});
183
+ const shouldDeleteFile = frontmatterEntry.created === true &&
184
+ !frontmatterEntry.hadFrontmatter &&
185
+ Object.keys(restoredFrontmatter).length === 0 &&
186
+ current.body.trim() === "";
187
+ if (shouldDeleteFile) {
188
+ await unlink(action.target);
189
+ return { shouldDeleteFile };
190
+ }
191
+ const restoredContent = frontmatterAdapter.buildMarkdownDocument(restoredFrontmatter, current.body, { hasFrontmatter: frontmatterEntry.hadFrontmatter ?? false });
192
+ await writeFile(action.target, restoredContent, "utf-8");
193
+ return { shouldDeleteFile };
194
+ }
195
+ async function revertFrontmatterEmit(action, dryRun, verbose, home, planned, deps) {
196
+ const label = `${action.skill} -> ${action.agent}`;
197
+ try {
198
+ await lstat(action.target);
199
+ }
200
+ catch (err) {
201
+ const result = lstatOutcome(err);
202
+ if (result.outcome === "skip") {
203
+ logger.skip(label, "(not found, skipping)");
204
+ return result;
205
+ }
206
+ logger.fail(label, result.error);
207
+ return result;
208
+ }
209
+ const frontmatterEntry = await loadManagedFrontmatterEntry(action, home, deps);
210
+ if (!frontmatterEntry) {
211
+ logger.warn(label, `skipping: ${action.target} is not in the deployment registry — not managed by inception-engine`);
212
+ return { outcome: "skip" };
213
+ }
214
+ if (!frontmatterEntry.undoPatch) {
215
+ return revertFileWrite({
216
+ kind: "file-write",
217
+ skill: action.skill,
218
+ agent: action.agent,
219
+ target: action.target,
220
+ }, dryRun, verbose, home, planned, deps);
221
+ }
222
+ if (dryRun) {
223
+ return planFrontmatterRevert(action, frontmatterEntry, planned);
224
+ }
225
+ try {
226
+ const { shouldDeleteFile } = await applyFrontmatterRevert(action, frontmatterEntry);
227
+ await unregisterDeployment(home, action.target, deps.registry);
228
+ logger.ok(label);
229
+ if (verbose) {
230
+ logger.detail(shouldDeleteFile
231
+ ? `removed: ${action.target}`
232
+ : `unapplied frontmatter patch from: ${action.target}`);
233
+ }
234
+ return { outcome: "ok" };
235
+ }
236
+ catch (err) {
237
+ const msg = err instanceof Error ? err.message : String(err);
238
+ logger.fail(label, msg);
239
+ return { outcome: "fail", error: msg };
240
+ }
241
+ }
182
242
  async function executeRevertAction(action, dryRun, verbose, home, planned, deps) {
183
243
  const label = `${action.skill} -> ${action.agent}`;
184
244
  try {
@@ -135,6 +135,23 @@ function validateCodexPermissions(config, entryName) {
135
135
  throw new UserError("DEPLOY_FAILED", `permissions entry "${entryName}" for agent "codex" must define "approval_policy" as one of: ${CODEX_APPROVAL_POLICY_VALUES.join(", ")}`);
136
136
  }
137
137
  }
138
+ function validateOpenCodePermissions(config, entryName) {
139
+ rejectUnknownKeys(config, ["permissions"], entryName, "opencode");
140
+ const perms = config.permissions;
141
+ if (perms === undefined)
142
+ return;
143
+ if (typeof perms !== "object" || perms === null || Array.isArray(perms)) {
144
+ throw new UserError("DEPLOY_FAILED", `permissions entry "${entryName}" for agent "opencode" must define "permissions" as an object`);
145
+ }
146
+ const permsObj = perms;
147
+ for (const key of ["allow", "ask", "deny"]) {
148
+ const val = permsObj[key];
149
+ if (val !== undefined &&
150
+ (!Array.isArray(val) || val.some((item) => typeof item !== "string"))) {
151
+ throw new UserError("DEPLOY_FAILED", `permissions entry "${entryName}" for agent "opencode" must define "permissions.${key}" as an array of strings when present`);
152
+ }
153
+ }
154
+ }
138
155
  export function validatePermissionsConfigShape(config, entryName, agentId) {
139
156
  if (agentId === "claude-code") {
140
157
  validateClaudeCodePermissions(config, entryName);
@@ -142,6 +159,9 @@ export function validatePermissionsConfigShape(config, entryName, agentId) {
142
159
  else if (agentId === "codex") {
143
160
  validateCodexPermissions(config, entryName);
144
161
  }
162
+ else if (agentId === "opencode") {
163
+ validateOpenCodePermissions(config, entryName);
164
+ }
145
165
  }
146
166
  export function validateAgentRuleMarkdownPath(manifestPath, agentId) {
147
167
  const extension = path.extname(manifestPath).toLowerCase();
@@ -59,6 +59,11 @@ export declare const McpServerEntrySchema: z.ZodObject<{
59
59
  "github-copilot": "github-copilot";
60
60
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
61
61
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
62
+ scope: z.ZodDefault<z.ZodEnum<{
63
+ global: "global";
64
+ repo: "repo";
65
+ workspace: "workspace";
66
+ }>>;
62
67
  }, z.core.$strip>;
63
68
  export declare const AgentRuleEntrySchema: z.ZodObject<{
64
69
  name: z.ZodString;
@@ -100,6 +105,11 @@ export declare const AgentDefinitionEntrySchema: z.ZodObject<{
100
105
  "github-copilot": "github-copilot";
101
106
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
102
107
  path: z.ZodString;
108
+ scope: z.ZodDefault<z.ZodEnum<{
109
+ global: "global";
110
+ repo: "repo";
111
+ workspace: "workspace";
112
+ }>>;
103
113
  }, z.core.$strip>;
104
114
  export declare const ManifestSchema: z.ZodObject<{
105
115
  skills: z.ZodArray<z.ZodObject<{
@@ -151,6 +161,11 @@ export declare const ManifestSchema: z.ZodObject<{
151
161
  "github-copilot": "github-copilot";
152
162
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
153
163
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
164
+ scope: z.ZodDefault<z.ZodEnum<{
165
+ global: "global";
166
+ repo: "repo";
167
+ workspace: "workspace";
168
+ }>>;
154
169
  }, z.core.$strip>>>;
155
170
  agentRules: z.ZodDefault<z.ZodArray<z.ZodObject<{
156
171
  name: z.ZodString;
@@ -192,6 +207,11 @@ export declare const ManifestSchema: z.ZodObject<{
192
207
  "github-copilot": "github-copilot";
193
208
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
194
209
  path: z.ZodString;
210
+ scope: z.ZodDefault<z.ZodEnum<{
211
+ global: "global";
212
+ repo: "repo";
213
+ workspace: "workspace";
214
+ }>>;
195
215
  }, z.core.$strip>>>;
196
216
  }, z.core.$strip>;
197
217
  export type SkillEntry = z.infer<typeof SkillEntrySchema>;
@@ -83,6 +83,12 @@ export const McpServerEntrySchema = z.object({
83
83
  // Raw server descriptor passed verbatim to each agent adapter.
84
84
  // Adapters are responsible for validating the shape they need.
85
85
  config: z.record(z.string(), z.unknown()),
86
+ // Deployment scope: "global" (default) targets the agent's user-level MCP
87
+ // config file. "repo" and "workspace" target repo- or workspace-relative
88
+ // config files for agents that support them (e.g. GitHub Copilot's
89
+ // .vscode/mcp.json). For agents without scope-specific surfaces the
90
+ // adapter falls back to the global surface or emits a warning.
91
+ scope: z.enum(["global", "repo", "workspace"]).default("global"),
86
92
  });
87
93
  export const AgentRuleEntrySchema = z.object({
88
94
  name: nameField,
@@ -103,6 +109,7 @@ export const PermissionsEntrySchema = z.object({
103
109
  // Raw permission config payload validated per agent by the permissions adapter.
104
110
  // For claude-code: { permissions: { allow?: string[], deny?: string[] } }
105
111
  // For codex: { approval_policy?: "auto" | "manual" | "suggest" | "on-failure" }
112
+ // For opencode: { permissions: { allow?: string[], ask?: string[], deny?: string[] } }
106
113
  config: z.record(z.string(), z.unknown()),
107
114
  });
108
115
  export const AgentDefinitionEntrySchema = z.object({
@@ -112,6 +119,10 @@ export const AgentDefinitionEntrySchema = z.object({
112
119
  // Must be a .md or .markdown file. Structural requirements (e.g. YAML
113
120
  // frontmatter) are validated per agent requirements by the adapter.
114
121
  path: sourcePathField,
122
+ // Deployment scope: "global" targets the agent's home-directory definition
123
+ // directory (if supported), "repo" targets the project-root definition directory
124
+ // within the deployed repository (default).
125
+ scope: z.enum(["global", "repo", "workspace"]).default("repo"),
115
126
  });
116
127
  export const ManifestSchema = z.object({
117
128
  skills: z.array(SkillEntrySchema).superRefine((skills, ctx) => {
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  declare const SkillDirRegistryEntrySchema: z.ZodObject<{
3
+ surfaceId: z.ZodOptional<z.ZodString>;
4
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
3
5
  kind: z.ZodLiteral<"skill-dir">;
4
6
  source: z.ZodString;
5
7
  skill: z.ZodString;
@@ -18,6 +20,8 @@ declare const SkillDirRegistryEntrySchema: z.ZodObject<{
18
20
  deployed: z.ZodString;
19
21
  }, z.core.$strip>;
20
22
  declare const FileWriteRegistryEntrySchema: z.ZodObject<{
23
+ surfaceId: z.ZodOptional<z.ZodString>;
24
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
25
  kind: z.ZodLiteral<"file-write">;
22
26
  source: z.ZodString;
23
27
  skill: z.ZodString;
@@ -32,6 +36,8 @@ declare const FileWriteRegistryEntrySchema: z.ZodObject<{
32
36
  deployed: z.ZodString;
33
37
  }, z.core.$strip>;
34
38
  declare const ConfigPatchRegistryEntrySchema: z.ZodObject<{
39
+ surfaceId: z.ZodOptional<z.ZodString>;
40
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
41
  kind: z.ZodLiteral<"config-patch">;
36
42
  patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
37
43
  undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -47,7 +53,13 @@ declare const ConfigPatchRegistryEntrySchema: z.ZodObject<{
47
53
  deployed: z.ZodString;
48
54
  }, z.core.$strip>;
49
55
  declare const FrontmatterEmitRegistryEntrySchema: z.ZodObject<{
56
+ surfaceId: z.ZodOptional<z.ZodString>;
57
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
58
  kind: z.ZodLiteral<"frontmatter-emit">;
59
+ patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
60
+ undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
61
+ created: z.ZodOptional<z.ZodBoolean>;
62
+ hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
51
63
  skill: z.ZodString;
52
64
  agent: z.ZodEnum<{
53
65
  "claude-code": "claude-code";
@@ -60,6 +72,8 @@ declare const FrontmatterEmitRegistryEntrySchema: z.ZodObject<{
60
72
  deployed: z.ZodString;
61
73
  }, z.core.$strip>;
62
74
  export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
75
+ surfaceId: z.ZodOptional<z.ZodString>;
76
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
63
77
  kind: z.ZodLiteral<"skill-dir">;
64
78
  source: z.ZodString;
65
79
  skill: z.ZodString;
@@ -77,6 +91,8 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
77
91
  }>>;
78
92
  deployed: z.ZodString;
79
93
  }, z.core.$strip>, z.ZodObject<{
94
+ surfaceId: z.ZodOptional<z.ZodString>;
95
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
80
96
  kind: z.ZodLiteral<"file-write">;
81
97
  source: z.ZodString;
82
98
  skill: z.ZodString;
@@ -90,6 +106,8 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
90
106
  }>;
91
107
  deployed: z.ZodString;
92
108
  }, z.core.$strip>, z.ZodObject<{
109
+ surfaceId: z.ZodOptional<z.ZodString>;
110
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
111
  kind: z.ZodLiteral<"config-patch">;
94
112
  patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
95
113
  undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -104,7 +122,13 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
104
122
  }>;
105
123
  deployed: z.ZodString;
106
124
  }, z.core.$strip>, z.ZodObject<{
125
+ surfaceId: z.ZodOptional<z.ZodString>;
126
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
107
127
  kind: z.ZodLiteral<"frontmatter-emit">;
128
+ patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
129
+ undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
130
+ created: z.ZodOptional<z.ZodBoolean>;
131
+ hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
108
132
  skill: z.ZodString;
109
133
  agent: z.ZodEnum<{
110
134
  "claude-code": "claude-code";
@@ -119,6 +143,8 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
119
143
  export declare const RegistrySchema: z.ZodObject<{
120
144
  version: z.ZodLiteral<1>;
121
145
  deployments: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
146
+ surfaceId: z.ZodOptional<z.ZodString>;
147
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
122
148
  kind: z.ZodLiteral<"skill-dir">;
123
149
  source: z.ZodString;
124
150
  skill: z.ZodString;
@@ -136,6 +162,8 @@ export declare const RegistrySchema: z.ZodObject<{
136
162
  }>>;
137
163
  deployed: z.ZodString;
138
164
  }, z.core.$strip>, z.ZodObject<{
165
+ surfaceId: z.ZodOptional<z.ZodString>;
166
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
139
167
  kind: z.ZodLiteral<"file-write">;
140
168
  source: z.ZodString;
141
169
  skill: z.ZodString;
@@ -149,6 +177,8 @@ export declare const RegistrySchema: z.ZodObject<{
149
177
  }>;
150
178
  deployed: z.ZodString;
151
179
  }, z.core.$strip>, z.ZodObject<{
180
+ surfaceId: z.ZodOptional<z.ZodString>;
181
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
152
182
  kind: z.ZodLiteral<"config-patch">;
153
183
  patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
154
184
  undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -163,7 +193,13 @@ export declare const RegistrySchema: z.ZodObject<{
163
193
  }>;
164
194
  deployed: z.ZodString;
165
195
  }, z.core.$strip>, z.ZodObject<{
196
+ surfaceId: z.ZodOptional<z.ZodString>;
197
+ migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
166
198
  kind: z.ZodLiteral<"frontmatter-emit">;
199
+ patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
200
+ undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
201
+ created: z.ZodOptional<z.ZodBoolean>;
202
+ hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
167
203
  skill: z.ZodString;
168
204
  agent: z.ZodEnum<{
169
205
  "claude-code": "claude-code";
@@ -1,6 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import { AgentIdSchema } from "./manifest.js";
3
- const SkillDirRegistryEntrySchema = z.object({
3
+ const RegistryOwnershipMetadataSchema = z.object({
4
+ surfaceId: z.string().optional(),
5
+ migratedFrom: z.array(z.string()).optional(),
6
+ });
7
+ const SkillDirRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
4
8
  kind: z.literal("skill-dir"),
5
9
  source: z.string(),
6
10
  skill: z.string(),
@@ -8,14 +12,14 @@ const SkillDirRegistryEntrySchema = z.object({
8
12
  method: z.enum(["symlink", "copy"]).optional(),
9
13
  deployed: z.string(),
10
14
  });
11
- const FileWriteRegistryEntrySchema = z.object({
15
+ const FileWriteRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
12
16
  kind: z.literal("file-write"),
13
17
  source: z.string(),
14
18
  skill: z.string(),
15
19
  agent: AgentIdSchema,
16
20
  deployed: z.string(),
17
21
  });
18
- const ConfigPatchRegistryEntrySchema = z.object({
22
+ const ConfigPatchRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
19
23
  kind: z.literal("config-patch"),
20
24
  patch: z.record(z.string(), z.unknown()),
21
25
  undoPatch: z.record(z.string(), z.unknown()),
@@ -23,8 +27,12 @@ const ConfigPatchRegistryEntrySchema = z.object({
23
27
  agent: AgentIdSchema,
24
28
  deployed: z.string(),
25
29
  });
26
- const FrontmatterEmitRegistryEntrySchema = z.object({
30
+ const FrontmatterEmitRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
27
31
  kind: z.literal("frontmatter-emit"),
32
+ patch: z.record(z.string(), z.unknown()).optional(),
33
+ undoPatch: z.record(z.string(), z.unknown()).optional(),
34
+ created: z.boolean().optional(),
35
+ hadFrontmatter: z.boolean().optional(),
28
36
  skill: z.string(),
29
37
  agent: AgentIdSchema,
30
38
  deployed: z.string(),
@@ -5,6 +5,7 @@ export interface AgentPaths {
5
5
  windows: string[];
6
6
  }
7
7
  export type Confidence = "documented" | "implementation-only" | "provisional";
8
+ export type CapabilityKind = "skills" | "mcpServers" | "agentRules" | "permissions" | "agentDefinitions";
8
9
  export interface SupportedAgentSurface {
9
10
  status: "supported";
10
11
  /**
@@ -90,12 +91,23 @@ export interface AgentConfig {
90
91
  detectBinary: string | null;
91
92
  provenance: AgentProvenance;
92
93
  mcpSupport?: AgentSurfaceSupport;
94
+ mcpRepoSupport?: AgentSurfaceSupport;
95
+ mcpWorkspaceSupport?: AgentSurfaceSupport;
93
96
  agentRulesSupport?: AgentSurfaceSupport;
94
97
  agentRulesRepoSupport?: AgentSurfaceSupport;
95
98
  agentRulesWorkspaceSupport?: AgentSurfaceSupport;
96
99
  permissionsSupport?: AgentSurfaceSupport;
97
100
  agentDefinitionsSupport?: AgentSurfaceSupport;
101
+ agentDefinitionsRepoSupport?: AgentSurfaceSupport;
102
+ agentDefinitionsWorkspaceSupport?: AgentSurfaceSupport;
103
+ agentDefinitionsTomlSupport?: AgentSurfaceSupport;
104
+ agentDefinitionsTomlRepoSupport?: AgentSurfaceSupport;
98
105
  policyNote?: string;
106
+ /**
107
+ * A list of documented surfaces that are currently not safe to support directly.
108
+ * Preflight will emit warnings for these if the agent is targeted.
109
+ */
110
+ unsupportedSurfaces?: AgentSurfaceSupport[];
99
111
  /**
100
112
  * When true, instruction files deployed to this agent must include valid
101
113
  * YAML frontmatter. Drives validateInstructionFileRequirements without
@@ -127,6 +139,7 @@ export interface FileWriteDeployAction {
127
139
  source: string;
128
140
  target: string;
129
141
  confidence?: Confidence;
142
+ migratedFrom?: string[];
130
143
  }
131
144
  export interface ConfigPatchDeployAction {
132
145
  kind: "config-patch";
@@ -0,0 +1,2 @@
1
+ export declare function exists(p: string): Promise<boolean>;
2
+ export declare function makeTmpDir(prefix?: string): Promise<string>;
@@ -0,0 +1,17 @@
1
+ import { access, mkdir } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export async function exists(p) {
5
+ try {
6
+ await access(p);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function makeTmpDir(prefix = "ie-test-dir") {
14
+ const dir = path.join(os.tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
15
+ await mkdir(dir, { recursive: true });
16
+ return dir;
17
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Normalize path separators to forward slashes for cross-platform path assertions.
3
+ * Use this instead of hard-coding POSIX separators in expected strings.
4
+ */
5
+ export declare function normalizeSlashes(value: string): string;
6
+ /**
7
+ * Assert that a path ends with the given POSIX-style suffix, normalizing separators.
8
+ * Use instead of: assert.ok(normalizeSlashes(p).endsWith("some/suffix"))
9
+ */
10
+ export declare function assertPathEndsWith(actual: string, suffix: string, msg?: string): void;
@@ -0,0 +1,15 @@
1
+ import assert from "node:assert/strict";
2
+ /**
3
+ * Normalize path separators to forward slashes for cross-platform path assertions.
4
+ * Use this instead of hard-coding POSIX separators in expected strings.
5
+ */
6
+ export function normalizeSlashes(value) {
7
+ return value.replaceAll("\\", "/");
8
+ }
9
+ /**
10
+ * Assert that a path ends with the given POSIX-style suffix, normalizing separators.
11
+ * Use instead of: assert.ok(normalizeSlashes(p).endsWith("some/suffix"))
12
+ */
13
+ export function assertPathEndsWith(actual, suffix, msg) {
14
+ assert.ok(normalizeSlashes(actual).endsWith(suffix), msg ?? `Expected path "${actual}" to end with "${suffix}"`);
15
+ }
@@ -0,0 +1,7 @@
1
+ interface SkillDirScenarioOptions {
2
+ method: "symlink" | "copy";
3
+ assertManagedTarget(target: string, source: string, expectedSkillMd: string): Promise<void>;
4
+ }
5
+ export declare function registerSharedSkillDirDeployScenarios(options: SkillDirScenarioOptions): void;
6
+ export declare function registerSharedSkillDirRevertScenarios(options: SkillDirScenarioOptions): void;
7
+ export {};