@kuznai/inception-engine 0.17.0 → 0.19.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.
- package/README.md +40 -13
- package/dist/config/agents.js +127 -5
- package/dist/core/adapters/agent-definitions.d.ts +2 -2
- package/dist/core/adapters/agent-definitions.js +6 -5
- package/dist/core/adapters/frontmatter.d.ts +17 -5
- package/dist/core/adapters/frontmatter.js +36 -57
- package/dist/core/adapters/index.d.ts +1 -1
- package/dist/core/adapters/index.js +4 -4
- package/dist/core/adapters/mcp.d.ts +2 -2
- package/dist/core/adapters/mcp.js +4 -4
- package/dist/core/adapters/rules.d.ts +2 -2
- package/dist/core/adapters/rules.js +99 -28
- package/dist/core/deploy.d.ts +1 -1
- package/dist/core/deploy.js +206 -54
- package/dist/core/init.js +129 -49
- package/dist/core/ownership.d.ts +2 -2
- package/dist/core/preflight.d.ts +2 -2
- package/dist/core/preflight.js +142 -2
- package/dist/core/resolve.d.ts +1 -1
- package/dist/core/resolve.js +7 -4
- package/dist/core/revert.js +9 -7
- package/dist/core/runtime-paths.d.ts +2 -1
- package/dist/core/runtime-paths.js +30 -23
- package/dist/core/validation.d.ts +10 -1
- package/dist/core/validation.js +73 -35
- package/dist/formatters.d.ts +5 -0
- package/dist/formatters.js +58 -0
- package/dist/index.js +8 -24
- package/dist/logger.js +22 -21
- package/dist/schemas/manifest.d.ts +10 -0
- package/dist/schemas/manifest.js +10 -3
- package/dist/schemas/registry.d.ts +38 -0
- package/dist/schemas/registry.js +7 -0
- package/dist/types.d.ts +48 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ inception-engine reads a manifest file (`inception.json`) from the target direct
|
|
|
27
27
|
|
|
28
28
|
Managed skills overwrite their previous version. If a target exists but was not created by inception-engine, deployment refuses to replace it. On POSIX systems, symlinks mean updates to the source repo are reflected immediately.
|
|
29
29
|
|
|
30
|
+
Before executing, the deploy command runs preflight analysis on instruction files: it validates that `agentRules` and `agentDefinitions` for targets requiring specific structure (like `github-copilot` and `antigravity`) include valid YAML frontmatter with `name` and `description` fields. For `github-copilot`, it further ensures either `tools` or `instructions` are defined; for `antigravity`, it validates the shape of any `mcp-servers` or `mcpServers` defined in the frontmatter. It also warns when the same agent will have multiple `agentRules` scopes active simultaneously, when the same source file is deployed to multiple scopes (duplicate-content risk), when `agentRules` or `agentDefinitions` source files exceed 50 KB (context-budget risk), and when GitHub Copilot appears to be running under enterprise-managed policy that may override local configuration. Warnings are printed but do not block deployment; structural validation failures block deployment for the affected targets.
|
|
31
|
+
|
|
30
32
|
## Agent Compatibility Matrix
|
|
31
33
|
|
|
32
34
|
| Agent | ID | Skills | macOS | Linux | Windows |
|
|
@@ -49,10 +51,11 @@ Managed skills overwrite their previous version. If a target exists but was not
|
|
|
49
51
|
| File write | All agents via manifest and CLI | All agents |
|
|
50
52
|
| Config patch (JSON merge) | All agents via manifest and CLI | All agents |
|
|
51
53
|
| MCP Servers | claude-code, gemini-cli, codex, antigravity, opencode; github-copilot repo-scoped surfaces are warned and skipped | claude-code, gemini-cli, codex, antigravity, opencode |
|
|
52
|
-
| Global/Repo Rules Files |
|
|
54
|
+
| Global/Repo/Workspace Rules Files | `scope: "global"` and `scope: "repo"` are supported on the implemented agent surfaces; `scope: "workspace"` is supported for `claude-code`, `codex`, and `gemini-cli`; `github-copilot` reads Claude-native rules via `claude-code` and has no separate rules deployment target | All supported agents |
|
|
53
55
|
| Permissions / Approval Config | claude-code (`~/.claude/settings.json`), codex (`~/.codex/config.toml`); other agents are warned and skipped | claude-code, codex |
|
|
54
56
|
| Agent Definitions | claude-code (`{repo}/.claude/agents/{name}.md`), gemini-cli (`{repo}/.gemini/agents/{name}.md`), antigravity (`{repo}/.agents/rules/{name}.md`), opencode (`{repo}/.opencode/agents/{name}.md`), github-copilot (`{repo}/.github/agents/{name}.agent.md`); codex is warned and skipped | All supported agents |
|
|
55
57
|
| `init` manifest generation | Scans `SKILL.md` directories (`skills`), `.md` files with Claude-first agent mapping (`agentRules`), `mcp-servers.json` (`mcpServers`), and agent-definition Markdown files (`agentDefinitions`); emits hints for `files/` and `configs/` directories | N/A |
|
|
58
|
+
| Instruction preflight analysis | Emits `precedence` warnings when an agent has multiple `agentRules` scopes active simultaneously or the same source file is deployed to multiple scopes; emits `budget` warnings when `agentRules` or `agentDefinitions` source files exceed 50 KB; emits GitHub Copilot enterprise-policy warnings when local configuration may be overridden | N/A |
|
|
56
59
|
|
|
57
60
|
Features that depend on agent-specific config surfaces are intentionally conservative: if a target path or schema is not implemented with enough confidence, inception-engine warns and skips it rather than guessing.
|
|
58
61
|
|
|
@@ -98,7 +101,14 @@ Create an `inception.json` file at the root of your skills directory:
|
|
|
98
101
|
{
|
|
99
102
|
"name": "my-rules",
|
|
100
103
|
"path": "rules/CLAUDE.md",
|
|
101
|
-
"agents": ["claude-code"]
|
|
104
|
+
"agents": ["claude-code"],
|
|
105
|
+
"scope": "global"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "project-rules",
|
|
109
|
+
"path": "rules/CLAUDE.md",
|
|
110
|
+
"agents": ["claude-code", "codex", "gemini-cli", "opencode"],
|
|
111
|
+
"scope": "repo"
|
|
102
112
|
}
|
|
103
113
|
],
|
|
104
114
|
"permissions": [
|
|
@@ -158,13 +168,28 @@ MCP server registration is supported for all agents except GitHub Copilot. Incep
|
|
|
158
168
|
|
|
159
169
|
Revert removes the registered server entry from the respective configuration file. GitHub Copilot, which uses repo-scoped MCP surfaces not yet implemented by inception-engine, continues to emit a schema-aware warning and is skipped.
|
|
160
170
|
|
|
161
|
-
Each **agentRules** entry deploys a Markdown instruction file to an agent's supported
|
|
171
|
+
Each **agentRules** entry deploys a Markdown instruction file to an agent's supported instruction file location:
|
|
162
172
|
|
|
163
173
|
- **name** - Unique identifier (same format as skill names)
|
|
164
|
-
- **path** - Relative path to the source Markdown file within the repo; supported
|
|
174
|
+
- **path** - Relative path to the source Markdown file within the repo; supported rules adapters require a `.md` or `.markdown` source path
|
|
165
175
|
- **agents** - Array of agent IDs to deploy this file to
|
|
176
|
+
- **scope** - `"global"` (default), `"repo"`, or `"workspace"`. Controls which instruction surface is targeted:
|
|
177
|
+
- `"global"` — deploys to the agent's home-directory instruction file when that surface is supported (e.g., `~/.claude/CLAUDE.md` for `claude-code`)
|
|
178
|
+
- `"repo"` — deploys to the project-root instruction file inside the deployed repository when that surface is supported (e.g., `{repo}/CLAUDE.md` for `claude-code`)
|
|
179
|
+
- `"workspace"` — deploys to the workspace-root instruction file when an agent exposes one (e.g., `{workspace}/CLAUDE.md` for `claude-code`); when unsupported, deployment is skipped with a warning
|
|
180
|
+
|
|
181
|
+
Instruction rule deployment is supported for implemented global, repo, and workspace surfaces. The target path depends on the agent and the `scope`:
|
|
166
182
|
|
|
167
|
-
|
|
183
|
+
| Agent | `scope: "global"` | `scope: "repo"` | `scope: "workspace"` |
|
|
184
|
+
|---|---|---|---|
|
|
185
|
+
| `claude-code` | `~/.claude/CLAUDE.md` | `{repo}/CLAUDE.md` | `{workspace}/CLAUDE.md` |
|
|
186
|
+
| `codex` | `~/.codex/AGENTS.md` | `{repo}/AGENTS.md` | `{workspace}/AGENTS.md` |
|
|
187
|
+
| `gemini-cli` | `~/.gemini/GEMINI.md` | `{repo}/GEMINI.md` | `{workspace}/GEMINI.md` |
|
|
188
|
+
| `antigravity` | `~/.gemini/GEMINI.md` | `{repo}/GEMINI.md` | unsupported; warns and skips |
|
|
189
|
+
| `opencode` | `~/.config/opencode/AGENTS.md` | `{repo}/AGENTS.md` | unsupported; warns and skips |
|
|
190
|
+
| `github-copilot` | unsupported / Claude-first | deploy via `claude-code` | unsupported; deploy via `claude-code` with `scope: "workspace"` |
|
|
191
|
+
|
|
192
|
+
For `antigravity`, `agentRules` now targets the shared GEMINI.md surface (`~/.gemini/GEMINI.md` for `global`, `{repo}/GEMINI.md` for `repo`) — the same paths used by `gemini-cli`. When both agents appear in the same entry, deduplication ensures only one write action is emitted. `workspace` scope is not supported and is skipped with a warning. For `github-copilot`, no separate deployment is needed — target it via the `claude-code` agentRules entry and it reaches Copilot automatically. Revert removes the deployed rules file.
|
|
168
193
|
|
|
169
194
|
Each **permissions** entry deploys execution and safety-oriented configuration to an agent's permission or approval surface:
|
|
170
195
|
|
|
@@ -251,8 +276,8 @@ Current `init` behavior:
|
|
|
251
276
|
- Uses the directory name as the manifest skill name
|
|
252
277
|
- Applies either the `--agents` list or all currently known agent IDs
|
|
253
278
|
- Refuses to overwrite an existing `inception.json` unless `--force` is provided
|
|
254
|
-
- Supports `--
|
|
255
|
-
- Discovers agent-rules Markdown files in the root and conventional subdirectories (`rules/`, `instructions/`, `.github
|
|
279
|
+
- Supports `--plan` so you can inspect the generated manifest before writing it
|
|
280
|
+
- Discovers agent-rules Markdown files in the root and conventional subdirectories (`rules/`, `instructions/`, `.github/`), mapping them to agents using Claude-first portability conventions: `copilot-instructions.md` maps to `claude-code` (Copilot reads `CLAUDE.md` natively), and the fallback for unrecognized files excludes agents whose agentRules surface is unsupported
|
|
256
281
|
- Reads `mcp-servers.json` from the repo root (if present) and generates `mcpServers` entries; invalid entries are warned and skipped
|
|
257
282
|
- Reads `files-manifest.json` from the repo root (if present) and generates `files` entries; invalid entries are warned and skipped
|
|
258
283
|
- Reads `configs-manifest.json` from the repo root (if present) and generates `configs` entries; invalid entries are warned and skipped
|
|
@@ -342,13 +367,15 @@ inception-engine init <directory> [options]
|
|
|
342
367
|
|
|
343
368
|
| Option | Description |
|
|
344
369
|
|---|---|
|
|
345
|
-
| `--
|
|
370
|
+
| `--plan` | Show what would be done without making changes |
|
|
346
371
|
| `--agents <list>` | Comma-separated list of agent IDs to target (overrides deploy detection; restricts revert) |
|
|
347
372
|
| `--force` | `init` only; overwrite an existing `inception.json` |
|
|
348
373
|
| `--verbose` | Show detailed output including file paths |
|
|
349
374
|
| `--debug` | Show full error stack traces |
|
|
350
375
|
| `--help` | Show help message |
|
|
351
376
|
|
|
377
|
+
With `--plan`, deploy and revert print a grouped action preview by agent. Each planned change includes the source path when applicable, the resolved target path, and action-specific details such as JSON/TOML patch payloads or emitted frontmatter content.
|
|
378
|
+
|
|
352
379
|
### Examples
|
|
353
380
|
|
|
354
381
|
```bash
|
|
@@ -356,7 +383,7 @@ inception-engine init <directory> [options]
|
|
|
356
383
|
npx @kuznai/inception-engine ./my-skills-repo
|
|
357
384
|
|
|
358
385
|
# Preview what would be deployed
|
|
359
|
-
npx @kuznai/inception-engine ./my-skills-repo --
|
|
386
|
+
npx @kuznai/inception-engine ./my-skills-repo --plan
|
|
360
387
|
|
|
361
388
|
# Deploy only to Claude Code and Codex
|
|
362
389
|
npx @kuznai/inception-engine ./my-skills-repo --agents claude-code,codex
|
|
@@ -365,13 +392,13 @@ npx @kuznai/inception-engine ./my-skills-repo --agents claude-code,codex
|
|
|
365
392
|
npx @kuznai/inception-engine revert ./my-skills-repo
|
|
366
393
|
|
|
367
394
|
# Preview what would be removed
|
|
368
|
-
npx @kuznai/inception-engine revert ./my-skills-repo --
|
|
395
|
+
npx @kuznai/inception-engine revert ./my-skills-repo --plan
|
|
369
396
|
|
|
370
397
|
# Generate a starter manifest from discovered skill folders
|
|
371
398
|
npx @kuznai/inception-engine init ./my-skills-repo
|
|
372
399
|
|
|
373
400
|
# Preview the generated manifest without writing it
|
|
374
|
-
npx @kuznai/inception-engine init ./my-skills-repo --
|
|
401
|
+
npx @kuznai/inception-engine init ./my-skills-repo --plan
|
|
375
402
|
```
|
|
376
403
|
|
|
377
404
|
## Sample Skills
|
|
@@ -381,8 +408,8 @@ The `limbo/` directory contains exceptional sample skills for testing purposes o
|
|
|
381
408
|
Try them out:
|
|
382
409
|
|
|
383
410
|
```bash
|
|
384
|
-
npx @kuznai/inception-engine init limbo --
|
|
385
|
-
npx @kuznai/inception-engine limbo --
|
|
411
|
+
npx @kuznai/inception-engine init limbo --plan
|
|
412
|
+
npx @kuznai/inception-engine limbo --plan
|
|
386
413
|
```
|
|
387
414
|
|
|
388
415
|
## Agent Detection
|
package/dist/config/agents.js
CHANGED
|
@@ -36,6 +36,14 @@ export const AGENT_REGISTRY = [
|
|
|
36
36
|
windows: ["{home}", ".claude", "CLAUDE.md"],
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
|
+
agentRulesRepoSupport: {
|
|
40
|
+
status: "supported",
|
|
41
|
+
schemaLabel: "repo-local CLAUDE.md",
|
|
42
|
+
path: {
|
|
43
|
+
posix: ["{repo}", "CLAUDE.md"],
|
|
44
|
+
windows: ["{repo}", "CLAUDE.md"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
39
47
|
permissionsSupport: {
|
|
40
48
|
status: "supported",
|
|
41
49
|
schemaLabel: "JSON permissions config",
|
|
@@ -52,6 +60,14 @@ export const AGENT_REGISTRY = [
|
|
|
52
60
|
windows: ["{repo}", ".claude", "agents", "{name}.md"],
|
|
53
61
|
},
|
|
54
62
|
},
|
|
63
|
+
agentRulesWorkspaceSupport: {
|
|
64
|
+
status: "supported",
|
|
65
|
+
schemaLabel: "workspace-local CLAUDE.md",
|
|
66
|
+
path: {
|
|
67
|
+
posix: ["{workspace}", "CLAUDE.md"],
|
|
68
|
+
windows: ["{workspace}", "CLAUDE.md"],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
55
71
|
},
|
|
56
72
|
{
|
|
57
73
|
id: "codex",
|
|
@@ -88,6 +104,14 @@ export const AGENT_REGISTRY = [
|
|
|
88
104
|
windows: ["{home}", ".codex", "AGENTS.md"],
|
|
89
105
|
},
|
|
90
106
|
},
|
|
107
|
+
agentRulesRepoSupport: {
|
|
108
|
+
status: "supported",
|
|
109
|
+
schemaLabel: "repo-local AGENTS.md",
|
|
110
|
+
path: {
|
|
111
|
+
posix: ["{repo}", "AGENTS.md"],
|
|
112
|
+
windows: ["{repo}", "AGENTS.md"],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
91
115
|
permissionsSupport: {
|
|
92
116
|
status: "supported",
|
|
93
117
|
schemaLabel: "TOML approval policy config",
|
|
@@ -101,6 +125,14 @@ export const AGENT_REGISTRY = [
|
|
|
101
125
|
schemaLabel: "dedicated agent definition directory",
|
|
102
126
|
reason: "OpenAI Codex does not expose a documented dedicated per-agent definition directory surface separate from AGENTS.md and config.toml — use agentRules to deploy persona instructions instead",
|
|
103
127
|
},
|
|
128
|
+
agentRulesWorkspaceSupport: {
|
|
129
|
+
status: "supported",
|
|
130
|
+
schemaLabel: "workspace-local AGENTS.md",
|
|
131
|
+
path: {
|
|
132
|
+
posix: ["{workspace}", "AGENTS.md"],
|
|
133
|
+
windows: ["{workspace}", "AGENTS.md"],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
104
136
|
},
|
|
105
137
|
{
|
|
106
138
|
id: "gemini-cli",
|
|
@@ -138,6 +170,14 @@ export const AGENT_REGISTRY = [
|
|
|
138
170
|
windows: ["{home}", ".gemini", "GEMINI.md"],
|
|
139
171
|
},
|
|
140
172
|
},
|
|
173
|
+
agentRulesRepoSupport: {
|
|
174
|
+
status: "supported",
|
|
175
|
+
schemaLabel: "repo-local GEMINI.md",
|
|
176
|
+
path: {
|
|
177
|
+
posix: ["{repo}", "GEMINI.md"],
|
|
178
|
+
windows: ["{repo}", "GEMINI.md"],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
141
181
|
permissionsSupport: {
|
|
142
182
|
status: "unsupported",
|
|
143
183
|
schemaLabel: "global permissions surface",
|
|
@@ -151,6 +191,14 @@ export const AGENT_REGISTRY = [
|
|
|
151
191
|
windows: ["{repo}", ".gemini", "agents", "{name}.md"],
|
|
152
192
|
},
|
|
153
193
|
},
|
|
194
|
+
agentRulesWorkspaceSupport: {
|
|
195
|
+
status: "supported",
|
|
196
|
+
schemaLabel: "workspace-local GEMINI.md",
|
|
197
|
+
path: {
|
|
198
|
+
posix: ["{workspace}", "GEMINI.md"],
|
|
199
|
+
windows: ["{workspace}", "GEMINI.md"],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
154
202
|
},
|
|
155
203
|
{
|
|
156
204
|
id: "antigravity",
|
|
@@ -179,12 +227,25 @@ export const AGENT_REGISTRY = [
|
|
|
179
227
|
windows: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
180
228
|
},
|
|
181
229
|
},
|
|
230
|
+
// Antigravity shares its instruction surfaces with gemini-cli (both target
|
|
231
|
+
// the same GEMINI.md paths). surfaceKind: shared-via drives deduplication
|
|
232
|
+
// when both agents appear in the same agentRules entry.
|
|
182
233
|
agentRulesSupport: {
|
|
183
234
|
status: "supported",
|
|
184
|
-
|
|
235
|
+
surfaceKind: { kind: "shared-via", via: "gemini-cli" },
|
|
236
|
+
schemaLabel: "global Gemini blueprint instructions file",
|
|
185
237
|
path: {
|
|
186
|
-
posix: ["{
|
|
187
|
-
windows: ["{
|
|
238
|
+
posix: ["{home}", ".gemini", "GEMINI.md"],
|
|
239
|
+
windows: ["{home}", ".gemini", "GEMINI.md"],
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
agentRulesRepoSupport: {
|
|
243
|
+
status: "supported",
|
|
244
|
+
surfaceKind: { kind: "shared-via", via: "gemini-cli" },
|
|
245
|
+
schemaLabel: "repo-local GEMINI.md",
|
|
246
|
+
path: {
|
|
247
|
+
posix: ["{repo}", "GEMINI.md"],
|
|
248
|
+
windows: ["{repo}", "GEMINI.md"],
|
|
188
249
|
},
|
|
189
250
|
},
|
|
190
251
|
permissionsSupport: {
|
|
@@ -200,6 +261,12 @@ export const AGENT_REGISTRY = [
|
|
|
200
261
|
windows: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
201
262
|
},
|
|
202
263
|
},
|
|
264
|
+
agentRulesWorkspaceSupport: {
|
|
265
|
+
status: "unsupported",
|
|
266
|
+
schemaLabel: "workspace-local instruction surface",
|
|
267
|
+
reason: "Antigravity is natively repo-local and does not expose a separate workspace-local instruction surface",
|
|
268
|
+
},
|
|
269
|
+
instructionFrontmatterRequired: true,
|
|
203
270
|
},
|
|
204
271
|
{
|
|
205
272
|
id: "opencode",
|
|
@@ -237,6 +304,14 @@ export const AGENT_REGISTRY = [
|
|
|
237
304
|
windows: ["{appdata}", "opencode", "AGENTS.md"],
|
|
238
305
|
},
|
|
239
306
|
},
|
|
307
|
+
agentRulesRepoSupport: {
|
|
308
|
+
status: "supported",
|
|
309
|
+
schemaLabel: "repo-local AGENTS.md",
|
|
310
|
+
path: {
|
|
311
|
+
posix: ["{repo}", "AGENTS.md"],
|
|
312
|
+
windows: ["{repo}", "AGENTS.md"],
|
|
313
|
+
},
|
|
314
|
+
},
|
|
240
315
|
permissionsSupport: {
|
|
241
316
|
status: "unsupported",
|
|
242
317
|
schemaLabel: "global permissions surface",
|
|
@@ -250,6 +325,11 @@ export const AGENT_REGISTRY = [
|
|
|
250
325
|
windows: ["{repo}", ".opencode", "agents", "{name}.md"],
|
|
251
326
|
},
|
|
252
327
|
},
|
|
328
|
+
agentRulesWorkspaceSupport: {
|
|
329
|
+
status: "unsupported",
|
|
330
|
+
schemaLabel: "workspace-local AGENTS.md",
|
|
331
|
+
reason: "OpenCode does not expose a documented workspace-local instruction surface distinct from repo-local AGENTS.md",
|
|
332
|
+
},
|
|
253
333
|
},
|
|
254
334
|
{
|
|
255
335
|
id: "github-copilot",
|
|
@@ -258,6 +338,7 @@ export const AGENT_REGISTRY = [
|
|
|
258
338
|
// from `.claude/skills/` (the same path used by claude-code). Deploying
|
|
259
339
|
// via the `claude-code` skills target automatically covers Copilot — no
|
|
260
340
|
// separate `~/.copilot/skills/` path is needed or maintained.
|
|
341
|
+
skillsSurfaceKind: { kind: "shared-via", via: "claude-code" },
|
|
261
342
|
detectPaths: {
|
|
262
343
|
posix: ["{home}", ".copilot"],
|
|
263
344
|
windows: ["{home}", ".copilot"],
|
|
@@ -274,10 +355,49 @@ export const AGENT_REGISTRY = [
|
|
|
274
355
|
plannedSurface: "devcontainer (.devcontainer/devcontainer.json) and agent-frontmatter (.github/agents/*.agent.md)",
|
|
275
356
|
reason: "GitHub Copilot MCP support will be implemented via repo-scoped devcontainer features and agent-frontmatter mappings — surfaces that are genuinely Copilot-specific and not covered by other agent targets",
|
|
276
357
|
},
|
|
358
|
+
// GitHub Copilot reads Claude-native instruction files (CLAUDE.md) without
|
|
359
|
+
// a separate deploy action. These surfaces are marked shared-via claude-code
|
|
360
|
+
// with requiresPrimary: true so deploy skips emitting a separate action
|
|
361
|
+
// when claude-code is also targeted, and emits a guidance warning when it
|
|
362
|
+
// is not (copilot cannot write to these surfaces independently).
|
|
277
363
|
agentRulesSupport: {
|
|
278
|
-
status: "
|
|
364
|
+
status: "supported",
|
|
365
|
+
surfaceKind: {
|
|
366
|
+
kind: "shared-via",
|
|
367
|
+
via: "claude-code",
|
|
368
|
+
requiresPrimary: true,
|
|
369
|
+
},
|
|
279
370
|
schemaLabel: "Claude-native shared instructions",
|
|
280
|
-
|
|
371
|
+
path: {
|
|
372
|
+
posix: ["{home}", ".claude", "CLAUDE.md"],
|
|
373
|
+
windows: ["{home}", ".claude", "CLAUDE.md"],
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
agentRulesRepoSupport: {
|
|
377
|
+
status: "supported",
|
|
378
|
+
surfaceKind: {
|
|
379
|
+
kind: "shared-via",
|
|
380
|
+
via: "claude-code",
|
|
381
|
+
requiresPrimary: true,
|
|
382
|
+
},
|
|
383
|
+
schemaLabel: "repo-local CLAUDE.md",
|
|
384
|
+
path: {
|
|
385
|
+
posix: ["{repo}", "CLAUDE.md"],
|
|
386
|
+
windows: ["{repo}", "CLAUDE.md"],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
agentRulesWorkspaceSupport: {
|
|
390
|
+
status: "supported",
|
|
391
|
+
surfaceKind: {
|
|
392
|
+
kind: "shared-via",
|
|
393
|
+
via: "claude-code",
|
|
394
|
+
requiresPrimary: true,
|
|
395
|
+
},
|
|
396
|
+
schemaLabel: "workspace-local CLAUDE.md",
|
|
397
|
+
path: {
|
|
398
|
+
posix: ["{workspace}", "CLAUDE.md"],
|
|
399
|
+
windows: ["{workspace}", "CLAUDE.md"],
|
|
400
|
+
},
|
|
281
401
|
},
|
|
282
402
|
permissionsSupport: {
|
|
283
403
|
status: "unsupported",
|
|
@@ -293,6 +413,8 @@ export const AGENT_REGISTRY = [
|
|
|
293
413
|
},
|
|
294
414
|
},
|
|
295
415
|
policyNote: "Organization policies may override locally deployed configuration. Verify with your GitHub org admin if deployed skills or rules are not active.",
|
|
416
|
+
instructionFrontmatterRequired: true,
|
|
417
|
+
enterprisePolicyDetection: true,
|
|
296
418
|
},
|
|
297
419
|
];
|
|
298
420
|
export const AGENT_REGISTRY_BY_ID = Object.fromEntries(AGENT_REGISTRY.map((a) => [a.id, a]));
|
|
@@ -16,5 +16,5 @@ export interface AgentDefinitionsAdapterResult {
|
|
|
16
16
|
* Target paths use the `{repo}` placeholder so definitions land in the
|
|
17
17
|
* repository being deployed, not the user's home directory.
|
|
18
18
|
*/
|
|
19
|
-
export declare function compileAgentDefinitionActions(entry: AgentDefinitionEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string): Promise<AgentDefinitionsAdapterResult>;
|
|
20
|
-
export declare function compileAgentDefinitionReverts(entry: AgentDefinitionEntry, agentFilter: AgentId[] | null, home: string, repo?: string): FileWriteRevertAction[];
|
|
19
|
+
export declare function compileAgentDefinitionActions(entry: AgentDefinitionEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, workspace?: string): Promise<AgentDefinitionsAdapterResult>;
|
|
20
|
+
export declare function compileAgentDefinitionReverts(entry: AgentDefinitionEntry, agentFilter: AgentId[] | null, home: string, repo?: string, workspace?: string): FileWriteRevertAction[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
|
|
3
3
|
import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
|
|
4
|
-
import { validateAgentRuleMarkdownPath, validateSourceFile, validateSourcePath, } from "../validation.js";
|
|
4
|
+
import { validateAgentRuleMarkdownPath, validateInstructionFileRequirements, validateSourceFile, validateSourcePath, } from "../validation.js";
|
|
5
5
|
/**
|
|
6
6
|
* Compiles deploy actions for agentDefinitions manifest entries.
|
|
7
7
|
*
|
|
@@ -14,7 +14,7 @@ import { validateAgentRuleMarkdownPath, validateSourceFile, validateSourcePath,
|
|
|
14
14
|
* Target paths use the `{repo}` placeholder so definitions land in the
|
|
15
15
|
* repository being deployed, not the user's home directory.
|
|
16
16
|
*/
|
|
17
|
-
export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo) {
|
|
17
|
+
export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace) {
|
|
18
18
|
const actions = [];
|
|
19
19
|
const warnings = [];
|
|
20
20
|
const platform = getPlatformKey();
|
|
@@ -43,7 +43,7 @@ export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSo
|
|
|
43
43
|
supportedTargets.push({
|
|
44
44
|
agentId,
|
|
45
45
|
confidence: agent.provenance.agentDefinitions ?? "provisional",
|
|
46
|
-
target: resolvePlaceholders(support.path[platform], entry.name, home, repo),
|
|
46
|
+
target: resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace),
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
if (supportedTargets.length === 0) {
|
|
@@ -55,6 +55,7 @@ export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSo
|
|
|
55
55
|
await validateSourceFile(source, entry.path);
|
|
56
56
|
for (const target of supportedTargets) {
|
|
57
57
|
validateAgentRuleMarkdownPath(entry.path, target.agentId);
|
|
58
|
+
await validateInstructionFileRequirements(source, entry.path, target.agentId);
|
|
58
59
|
actions.push({
|
|
59
60
|
kind: "file-write",
|
|
60
61
|
skill: entry.name,
|
|
@@ -66,7 +67,7 @@ export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSo
|
|
|
66
67
|
}
|
|
67
68
|
return { actions, warnings };
|
|
68
69
|
}
|
|
69
|
-
export function compileAgentDefinitionReverts(entry, agentFilter, home, repo) {
|
|
70
|
+
export function compileAgentDefinitionReverts(entry, agentFilter, home, repo, workspace) {
|
|
70
71
|
const actions = [];
|
|
71
72
|
const platform = getPlatformKey();
|
|
72
73
|
for (const agentId of entry.agents) {
|
|
@@ -78,7 +79,7 @@ export function compileAgentDefinitionReverts(entry, agentFilter, home, repo) {
|
|
|
78
79
|
support.status === "unsupported" ||
|
|
79
80
|
support.status === "planned")
|
|
80
81
|
continue;
|
|
81
|
-
const target = resolvePlaceholders(support.path[platform], entry.name, home, repo);
|
|
82
|
+
const target = resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace);
|
|
82
83
|
actions.push({
|
|
83
84
|
kind: "file-write",
|
|
84
85
|
skill: entry.name,
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Splits a Markdown string into YAML frontmatter and the remaining body.
|
|
3
|
+
* Expects the file to start with --- delimiter.
|
|
4
|
+
*/
|
|
5
|
+
export declare function splitFrontmatter(raw: string): {
|
|
6
|
+
frontmatter: string;
|
|
7
|
+
body: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Parses a Markdown string with YAML frontmatter.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseFrontmatterDocument<T = Record<string, unknown>>(raw: string): {
|
|
13
|
+
attributes: T;
|
|
14
|
+
body: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Serializes an object to a YAML block.
|
|
4
18
|
*/
|
|
5
19
|
export declare function serializeFrontmatter(data: Record<string, unknown>): string;
|
|
6
20
|
/**
|
|
7
21
|
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
8
|
-
* If `body` is provided it is appended after the closing delimiter.
|
|
9
22
|
*/
|
|
10
23
|
export declare function buildFrontmatterDocument(frontmatter: Record<string, unknown>, body?: string): string;
|
|
11
24
|
/**
|
|
12
|
-
* Reads an existing `.md` file and parses its frontmatter
|
|
13
|
-
* `front-matter` package). Returns the parsed attributes and raw body.
|
|
25
|
+
* Reads an existing `.md` file and parses its frontmatter.
|
|
14
26
|
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
15
27
|
*/
|
|
16
28
|
export declare function readFrontmatterFile(filePath: string): Promise<{
|
|
@@ -1,71 +1,52 @@
|
|
|
1
1
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (typeof value === "string") {
|
|
14
|
-
const needsQuotes = /[:#[\]{},|>&*!'"@`]|^\s|\s$/.test(value);
|
|
15
|
-
return needsQuotes
|
|
16
|
-
? `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`
|
|
17
|
-
: value;
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
/**
|
|
5
|
+
* Splits a Markdown string into YAML frontmatter and the remaining body.
|
|
6
|
+
* Expects the file to start with --- delimiter.
|
|
7
|
+
*/
|
|
8
|
+
export function splitFrontmatter(raw) {
|
|
9
|
+
const lines = raw.split(/\r?\n/);
|
|
10
|
+
if (lines[0]?.trim() !== "---") {
|
|
11
|
+
return { frontmatter: "", body: raw };
|
|
18
12
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
? serializeScalar(item)
|
|
29
|
-
: JSON.stringify(item);
|
|
30
|
-
return `${pad} - ${scalar}`;
|
|
31
|
-
});
|
|
32
|
-
return [`${pad}${key}:`, ...items].join("\n");
|
|
33
|
-
}
|
|
34
|
-
function serializeObject(key, obj, pad) {
|
|
35
|
-
const inner = serializeFrontmatterAtDepth(obj, `${pad} `);
|
|
36
|
-
return inner ? `${pad}${key}:\n${inner}` : `${pad}${key}: {}`;
|
|
13
|
+
const closingIndex = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
|
|
14
|
+
if (closingIndex === -1) {
|
|
15
|
+
return { frontmatter: "", body: raw };
|
|
16
|
+
}
|
|
17
|
+
// Preserve the actual lines for the body to avoid normalizing line endings if not needed
|
|
18
|
+
// but for frontmatter block, we join with \n for the YAML parser
|
|
19
|
+
const frontmatter = lines.slice(1, closingIndex).join("\n");
|
|
20
|
+
const body = lines.slice(closingIndex + 1).join("\n");
|
|
21
|
+
return { frontmatter, body };
|
|
37
22
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
else if (typeof value === "object") {
|
|
47
|
-
lines.push(serializeObject(key, value, pad));
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
lines.push(`${pad}${key}: ${serializeScalar(value)}`);
|
|
51
|
-
}
|
|
23
|
+
/**
|
|
24
|
+
* Parses a Markdown string with YAML frontmatter.
|
|
25
|
+
*/
|
|
26
|
+
export function parseFrontmatterDocument(raw) {
|
|
27
|
+
const { frontmatter, body } = splitFrontmatter(raw);
|
|
28
|
+
if (!(frontmatter || raw.startsWith("---"))) {
|
|
29
|
+
return { attributes: {}, body };
|
|
52
30
|
}
|
|
53
|
-
|
|
31
|
+
const attributes = YAML.parse(frontmatter);
|
|
32
|
+
return { attributes: (attributes || {}), body };
|
|
54
33
|
}
|
|
55
34
|
/**
|
|
56
|
-
* Serializes
|
|
57
|
-
* `---` frontmatter delimiters.
|
|
35
|
+
* Serializes an object to a YAML block.
|
|
58
36
|
*/
|
|
59
37
|
export function serializeFrontmatter(data) {
|
|
60
|
-
|
|
38
|
+
// Using a consistent indentation that matches standard YAML
|
|
39
|
+
return YAML.stringify(data, { indent: 2 }).trim();
|
|
61
40
|
}
|
|
62
41
|
/**
|
|
63
42
|
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
64
|
-
* If `body` is provided it is appended after the closing delimiter.
|
|
65
43
|
*/
|
|
66
44
|
export function buildFrontmatterDocument(frontmatter, body = "") {
|
|
67
45
|
const serialized = serializeFrontmatter(frontmatter);
|
|
68
|
-
|
|
46
|
+
// Ensure exactly one newline after the closing delimiter before the body
|
|
47
|
+
const cleanBody = body.trimStart();
|
|
48
|
+
const separator = cleanBody ? "\n\n" : "\n";
|
|
49
|
+
return `---\n${serialized}\n---\n${separator}${cleanBody}`;
|
|
69
50
|
}
|
|
70
51
|
function createAtomicTempPath(targetPath) {
|
|
71
52
|
return `${targetPath}.inception-tmp-${process.pid}-${Date.now()}-${Math.random()
|
|
@@ -73,8 +54,7 @@ function createAtomicTempPath(targetPath) {
|
|
|
73
54
|
.slice(2)}`;
|
|
74
55
|
}
|
|
75
56
|
/**
|
|
76
|
-
* Reads an existing `.md` file and parses its frontmatter
|
|
77
|
-
* `front-matter` package). Returns the parsed attributes and raw body.
|
|
57
|
+
* Reads an existing `.md` file and parses its frontmatter.
|
|
78
58
|
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
79
59
|
*/
|
|
80
60
|
export async function readFrontmatterFile(filePath) {
|
|
@@ -88,8 +68,7 @@ export async function readFrontmatterFile(filePath) {
|
|
|
88
68
|
return { attributes: {}, body: "" };
|
|
89
69
|
throw err;
|
|
90
70
|
}
|
|
91
|
-
|
|
92
|
-
return { attributes: parsed.attributes, body: parsed.body };
|
|
71
|
+
return parseFrontmatterDocument(raw);
|
|
93
72
|
}
|
|
94
73
|
/**
|
|
95
74
|
* Atomically writes a Markdown file with the given frontmatter and optional
|
|
@@ -10,4 +10,4 @@ export interface AdapterResult {
|
|
|
10
10
|
actions: AdapterAction[];
|
|
11
11
|
warnings: PlanWarning[];
|
|
12
12
|
}
|
|
13
|
-
export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], permissions: PermissionsEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, agentDefinitions?: AgentDefinitionEntry[]): Promise<AdapterResult>;
|
|
13
|
+
export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], permissions: PermissionsEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, agentDefinitions?: AgentDefinitionEntry[], workspace?: string): Promise<AdapterResult>;
|
|
@@ -3,16 +3,16 @@ import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
|
|
|
3
3
|
import { compilePermissionsActions, compilePermissionsReverts, } from "./permissions.js";
|
|
4
4
|
import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
|
|
5
5
|
export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
|
|
6
|
-
export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions) {
|
|
6
|
+
export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions, workspace) {
|
|
7
7
|
const actions = [];
|
|
8
8
|
const warnings = [];
|
|
9
9
|
for (const entry of mcpServers) {
|
|
10
|
-
const r = compileMcpServerActions(entry, detectedAgents, home, repo);
|
|
10
|
+
const r = compileMcpServerActions(entry, detectedAgents, home, repo, workspace);
|
|
11
11
|
actions.push(...r.actions);
|
|
12
12
|
warnings.push(...r.warnings);
|
|
13
13
|
}
|
|
14
14
|
for (const entry of agentRules) {
|
|
15
|
-
const r = await compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo);
|
|
15
|
+
const r = await compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace);
|
|
16
16
|
actions.push(...r.actions);
|
|
17
17
|
warnings.push(...r.warnings);
|
|
18
18
|
}
|
|
@@ -22,7 +22,7 @@ export async function compileAdapterActions(mcpServers, agentRules, permissions,
|
|
|
22
22
|
warnings.push(...r.warnings);
|
|
23
23
|
}
|
|
24
24
|
for (const entry of agentDefinitions ?? []) {
|
|
25
|
-
const r = await compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo);
|
|
25
|
+
const r = await compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace);
|
|
26
26
|
actions.push(...r.actions);
|
|
27
27
|
warnings.push(...r.warnings);
|
|
28
28
|
}
|
|
@@ -4,5 +4,5 @@ export interface McpAdapterResult {
|
|
|
4
4
|
actions: Array<ConfigPatchDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction>;
|
|
5
5
|
warnings: PlanWarning[];
|
|
6
6
|
}
|
|
7
|
-
export declare function compileMcpServerActions(entry: McpServerEntry, detectedAgents: AgentId[], home: string, repo?: string): McpAdapterResult;
|
|
8
|
-
export declare function compileMcpServerReverts(entry: McpServerEntry, agentFilter: AgentId[] | null, home: string, repo?: string): Array<ConfigPatchRevertAction | TomlPatchRevertAction | FrontmatterEmitRevertAction>;
|
|
7
|
+
export declare function compileMcpServerActions(entry: McpServerEntry, detectedAgents: AgentId[], home: string, repo?: string, workspace?: string): McpAdapterResult;
|
|
8
|
+
export declare function compileMcpServerReverts(entry: McpServerEntry, agentFilter: AgentId[] | null, home: string, repo?: string, workspace?: string): Array<ConfigPatchRevertAction | TomlPatchRevertAction | FrontmatterEmitRevertAction>;
|