@kuznai/inception-engine 0.16.0 → 0.18.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.
@@ -1,6 +1,7 @@
1
1
  import { lstat, readFile, realpath, stat } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { UserError } from "../errors.js";
4
+ import { parseFrontmatterDocument } from "./adapters/frontmatter.js";
4
5
  export function sourceAccessError(err, sourcePath) {
5
6
  const code = err.code;
6
7
  if (code === "ENOENT")
@@ -147,23 +148,6 @@ export function validateAgentRuleMarkdownPath(manifestPath, agentId) {
147
148
  throw new UserError("DEPLOY_FAILED", `agentRules entry "${manifestPath}" for agent "${agentId}" must point to a Markdown source file`);
148
149
  }
149
150
  }
150
- function trimMatchingQuotes(value) {
151
- if ((value.startsWith('"') && value.endsWith('"')) ||
152
- (value.startsWith("'") && value.endsWith("'"))) {
153
- return value.slice(1, -1).trim();
154
- }
155
- return value;
156
- }
157
- function parseSimpleFrontmatterValue(field, rawValue, manifestPath) {
158
- const value = trimMatchingQuotes(rawValue.trim());
159
- if (value.length === 0) {
160
- throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter field "${field}" must be a non-empty string`);
161
- }
162
- if (rawValue.trim() === "|" || rawValue.trim() === ">") {
163
- throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter field "${field}" must be a single-line string`);
164
- }
165
- return value;
166
- }
167
151
  export async function validateSkillDefinitionFile(sourcePath, manifestPath) {
168
152
  await validateSourceFile(sourcePath, `${manifestPath}/SKILL.md`);
169
153
  let raw;
@@ -181,27 +165,26 @@ export async function validateSkillDefinitionFile(sourcePath, manifestPath) {
181
165
  if (closingIndex === -1) {
182
166
  throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md is missing the closing --- frontmatter delimiter`);
183
167
  }
184
- let name = null;
185
- let description = null;
186
- for (const line of lines.slice(1, closingIndex)) {
187
- const trimmed = line.trim();
188
- if (trimmed.length === 0 || trimmed.startsWith("#"))
189
- continue;
190
- const match = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/.exec(line);
191
- if (!match)
192
- continue;
193
- const [, key, rawValue] = match;
194
- if (key === "name") {
195
- name = parseSimpleFrontmatterValue("name", rawValue, manifestPath);
196
- }
197
- else if (key === "description") {
198
- description = parseSimpleFrontmatterValue("description", rawValue, manifestPath);
199
- }
200
- }
201
- if (name === null) {
202
- throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter must include a non-empty "name" field`);
168
+ let attributes;
169
+ try {
170
+ const parsed = parseFrontmatterDocument(raw);
171
+ attributes = parsed.attributes;
203
172
  }
204
- if (description === null) {
205
- throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter must include a non-empty "description" field`);
173
+ catch (err) {
174
+ throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md has malformed YAML frontmatter: ${err instanceof Error ? err.message : String(err)}`);
206
175
  }
176
+ const validateField = (field) => {
177
+ const value = attributes[field];
178
+ if (value === undefined || value === null) {
179
+ throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter must include a non-empty "${field}" field`);
180
+ }
181
+ if (typeof value !== "string" || value.trim().length === 0) {
182
+ throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter field "${field}" must be a non-empty string`);
183
+ }
184
+ if (value.includes("\n") || value.includes("\r")) {
185
+ throw new UserError("DEPLOY_FAILED", `Skill "${manifestPath}" SKILL.md frontmatter field "${field}" must be a single-line string`);
186
+ }
187
+ };
188
+ validateField("name");
189
+ validateField("description");
207
190
  }
@@ -71,6 +71,10 @@ export declare const AgentRuleEntrySchema: z.ZodObject<{
71
71
  "github-copilot": "github-copilot";
72
72
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
73
73
  path: z.ZodString;
74
+ scope: z.ZodDefault<z.ZodEnum<{
75
+ global: "global";
76
+ repo: "repo";
77
+ }>>;
74
78
  }, z.core.$strip>;
75
79
  export declare const PermissionsEntrySchema: z.ZodObject<{
76
80
  name: z.ZodString;
@@ -84,6 +88,18 @@ export declare const PermissionsEntrySchema: z.ZodObject<{
84
88
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
85
89
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
86
90
  }, z.core.$strip>;
91
+ export declare const AgentDefinitionEntrySchema: z.ZodObject<{
92
+ name: z.ZodString;
93
+ agents: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
94
+ "claude-code": "claude-code";
95
+ codex: "codex";
96
+ "gemini-cli": "gemini-cli";
97
+ antigravity: "antigravity";
98
+ opencode: "opencode";
99
+ "github-copilot": "github-copilot";
100
+ }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
101
+ path: z.ZodString;
102
+ }, z.core.$strip>;
87
103
  export declare const ManifestSchema: z.ZodObject<{
88
104
  skills: z.ZodArray<z.ZodObject<{
89
105
  name: z.ZodString;
@@ -146,6 +162,10 @@ export declare const ManifestSchema: z.ZodObject<{
146
162
  "github-copilot": "github-copilot";
147
163
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
148
164
  path: z.ZodString;
165
+ scope: z.ZodDefault<z.ZodEnum<{
166
+ global: "global";
167
+ repo: "repo";
168
+ }>>;
149
169
  }, z.core.$strip>>>;
150
170
  permissions: z.ZodDefault<z.ZodArray<z.ZodObject<{
151
171
  name: z.ZodString;
@@ -159,6 +179,18 @@ export declare const ManifestSchema: z.ZodObject<{
159
179
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
160
180
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
161
181
  }, z.core.$strip>>>;
182
+ agentDefinitions: z.ZodDefault<z.ZodArray<z.ZodObject<{
183
+ name: z.ZodString;
184
+ agents: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
185
+ "claude-code": "claude-code";
186
+ codex: "codex";
187
+ "gemini-cli": "gemini-cli";
188
+ antigravity: "antigravity";
189
+ opencode: "opencode";
190
+ "github-copilot": "github-copilot";
191
+ }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
192
+ path: z.ZodString;
193
+ }, z.core.$strip>>>;
162
194
  }, z.core.$strip>;
163
195
  export type SkillEntry = z.infer<typeof SkillEntrySchema>;
164
196
  export type FileEntry = z.infer<typeof FileEntrySchema>;
@@ -166,6 +198,7 @@ export type ConfigEntry = z.infer<typeof ConfigEntrySchema>;
166
198
  export type McpServerEntry = z.infer<typeof McpServerEntrySchema>;
167
199
  export type AgentRuleEntry = z.infer<typeof AgentRuleEntrySchema>;
168
200
  export type PermissionsEntry = z.infer<typeof PermissionsEntrySchema>;
201
+ export type AgentDefinitionEntry = z.infer<typeof AgentDefinitionEntrySchema>;
169
202
  export type Manifest = z.infer<typeof ManifestSchema>;
170
203
  export declare const AgentListSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string[], string>>, z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
171
204
  "claude-code": "claude-code";
@@ -89,6 +89,10 @@ export const AgentRuleEntrySchema = z.object({
89
89
  agents: agentsField,
90
90
  // Relative path to the rules/instruction file within the source bundle.
91
91
  path: sourcePathField,
92
+ // Deployment scope: "global" targets the agent's home-directory instruction
93
+ // file (default), "repo" targets the project-root instruction file within the
94
+ // deployed repository (e.g. {repo}/CLAUDE.md for claude-code).
95
+ scope: z.enum(["global", "repo"]).default("global"),
92
96
  });
93
97
  export const PermissionsEntrySchema = z.object({
94
98
  name: nameField,
@@ -98,6 +102,14 @@ export const PermissionsEntrySchema = z.object({
98
102
  // For codex: { approval_policy?: "auto" | "manual" | "suggest" | "on-failure" }
99
103
  config: z.record(z.string(), z.unknown()),
100
104
  });
105
+ export const AgentDefinitionEntrySchema = z.object({
106
+ name: nameField,
107
+ agents: agentsField,
108
+ // Relative path to the agent definition Markdown file within the source bundle.
109
+ // Must be a .md or .markdown file. Content and frontmatter structure are not
110
+ // validated by inception-engine — format requirements are agent-specific.
111
+ path: sourcePathField,
112
+ });
101
113
  export const ManifestSchema = z.object({
102
114
  skills: z.array(SkillEntrySchema).superRefine((skills, ctx) => {
103
115
  const seen = new Set();
@@ -117,6 +129,7 @@ export const ManifestSchema = z.object({
117
129
  mcpServers: z.array(McpServerEntrySchema).default([]),
118
130
  agentRules: z.array(AgentRuleEntrySchema).default([]),
119
131
  permissions: z.array(PermissionsEntrySchema).default([]),
132
+ agentDefinitions: z.array(AgentDefinitionEntrySchema).default([]),
120
133
  });
121
134
  // Parses the --agents CLI flag: comma-separated agent IDs → AgentId[]
122
135
  export const AgentListSchema = z
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AgentId } from "./schemas/manifest.ts";
2
- export type { AgentId, ConfigEntry, FileEntry, Manifest, SkillEntry, } from "./schemas/manifest.ts";
2
+ export type { AgentDefinitionEntry, AgentId, ConfigEntry, FileEntry, Manifest, SkillEntry, } from "./schemas/manifest.ts";
3
3
  export interface AgentPaths {
4
4
  posix: string[];
5
5
  windows: string[];
@@ -16,25 +16,48 @@ export interface UnsupportedAgentSurface {
16
16
  schemaLabel: string;
17
17
  reason: string;
18
18
  }
19
- export type AgentSurfaceSupport = SupportedAgentSurface | UnsupportedAgentSurface;
19
+ /**
20
+ * A surface that is confirmed as Copilot-specific and genuinely justified for
21
+ * future dedicated implementation, but not yet supported. Distinct from
22
+ * "unsupported" (which means the surface is either covered by another target or
23
+ * will never be added) so adapters can emit a forward-looking "planned" notice
24
+ * rather than a blocking skip warning.
25
+ */
26
+ export interface PlannedAgentSurface {
27
+ status: "planned";
28
+ schemaLabel: string;
29
+ /** Short description of the concrete file / config surface to be implemented. */
30
+ plannedSurface: string;
31
+ reason: string;
32
+ }
33
+ export type AgentSurfaceSupport = SupportedAgentSurface | UnsupportedAgentSurface | PlannedAgentSurface;
20
34
  export interface AgentProvenance {
21
- skills: Confidence;
35
+ /** Omit when the agent has no separate skill deployment path. */
36
+ skills?: Confidence;
22
37
  detectPaths: Confidence;
23
38
  detectBinary: Confidence;
24
39
  mcpConfig?: Confidence;
25
40
  agentRules?: Confidence;
26
41
  permissions?: Confidence;
42
+ agentDefinitions?: Confidence;
27
43
  }
28
44
  export interface AgentConfig {
29
45
  id: AgentId;
30
46
  displayName: string;
31
- skills: AgentPaths;
47
+ /**
48
+ * The on-disk path template for deploying skills to this agent.
49
+ * Omit for agents that consume skills from another agent's path natively
50
+ * (e.g. GitHub Copilot reads `.claude/skills/` directly).
51
+ */
52
+ skills?: AgentPaths;
32
53
  detectPaths: AgentPaths;
33
54
  detectBinary: string | null;
34
55
  provenance: AgentProvenance;
35
56
  mcpSupport?: AgentSurfaceSupport;
36
57
  agentRulesSupport?: AgentSurfaceSupport;
58
+ agentRulesRepoSupport?: AgentSurfaceSupport;
37
59
  permissionsSupport?: AgentSurfaceSupport;
60
+ agentDefinitionsSupport?: AgentSurfaceSupport;
38
61
  policyNote?: string;
39
62
  }
40
63
  export interface PlanWarning {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuznai/inception-engine",
3
- "version": "0.16.0",
3
+ "version": "0.18.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",
@@ -47,8 +47,8 @@
47
47
  "test:posix": "node --test --test-isolation=none test/unit/*.test.ts test/os/cross-platform/*.test.ts test/os/posix/*.test.ts"
48
48
  },
49
49
  "dependencies": {
50
- "front-matter": "^4.0.2",
51
50
  "smol-toml": "^1.6.1",
51
+ "yaml": "^2.8.3",
52
52
  "zod": "^4.0.0"
53
53
  },
54
54
  "devDependencies": {