@kuznai/inception-engine 0.20.0 → 0.22.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 +44 -4
- package/dist/src/config/agents.js +70 -0
- package/dist/src/core/adapters/hooks.d.ts +8 -0
- package/dist/src/core/adapters/hooks.js +86 -0
- package/dist/src/core/adapters/index.d.ts +4 -3
- package/dist/src/core/adapters/index.js +19 -22
- package/dist/src/core/adapters/mcp.js +15 -1
- package/dist/src/core/capabilities.d.ts +1 -1
- package/dist/src/core/capabilities.js +17 -2
- package/dist/src/core/deploy.js +18 -19
- package/dist/src/core/detect.js +2 -7
- package/dist/src/core/init.js +20 -11
- package/dist/src/core/preflight.js +35 -19
- package/dist/src/core/revert.js +1 -1
- package/dist/src/core/validation.d.ts +1 -0
- package/dist/src/core/validation.js +15 -0
- package/dist/src/errors.d.ts +3 -1
- package/dist/src/errors.js +2 -2
- package/dist/src/schemas/manifest.d.ts +27 -0
- package/dist/src/schemas/manifest.js +11 -1
- package/dist/src/types.d.ts +8 -2
- package/dist/test/os/windows/agentRules-integration.test.d.ts +1 -0
- package/dist/test/os/windows/agentRules-integration.test.js +245 -0
- package/dist/test/unit/adapters.test.js +86 -2
- package/dist/test/unit/deploy.test.js +5 -3
- package/dist/test/unit/init-fixture.test.d.ts +1 -0
- package/dist/test/unit/init-fixture.test.js +153 -0
- package/dist/test/unit/preflight.test.js +18 -0
- package/dist/test/unit/revert.test.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,9 +50,10 @@ Before executing, the deploy command runs preflight analysis on instruction file
|
|
|
50
50
|
| Skills (SKILL.md) | All agents via manifest and CLI | All agents |
|
|
51
51
|
| File write | All agents via manifest and CLI | All agents |
|
|
52
52
|
| Config patch (JSON merge) | All agents via manifest and CLI | All agents |
|
|
53
|
-
| MCP Servers | claude-code (`scope: "global"` → `~/.claude.json`; `scope: "repo"` → `{repo}/.claude/mcp.json`; `scope: "workspace"` → `{workspace}/.claude/mcp.json`), gemini-cli, codex, antigravity, opencode; github-copilot with `scope: "repo"` deploys to `{repo}/.vscode/mcp.json` and `scope: "workspace"` deploys to `{workspace}/.vscode/mcp.json`; github-copilot with `scope: "global"` (default) is unsupported and warns | claude-code, gemini-cli, codex, antigravity, opencode, github-copilot |
|
|
53
|
+
| MCP Servers | claude-code (`scope: "global"` → `~/.claude.json`; `scope: "repo"` → `{repo}/.claude/mcp.json`; `scope: "workspace"` → `{workspace}/.claude/mcp.json`), gemini-cli, codex, antigravity (`scope: "global"` → `~/.gemini/antigravity/mcp_config.json`; `scope: "repo"` → `{repo}/.agents/rules/{name}.md`), opencode; github-copilot with `scope: "repo"` deploys to `{repo}/.vscode/mcp.json` and `scope: "workspace"` deploys to `{workspace}/.vscode/mcp.json`; github-copilot with `scope: "global"` (default) is unsupported and warns | claude-code, gemini-cli, codex, antigravity, opencode, github-copilot |
|
|
54
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 |
|
|
55
55
|
| Permissions / Approval Config | claude-code (`~/.claude/settings.json`), codex (`~/.codex/config.toml`), opencode (`~/.config/opencode/opencode.json` on POSIX, `%APPDATA%\\opencode\\opencode.json` on Windows); other agents are warned and skipped | claude-code, codex, opencode |
|
|
56
|
+
| Execution Hooks | claude-code (`~/.claude/settings.json`), github-copilot (`planned`); other agents are warned and skipped | claude-code |
|
|
56
57
|
| Agent Definitions | claude-code (`{repo}/.claude/agents/{name}.md`), gemini-cli (`{repo}/.gemini/agents/{name}.md` or `.toml`, plus `scope: "global"` to `~/.gemini/agents/{name}.md` or `.toml`), antigravity (`{repo}/.agents/rules/{name}.md`), opencode (`{repo}/.opencode/agents/{name}.md`, plus `scope: "global"` to the user config dir), github-copilot (`{repo}/.github/copilot/agents/{name}.md`, with migration from legacy `.github/agents/{name}.agent.md`); codex is warned and skipped | All supported agents |
|
|
57
58
|
| `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`); shared surfaces default to the primary deploy target instead of shared riders; emits hints for `files/` and `configs/` directories | N/A |
|
|
58
59
|
| Instruction preflight analysis | Emits capability warnings for implementation-only, planned, unsupported, and shared-through surfaces used by the manifest; 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; emits a `config-authority` warning when Gemini CLI's `settings.json` contains an `instructionFilename` override that differs from the deploy target | N/A |
|
|
@@ -135,6 +136,17 @@ Create an `inception.json` file at the root of your skills directory:
|
|
|
135
136
|
"path": "agents/code-reviewer.md",
|
|
136
137
|
"agents": ["claude-code", "opencode", "github-copilot"]
|
|
137
138
|
}
|
|
139
|
+
],
|
|
140
|
+
"hooks": [
|
|
141
|
+
{
|
|
142
|
+
"name": "pre-exec-check",
|
|
143
|
+
"agents": ["claude-code"],
|
|
144
|
+
"config": {
|
|
145
|
+
"hooks": {
|
|
146
|
+
"pre_exec": "scripts/check-env.sh"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
138
150
|
]
|
|
139
151
|
}
|
|
140
152
|
```
|
|
@@ -166,17 +178,18 @@ Each **mcpServer** entry registers an MCP server into the agent's config file by
|
|
|
166
178
|
- **name** - Unique identifier (same format as skill names); used as the server's key in the config
|
|
167
179
|
- **agents** - Array of agent IDs to register this server with
|
|
168
180
|
- **config** - Raw server descriptor object. For the currently supported JSON-backed adapters, inception-engine requires at least one non-empty `command` or `url` field, validates `args` as an array of strings when present, and validates `env` as a string-to-string object when present. Additional keys are passed through verbatim.
|
|
169
|
-
- **scope** - `"global"` (default), `"repo"`, or `"
|
|
181
|
+
- **scope** - `"global"` (default), `"repo"`, `"workspace"`, or `"devcontainer"`. For most agents this field is ignored (they have only a single user-level config path). For `github-copilot`, `scope` selects the target file:
|
|
170
182
|
- `"global"` — unsupported; emits a warning and is skipped
|
|
171
183
|
- `"repo"` — deploys to `{repo}/.vscode/mcp.json` under the `servers` key
|
|
172
184
|
- `"workspace"` — deploys to `{workspace}/.vscode/mcp.json` under the `servers` key
|
|
185
|
+
- `"devcontainer"` — deploys to `{repo}/.devcontainer/devcontainer.json` under the `customizations.vscode.mcp.servers` key
|
|
173
186
|
|
|
174
187
|
GitHub Copilot's `.vscode/mcp.json` uses `servers` (not `mcpServers`) as the top-level key and optionally accepts a `type` field (`"stdio"` | `"sse"` | `"http"`) in the server descriptor, which is passed through verbatim.
|
|
175
188
|
|
|
176
189
|
MCP server registration is supported for all agents. Inception-engine automatically uses the correct adapter for each agent's configuration schema:
|
|
177
|
-
- **JSON (Merge Patch)**: `claude-code` (`~/.claude.json` for `scope: "global"`; `{repo}/.claude/mcp.json` for `scope: "repo"`; `{workspace}/.claude/mcp.json` for `scope: "workspace"`), `gemini-cli` (`~/.gemini/settings.json`), `opencode` (`~/.config/opencode/opencode.json` using the custom `"mcp"` key), and `github-copilot` (`{repo}/.vscode/mcp.json
|
|
190
|
+
- **JSON (Merge Patch)**: `claude-code` (`~/.claude.json` for `scope: "global"`; `{repo}/.claude/mcp.json` for `scope: "repo"`; `{workspace}/.claude/mcp.json` for `scope: "workspace"`), `gemini-cli` (`~/.gemini/settings.json`), `antigravity` (`~/.gemini/antigravity/mcp_config.json` for `scope: "global"`), `opencode` (`~/.config/opencode/opencode.json` using the custom `"mcp"` key), and `github-copilot` (`{repo}/.vscode/mcp.json`, `{workspace}/.vscode/mcp.json`, or `{repo}/.devcontainer/devcontainer.json`).
|
|
178
191
|
- **TOML (Patch)**: `codex` (`~/.codex/config.toml`).
|
|
179
|
-
- **Markdown Frontmatter (Emit)**: `antigravity` (repo
|
|
192
|
+
- **Markdown Frontmatter (Emit)**: `antigravity` (`{repo}/.agents/rules/{name}.md` for `scope: "repo"`).
|
|
180
193
|
|
|
181
194
|
For Markdown frontmatter targets, inception-engine now records patch-level provenance for the emitted frontmatter block. Deploy merges only the owned frontmatter keys, preserves unrelated frontmatter and Markdown body content, and `revert` removes only the engine-owned keys instead of deleting the whole file unless inception-engine originally created an otherwise-empty file.
|
|
182
195
|
|
|
@@ -248,6 +261,31 @@ Valid `approval_policy` values are `"auto"`, `"manual"`, `"suggest"`, and `"on-f
|
|
|
248
261
|
|
|
249
262
|
Revert restores the previous config values using the undo patch recorded at deploy time.
|
|
250
263
|
|
|
264
|
+
Each **hooks** entry deploys lifecycle-binding configurations to an agent's execution hook surface:
|
|
265
|
+
|
|
266
|
+
- **name** - Unique identifier (same format as skill names)
|
|
267
|
+
- **agents** - Array of agent IDs to deploy this entry to
|
|
268
|
+
- **config** - Hook configuration payload; shape is validated per agent (see below)
|
|
269
|
+
|
|
270
|
+
Hook deployment is currently supported for `claude-code`. For `github-copilot`, it is marked as `planned`. Other agents emit a warning and are skipped.
|
|
271
|
+
|
|
272
|
+
For `claude-code`, the config is merged into `~/.claude/settings.json`. Only the `hooks` key is accepted:
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"name": "pre-exec-check",
|
|
277
|
+
"agents": ["claude-code"],
|
|
278
|
+
"config": {
|
|
279
|
+
"hooks": {
|
|
280
|
+
"pre_exec": "scripts/check-env.sh",
|
|
281
|
+
"post_exec": "scripts/notify.sh"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Revert restores the previous config values using the undo patch recorded at deploy time.
|
|
288
|
+
|
|
251
289
|
Each **agentDefinitions** entry deploys an agent-definition file to the agent-definition directory of each targeted agent. `scope: "repo"` is the default, and some agents also support `scope: "global"`:
|
|
252
290
|
|
|
253
291
|
- **name** - Unique identifier (same format as skill names); used as the definition filename
|
|
@@ -271,6 +309,8 @@ Global targets where supported:
|
|
|
271
309
|
|
|
272
310
|
For GitHub Copilot, deploy also records migration from the legacy `{repo}/.github/agents/{name}.agent.md` path so older installs can be cleaned up safely.
|
|
273
311
|
|
|
312
|
+
For GitHub Copilot, the `tools` YAML frontmatter field in agent definition files declares which MCP tools and built-in Copilot tools the agent has access to (agent-level tool mapping). Inception-engine validates that `tools`, when present, is an array of strings. Deploy agent-level tool mappings through `agentDefinitions` by including the `tools` field in your source file's frontmatter - no separate manifest section is needed.
|
|
313
|
+
|
|
274
314
|
Revert removes the deployed agent-definition file.
|
|
275
315
|
|
|
276
316
|
## Creating Skills
|
|
@@ -18,6 +18,7 @@ export const AGENT_REGISTRY = [
|
|
|
18
18
|
mcpConfig: "documented",
|
|
19
19
|
agentRules: "documented",
|
|
20
20
|
permissions: "documented",
|
|
21
|
+
hooks: "documented",
|
|
21
22
|
agentDefinitions: "documented",
|
|
22
23
|
},
|
|
23
24
|
mcpSupport: {
|
|
@@ -68,6 +69,14 @@ export const AGENT_REGISTRY = [
|
|
|
68
69
|
windows: ["{home}", ".claude", "settings.json"],
|
|
69
70
|
},
|
|
70
71
|
},
|
|
72
|
+
hooksSupport: {
|
|
73
|
+
status: "supported",
|
|
74
|
+
schemaLabel: "JSON hooks config",
|
|
75
|
+
path: {
|
|
76
|
+
posix: ["{home}", ".claude", "settings.json"],
|
|
77
|
+
windows: ["{home}", ".claude", "settings.json"],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
71
80
|
agentDefinitionsRepoSupport: {
|
|
72
81
|
status: "supported",
|
|
73
82
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
@@ -103,6 +112,7 @@ export const AGENT_REGISTRY = [
|
|
|
103
112
|
detectBinary: "documented",
|
|
104
113
|
agentRules: "documented",
|
|
105
114
|
permissions: "documented",
|
|
115
|
+
hooks: "provisional",
|
|
106
116
|
},
|
|
107
117
|
mcpSupport: {
|
|
108
118
|
status: "supported",
|
|
@@ -136,6 +146,11 @@ export const AGENT_REGISTRY = [
|
|
|
136
146
|
windows: ["{home}", ".codex", "config.toml"],
|
|
137
147
|
},
|
|
138
148
|
},
|
|
149
|
+
hooksSupport: {
|
|
150
|
+
status: "unsupported",
|
|
151
|
+
schemaLabel: "global hooks surface",
|
|
152
|
+
reason: "OpenAI Codex does not expose a documented lifecycle-hook config surface in config.toml",
|
|
153
|
+
},
|
|
139
154
|
agentDefinitionsRepoSupport: {
|
|
140
155
|
status: "unsupported",
|
|
141
156
|
schemaLabel: "dedicated agent definition directory",
|
|
@@ -168,6 +183,7 @@ export const AGENT_REGISTRY = [
|
|
|
168
183
|
detectBinary: "documented",
|
|
169
184
|
mcpConfig: "documented",
|
|
170
185
|
agentRules: "documented",
|
|
186
|
+
hooks: "provisional",
|
|
171
187
|
agentDefinitions: "documented",
|
|
172
188
|
},
|
|
173
189
|
mcpSupport: {
|
|
@@ -202,6 +218,12 @@ export const AGENT_REGISTRY = [
|
|
|
202
218
|
schemaLabel: "global permissions surface",
|
|
203
219
|
reason: "Gemini CLI does not expose a documented global per-user permission or approval config surface",
|
|
204
220
|
},
|
|
221
|
+
hooksSupport: {
|
|
222
|
+
status: "planned",
|
|
223
|
+
schemaLabel: "global hooks surface",
|
|
224
|
+
plannedSurface: "settings.json hooks field",
|
|
225
|
+
reason: "Gemini CLI execution hooks are emerging and not yet settled",
|
|
226
|
+
},
|
|
205
227
|
agentDefinitionsSupport: {
|
|
206
228
|
status: "supported",
|
|
207
229
|
schemaLabel: "global agent definition Markdown file",
|
|
@@ -263,6 +285,14 @@ export const AGENT_REGISTRY = [
|
|
|
263
285
|
agentDefinitions: "documented",
|
|
264
286
|
},
|
|
265
287
|
mcpSupport: {
|
|
288
|
+
status: "supported",
|
|
289
|
+
schemaLabel: "global mcp_config.json",
|
|
290
|
+
path: {
|
|
291
|
+
posix: ["{home}", ".gemini", "antigravity", "mcp_config.json"],
|
|
292
|
+
windows: ["{home}", ".gemini", "antigravity", "mcp_config.json"],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
mcpRepoSupport: {
|
|
266
296
|
status: "supported",
|
|
267
297
|
schemaLabel: "repo-local frontmatter-emit MCP rules",
|
|
268
298
|
path: {
|
|
@@ -296,6 +326,11 @@ export const AGENT_REGISTRY = [
|
|
|
296
326
|
schemaLabel: "global permissions surface",
|
|
297
327
|
reason: "Antigravity does not expose a documented global per-user permission or approval config surface",
|
|
298
328
|
},
|
|
329
|
+
hooksSupport: {
|
|
330
|
+
status: "unsupported",
|
|
331
|
+
schemaLabel: "global hooks surface",
|
|
332
|
+
reason: "Antigravity does not expose a documented global per-user hook config surface",
|
|
333
|
+
},
|
|
299
334
|
agentDefinitionsRepoSupport: {
|
|
300
335
|
status: "supported",
|
|
301
336
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
@@ -330,6 +365,7 @@ export const AGENT_REGISTRY = [
|
|
|
330
365
|
agentRules: "documented",
|
|
331
366
|
agentDefinitions: "documented",
|
|
332
367
|
permissions: "documented",
|
|
368
|
+
hooks: "provisional",
|
|
333
369
|
},
|
|
334
370
|
mcpSupport: {
|
|
335
371
|
status: "supported",
|
|
@@ -364,6 +400,11 @@ export const AGENT_REGISTRY = [
|
|
|
364
400
|
windows: ["{appdata}", "opencode", "opencode.json"],
|
|
365
401
|
},
|
|
366
402
|
},
|
|
403
|
+
hooksSupport: {
|
|
404
|
+
status: "unsupported",
|
|
405
|
+
schemaLabel: "global hooks surface",
|
|
406
|
+
reason: "OpenCode does not expose a documented lifecycle-hook surface",
|
|
407
|
+
},
|
|
367
408
|
agentDefinitionsSupport: {
|
|
368
409
|
status: "supported",
|
|
369
410
|
schemaLabel: "global agent definition Markdown file",
|
|
@@ -404,6 +445,7 @@ export const AGENT_REGISTRY = [
|
|
|
404
445
|
detectBinary: "documented",
|
|
405
446
|
agentDefinitions: "documented",
|
|
406
447
|
mcpConfig: "documented",
|
|
448
|
+
hooks: "provisional",
|
|
407
449
|
},
|
|
408
450
|
mcpSupport: {
|
|
409
451
|
status: "unsupported",
|
|
@@ -472,11 +514,26 @@ export const AGENT_REGISTRY = [
|
|
|
472
514
|
windows: ["{workspace}", "CLAUDE.md"],
|
|
473
515
|
},
|
|
474
516
|
},
|
|
517
|
+
mcpDevcontainerSupport: {
|
|
518
|
+
status: "supported",
|
|
519
|
+
schemaLabel: "devcontainer.json MCP surface",
|
|
520
|
+
mcpPatchKey: "customizations.vscode.mcp.servers",
|
|
521
|
+
path: {
|
|
522
|
+
posix: ["{repo}", ".devcontainer", "devcontainer.json"],
|
|
523
|
+
windows: ["{repo}", ".devcontainer", "devcontainer.json"],
|
|
524
|
+
},
|
|
525
|
+
},
|
|
475
526
|
permissionsSupport: {
|
|
476
527
|
status: "unsupported",
|
|
477
528
|
schemaLabel: "global permissions surface",
|
|
478
529
|
reason: "GitHub Copilot permissions are managed via organization policy, not a deployable per-user config surface",
|
|
479
530
|
},
|
|
531
|
+
hooksSupport: {
|
|
532
|
+
status: "planned",
|
|
533
|
+
schemaLabel: "binary execution hooks",
|
|
534
|
+
plannedSurface: "agent frontmatter pre_exec/post_exec hooks",
|
|
535
|
+
reason: "GitHub Copilot binary hook support is planned and requires further validation of the stdin/stdout contract",
|
|
536
|
+
},
|
|
480
537
|
agentDefinitionsRepoSupport: {
|
|
481
538
|
status: "supported",
|
|
482
539
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
@@ -485,7 +542,20 @@ export const AGENT_REGISTRY = [
|
|
|
485
542
|
windows: ["{repo}", ".github", "copilot", "agents", "{name}.md"],
|
|
486
543
|
},
|
|
487
544
|
},
|
|
545
|
+
// GitHub Copilot agent definitions declare MCP tool access via a top-level
|
|
546
|
+
// 'tools' array in YAML frontmatter. This surface is deployed through
|
|
547
|
+
// agentDefinitions - no separate deploy action is emitted.
|
|
548
|
+
mcpAgentFrontmatterSupport: {
|
|
549
|
+
status: "supported",
|
|
550
|
+
schemaLabel: "agent definition frontmatter tools field",
|
|
551
|
+
surfaceKind: { kind: "native" },
|
|
552
|
+
path: {
|
|
553
|
+
posix: ["{repo}", ".github", "copilot", "agents", "{name}.md"],
|
|
554
|
+
windows: ["{repo}", ".github", "copilot", "agents", "{name}.md"],
|
|
555
|
+
},
|
|
556
|
+
},
|
|
488
557
|
policyNote: "Organization policies may override locally deployed configuration. Verify with your GitHub org admin if deployed skills or rules are not active.",
|
|
558
|
+
unsupportedSurfaces: [],
|
|
489
559
|
instructionFrontmatterRequired: true,
|
|
490
560
|
enterprisePolicyDetection: true,
|
|
491
561
|
},
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HookEntry } from "../../schemas/manifest.ts";
|
|
2
|
+
import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, PlanWarning, TomlPatchDeployAction, TomlPatchRevertAction } from "../../types.ts";
|
|
3
|
+
export interface HooksAdapterResult {
|
|
4
|
+
actions: Array<ConfigPatchDeployAction | TomlPatchDeployAction>;
|
|
5
|
+
warnings: PlanWarning[];
|
|
6
|
+
}
|
|
7
|
+
export declare function compileHookActions(entry: HookEntry, detectedAgents: AgentId[], home: string): HooksAdapterResult;
|
|
8
|
+
export declare function compileHookReverts(entry: HookEntry, agentFilter: AgentId[] | null, home: string): Array<ConfigPatchRevertAction | TomlPatchRevertAction>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
|
|
3
|
+
import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
|
|
4
|
+
import { validateHookConfigShape } from "../validation.js";
|
|
5
|
+
function isTomlTarget(targetPath) {
|
|
6
|
+
return path.extname(targetPath).toLowerCase() === ".toml";
|
|
7
|
+
}
|
|
8
|
+
export function compileHookActions(entry, detectedAgents, home) {
|
|
9
|
+
const actions = [];
|
|
10
|
+
const warnings = [];
|
|
11
|
+
const platform = getPlatformKey();
|
|
12
|
+
for (const agentId of entry.agents) {
|
|
13
|
+
if (!detectedAgents.includes(agentId))
|
|
14
|
+
continue;
|
|
15
|
+
const plan = planCapabilityForDeploy({
|
|
16
|
+
agentId,
|
|
17
|
+
capability: "hooks",
|
|
18
|
+
entryName: entry.name,
|
|
19
|
+
targetAgentIds: entry.agents,
|
|
20
|
+
});
|
|
21
|
+
if (plan.outcome === "warn") {
|
|
22
|
+
warnings.push(plan.warning);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (plan.outcome === "native" || plan.outcome === "redundant")
|
|
26
|
+
continue;
|
|
27
|
+
const support = resolveCapabilitySurface(agentId, "hooks").support;
|
|
28
|
+
if (!support)
|
|
29
|
+
continue;
|
|
30
|
+
validateHookConfigShape(entry.config, entry.name, agentId);
|
|
31
|
+
const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
|
|
32
|
+
const resolvedTarget = path.resolve(rawTarget);
|
|
33
|
+
const confidence = plan.confidence ?? "provisional";
|
|
34
|
+
if (isTomlTarget(resolvedTarget)) {
|
|
35
|
+
actions.push({
|
|
36
|
+
kind: "toml-patch",
|
|
37
|
+
skill: entry.name,
|
|
38
|
+
agent: agentId,
|
|
39
|
+
target: resolvedTarget,
|
|
40
|
+
config: entry.config,
|
|
41
|
+
confidence,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
actions.push({
|
|
46
|
+
kind: "config-patch",
|
|
47
|
+
skill: entry.name,
|
|
48
|
+
agent: agentId,
|
|
49
|
+
target: resolvedTarget,
|
|
50
|
+
patch: entry.config,
|
|
51
|
+
confidence,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { actions, warnings };
|
|
56
|
+
}
|
|
57
|
+
export function compileHookReverts(entry, agentFilter, home) {
|
|
58
|
+
const actions = [];
|
|
59
|
+
const platform = getPlatformKey();
|
|
60
|
+
for (const agentId of entry.agents) {
|
|
61
|
+
if (agentFilter && !agentFilter.includes(agentId))
|
|
62
|
+
continue;
|
|
63
|
+
const support = resolveCapabilitySurface(agentId, "hooks").support;
|
|
64
|
+
if (!support)
|
|
65
|
+
continue;
|
|
66
|
+
const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
|
|
67
|
+
const target = path.resolve(rawTarget);
|
|
68
|
+
if (isTomlTarget(target)) {
|
|
69
|
+
actions.push({
|
|
70
|
+
kind: "toml-patch",
|
|
71
|
+
skill: entry.name,
|
|
72
|
+
agent: agentId,
|
|
73
|
+
target,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
actions.push({
|
|
78
|
+
kind: "config-patch",
|
|
79
|
+
skill: entry.name,
|
|
80
|
+
agent: agentId,
|
|
81
|
+
target,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return actions;
|
|
86
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type { AgentDefinitionEntry, AgentRuleEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
|
|
1
|
+
import type { AgentDefinitionEntry, AgentRuleEntry, HookEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
|
|
2
2
|
import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, FrontmatterEmitDeployAction, PlanWarning, TomlPatchDeployAction } from "../../types.ts";
|
|
3
3
|
import { compileAgentDefinitionReverts } from "./agent-definitions.ts";
|
|
4
|
+
import { compileHookReverts } from "./hooks.ts";
|
|
4
5
|
import { compileMcpServerReverts } from "./mcp.ts";
|
|
5
6
|
import { compilePermissionsReverts } from "./permissions.ts";
|
|
6
7
|
import { compileAgentRuleReverts } from "./rules.ts";
|
|
7
|
-
export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
|
|
8
|
+
export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileHookReverts, compileMcpServerReverts, compilePermissionsReverts, };
|
|
8
9
|
export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction;
|
|
9
10
|
export interface AdapterResult {
|
|
10
11
|
actions: AdapterAction[];
|
|
11
12
|
warnings: PlanWarning[];
|
|
12
13
|
}
|
|
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>;
|
|
14
|
+
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, hooks?: HookEntry[]): Promise<AdapterResult>;
|
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
import { compileAgentDefinitionActions, compileAgentDefinitionReverts, } from "./agent-definitions.js";
|
|
2
|
+
import { compileHookActions, compileHookReverts } from "./hooks.js";
|
|
2
3
|
import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
|
|
3
4
|
import { compilePermissionsActions, compilePermissionsReverts, } from "./permissions.js";
|
|
4
5
|
import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
|
|
5
|
-
export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
|
|
6
|
-
|
|
6
|
+
export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileHookReverts, compileMcpServerReverts, compilePermissionsReverts, };
|
|
7
|
+
async function compileAll(entries, fn) {
|
|
8
|
+
const results = await Promise.all(entries.map(fn));
|
|
9
|
+
return {
|
|
10
|
+
actions: results.flatMap((r) => r.actions),
|
|
11
|
+
warnings: results.flatMap((r) => r.warnings),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions, workspace, hooks = []) {
|
|
7
15
|
const actions = [];
|
|
8
16
|
const warnings = [];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
for (const entry of permissions) {
|
|
20
|
-
const r = compilePermissionsActions(entry, detectedAgents, home);
|
|
21
|
-
actions.push(...r.actions);
|
|
22
|
-
warnings.push(...r.warnings);
|
|
23
|
-
}
|
|
24
|
-
for (const entry of agentDefinitions ?? []) {
|
|
25
|
-
const r = await compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace);
|
|
26
|
-
actions.push(...r.actions);
|
|
27
|
-
warnings.push(...r.warnings);
|
|
28
|
-
}
|
|
17
|
+
const [mcp, rules, perms, defs, hookResults] = await Promise.all([
|
|
18
|
+
compileAll(mcpServers, (entry) => compileMcpServerActions(entry, detectedAgents, home, repo, workspace)),
|
|
19
|
+
compileAll(agentRules, (entry) => compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
|
|
20
|
+
compileAll(permissions, (entry) => compilePermissionsActions(entry, detectedAgents, home)),
|
|
21
|
+
compileAll(agentDefinitions ?? [], (entry) => compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
|
|
22
|
+
compileAll(hooks, (entry) => compileHookActions(entry, detectedAgents, home)),
|
|
23
|
+
]);
|
|
24
|
+
actions.push(...mcp.actions, ...rules.actions, ...perms.actions, ...defs.actions, ...hookResults.actions);
|
|
25
|
+
warnings.push(...mcp.warnings, ...rules.warnings, ...perms.warnings, ...defs.warnings, ...hookResults.warnings);
|
|
29
26
|
return { actions, warnings };
|
|
30
27
|
}
|
|
@@ -16,6 +16,20 @@ function isMarkdownTarget(targetPath) {
|
|
|
16
16
|
const ext = path.extname(targetPath).toLowerCase();
|
|
17
17
|
return ext === ".md" || ext === ".markdown";
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds a nested object from a dot-separated key path.
|
|
21
|
+
* e.g. ("a.b", {c: 1}) -> {a: {b: {c: 1}}}
|
|
22
|
+
*/
|
|
23
|
+
function buildNestedPatch(keyPath, leafValue) {
|
|
24
|
+
const parts = keyPath.split(".");
|
|
25
|
+
let current = {
|
|
26
|
+
[parts[parts.length - 1]]: leafValue,
|
|
27
|
+
};
|
|
28
|
+
for (let i = parts.length - 2; i >= 0; i--) {
|
|
29
|
+
current = { [parts[i]]: current };
|
|
30
|
+
}
|
|
31
|
+
return current;
|
|
32
|
+
}
|
|
19
33
|
function buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPatchKey) {
|
|
20
34
|
if (isMarkdownTarget(resolvedTarget)) {
|
|
21
35
|
return {
|
|
@@ -42,7 +56,7 @@ function buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPat
|
|
|
42
56
|
skill: entry.name,
|
|
43
57
|
agent: agentId,
|
|
44
58
|
target: resolvedTarget,
|
|
45
|
-
patch:
|
|
59
|
+
patch: buildNestedPatch(mcpPatchKey, { [entry.name]: entry.config }),
|
|
46
60
|
confidence,
|
|
47
61
|
};
|
|
48
62
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentId, AgentSurfaceSupport, CapabilityKind, Confidence, PlanWarning, SupportedAgentSurface } from "../types.ts";
|
|
2
|
-
type CapabilityScope = "global" | "repo" | "workspace";
|
|
2
|
+
type CapabilityScope = "global" | "repo" | "workspace" | "devcontainer";
|
|
3
3
|
export interface ResolvedCapabilitySurface {
|
|
4
4
|
agentId: AgentId;
|
|
5
5
|
capability: CapabilityKind;
|
|
@@ -19,6 +19,11 @@ function resolveMcpSupport(agentId, scope) {
|
|
|
19
19
|
if (scope === "workspace") {
|
|
20
20
|
return (agent?.mcpWorkspaceSupport ?? agent?.mcpRepoSupport ?? agent?.mcpSupport);
|
|
21
21
|
}
|
|
22
|
+
if (scope === "devcontainer") {
|
|
23
|
+
return (agent?.mcpDevcontainerSupport ??
|
|
24
|
+
agent?.mcpRepoSupport ??
|
|
25
|
+
agent?.mcpSupport);
|
|
26
|
+
}
|
|
22
27
|
return agent?.mcpSupport;
|
|
23
28
|
}
|
|
24
29
|
function resolveAgentDefinitionsSupport(agentId, scope) {
|
|
@@ -45,6 +50,8 @@ function capabilityLabel(capability) {
|
|
|
45
50
|
return "permissions";
|
|
46
51
|
case "agentDefinitions":
|
|
47
52
|
return "agentDefinitions";
|
|
53
|
+
case "hooks":
|
|
54
|
+
return "hooks";
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
function capabilitySurfaceLabel(capability) {
|
|
@@ -59,6 +66,8 @@ function capabilitySurfaceLabel(capability) {
|
|
|
59
66
|
return "permissions";
|
|
60
67
|
case "agentDefinitions":
|
|
61
68
|
return "agent-definitions";
|
|
69
|
+
case "hooks":
|
|
70
|
+
return "hooks";
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
function resolveSkillsCapability(agentId) {
|
|
@@ -110,9 +119,15 @@ function getSurfaceRecordAndConfidence(agentId, capability, scope) {
|
|
|
110
119
|
confidence: agent.provenance.permissions,
|
|
111
120
|
};
|
|
112
121
|
}
|
|
122
|
+
if (capability === "agentDefinitions") {
|
|
123
|
+
return {
|
|
124
|
+
supportRecord: resolveAgentDefinitionsSupport(agentId, scope),
|
|
125
|
+
confidence: agent.provenance.agentDefinitions,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
113
128
|
return {
|
|
114
|
-
supportRecord:
|
|
115
|
-
confidence: agent.provenance.
|
|
129
|
+
supportRecord: agent.hooksSupport,
|
|
130
|
+
confidence: agent.provenance.hooks,
|
|
116
131
|
};
|
|
117
132
|
}
|
|
118
133
|
function resolveUnsupportedSurface(agentId, capability, supportRecord, confidence) {
|