@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.
- package/README.md +48 -22
- package/dist/{config → src/config}/agents.js +87 -14
- package/dist/{core → src/core}/adapters/agent-definitions.d.ts +0 -12
- package/dist/src/core/adapters/agent-definitions.js +162 -0
- package/dist/{core → src/core}/adapters/frontmatter.d.ts +10 -0
- package/dist/{core → src/core}/adapters/frontmatter.js +23 -6
- package/dist/{core → src/core}/adapters/mcp.js +17 -20
- package/dist/{core → src/core}/adapters/permissions.js +16 -20
- package/dist/{core → src/core}/adapters/rules.js +26 -50
- package/dist/src/core/capabilities.d.ts +47 -0
- package/dist/src/core/capabilities.js +280 -0
- package/dist/{core → src/core}/deploy.js +70 -41
- package/dist/{core → src/core}/init.js +18 -24
- package/dist/src/core/merge-patch.d.ts +4 -0
- package/dist/src/core/merge-patch.js +46 -0
- package/dist/{core → src/core}/ownership.js +13 -0
- package/dist/{core → src/core}/preflight.js +141 -29
- package/dist/{core → src/core}/revert.js +86 -26
- package/dist/{core → src/core}/validation.js +20 -0
- package/dist/{schemas → src/schemas}/manifest.d.ts +20 -0
- package/dist/{schemas → src/schemas}/manifest.js +11 -0
- package/dist/{schemas → src/schemas}/registry.d.ts +36 -0
- package/dist/{schemas → src/schemas}/registry.js +12 -4
- package/dist/{types.d.ts → src/types.d.ts} +13 -0
- package/dist/test/helpers/fs.d.ts +2 -0
- package/dist/test/helpers/fs.js +17 -0
- package/dist/test/helpers/path.d.ts +10 -0
- package/dist/test/helpers/path.js +15 -0
- package/dist/test/helpers/skill-dir-scenarios.d.ts +7 -0
- package/dist/test/helpers/skill-dir-scenarios.js +206 -0
- package/dist/test/helpers/skill-dir.d.ts +7 -0
- package/dist/test/helpers/skill-dir.js +46 -0
- package/dist/test/os/cross-platform/cross-platform.test.d.ts +1 -0
- package/dist/test/os/cross-platform/cross-platform.test.js +328 -0
- package/dist/test/os/posix/skill-dir.test.d.ts +1 -0
- package/dist/test/os/posix/skill-dir.test.js +19 -0
- package/dist/test/os/windows/revert-integration.test.d.ts +1 -0
- package/dist/test/os/windows/revert-integration.test.js +72 -0
- package/dist/test/os/windows/skill-dir.test.d.ts +1 -0
- package/dist/test/os/windows/skill-dir.test.js +19 -0
- package/dist/test/unit/adapters.test.d.ts +1 -0
- package/dist/test/unit/adapters.test.js +947 -0
- package/dist/test/unit/capabilities.test.d.ts +1 -0
- package/dist/test/unit/capabilities.test.js +71 -0
- package/dist/test/unit/cli.test.d.ts +1 -0
- package/dist/test/unit/cli.test.js +834 -0
- package/dist/test/unit/deploy.test.d.ts +1 -0
- package/dist/test/unit/deploy.test.js +2481 -0
- package/dist/test/unit/detect.test.d.ts +1 -0
- package/dist/test/unit/detect.test.js +192 -0
- package/dist/test/unit/enterprise.test.d.ts +1 -0
- package/dist/test/unit/enterprise.test.js +106 -0
- package/dist/test/unit/frontmatter.test.d.ts +1 -0
- package/dist/test/unit/frontmatter.test.js +102 -0
- package/dist/test/unit/gemini-north-star.test.d.ts +1 -0
- package/dist/test/unit/gemini-north-star.test.js +243 -0
- package/dist/test/unit/manifest.test.d.ts +1 -0
- package/dist/test/unit/manifest.test.js +737 -0
- package/dist/test/unit/migration-golden.test.d.ts +1 -0
- package/dist/test/unit/migration-golden.test.js +197 -0
- package/dist/test/unit/ownership.test.d.ts +1 -0
- package/dist/test/unit/ownership.test.js +587 -0
- package/dist/test/unit/preflight.test.d.ts +1 -0
- package/dist/test/unit/preflight.test.js +501 -0
- package/dist/test/unit/resolve.test.d.ts +1 -0
- package/dist/test/unit/resolve.test.js +119 -0
- package/dist/test/unit/revert.test.d.ts +1 -0
- package/dist/test/unit/revert.test.js +1004 -0
- package/dist/test/unit/toml.test.d.ts +1 -0
- package/dist/test/unit/toml.test.js +55 -0
- package/package.json +1 -1
- package/dist/core/adapters/agent-definitions.js +0 -91
- /package/dist/{config → src/config}/agents.d.ts +0 -0
- /package/dist/{config → src/config}/manifest.d.ts +0 -0
- /package/dist/{config → src/config}/manifest.js +0 -0
- /package/dist/{core → src/core}/adapters/index.d.ts +0 -0
- /package/dist/{core → src/core}/adapters/index.js +0 -0
- /package/dist/{core → src/core}/adapters/mcp.d.ts +0 -0
- /package/dist/{core → src/core}/adapters/permissions.d.ts +0 -0
- /package/dist/{core → src/core}/adapters/rules.d.ts +0 -0
- /package/dist/{core → src/core}/adapters/toml.d.ts +0 -0
- /package/dist/{core → src/core}/adapters/toml.js +0 -0
- /package/dist/{core → src/core}/deploy.d.ts +0 -0
- /package/dist/{core → src/core}/detect.d.ts +0 -0
- /package/dist/{core → src/core}/detect.js +0 -0
- /package/dist/{core → src/core}/init.d.ts +0 -0
- /package/dist/{core → src/core}/ownership.d.ts +0 -0
- /package/dist/{core → src/core}/preflight.d.ts +0 -0
- /package/dist/{core → src/core}/resolve.d.ts +0 -0
- /package/dist/{core → src/core}/resolve.js +0 -0
- /package/dist/{core → src/core}/revert.d.ts +0 -0
- /package/dist/{core → src/core}/runtime-paths.d.ts +0 -0
- /package/dist/{core → src/core}/runtime-paths.js +0 -0
- /package/dist/{core → src/core}/validation.d.ts +0 -0
- /package/dist/{errors.d.ts → src/errors.d.ts} +0 -0
- /package/dist/{errors.js → src/errors.js} +0 -0
- /package/dist/{formatters.d.ts → src/formatters.d.ts} +0 -0
- /package/dist/{formatters.js → src/formatters.js} +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{index.js → src/index.js} +0 -0
- /package/dist/{logger.d.ts → src/logger.d.ts} +0 -0
- /package/dist/{logger.js → src/logger.js} +0 -0
- /package/dist/{schemas → src/schemas}/errors.d.ts +0 -0
- /package/dist/{schemas → src/schemas}/errors.js +0 -0
- /package/dist/{types.js → src/types.js} +0 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ GitHub Copilot is no longer treated as a separate instruction or skill target in
|
|
|
8
8
|
|
|
9
9
|
The broader portability layer is the roadmap direction, but this README focuses on what is working now.
|
|
10
10
|
|
|
11
|
-
`init` is available as a bootstrap command. It scans for directories containing `SKILL.md`, discovers agent-rules Markdown files using the Claude-first portability conventions, and reads `mcp-servers.json` from the repo root to populate `mcpServers`. `files` and `configs` remain empty — `init` emits guidance when it detects a `files/` or `configs/` directory.
|
|
11
|
+
`init` is available as a bootstrap command. It scans for directories containing `SKILL.md`, discovers agent-rules Markdown files using the Claude-first portability conventions, and reads `mcp-servers.json` from the repo root to populate `mcpServers`. Shared surfaces now default to the primary deploy target in generated manifests: for example, `init` emits `claude-code` rather than `github-copilot` for shared Claude-native skills and rules, and emits `gemini-cli` rather than `antigravity` for shared `GEMINI.md` rules surfaces. `files` and `configs` remain empty — `init` emits guidance when it detects a `files/` or `configs/` directory.
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
@@ -27,7 +27,7 @@ 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
|
|
30
|
+
Before executing, the deploy command runs preflight analysis on instruction files and capability planning inputs. 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 a manifest targets a surface that is implementation-only, planned, unsupported, or shared through another agent, 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
31
|
|
|
32
32
|
## Agent Compatibility Matrix
|
|
33
33
|
|
|
@@ -50,14 +50,14 @@ 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, gemini-cli, codex, antigravity, opencode; github-copilot repo-
|
|
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 |
|
|
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
|
-
| Permissions / Approval Config | claude-code (`~/.claude/settings.json`), codex (`~/.codex/config.toml`); other agents are warned and skipped | claude-code, codex |
|
|
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 |
|
|
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 |
|
|
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
|
+
| 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
|
+
| `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
|
+
| 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 |
|
|
59
59
|
|
|
60
|
-
Features that depend on agent-specific config surfaces are intentionally conservative:
|
|
60
|
+
Features that depend on agent-specific config surfaces are intentionally conservative: deploy and preflight now classify each surface through the same planner. If a target path or schema is implementation-only, planned, unsupported, or only shared through another agent, inception-engine warns and either routes through the primary surface or skips it rather than guessing.
|
|
61
61
|
|
|
62
62
|
For GitHub Copilot specifically, the portability rule is Claude-first: if Copilot accepts the same Claude-native instruction or skill artifact, inception-engine should not add a separate Copilot deployment feature for it.
|
|
63
63
|
|
|
@@ -95,6 +95,12 @@ Create an `inception.json` file at the root of your skills directory:
|
|
|
95
95
|
"name": "my-server",
|
|
96
96
|
"agents": ["claude-code", "gemini-cli"],
|
|
97
97
|
"config": { "command": "npx", "args": ["-y", "my-mcp-server"] }
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "my-server",
|
|
101
|
+
"agents": ["github-copilot"],
|
|
102
|
+
"scope": "repo",
|
|
103
|
+
"config": { "type": "stdio", "command": "npx", "args": ["-y", "my-mcp-server"] }
|
|
98
104
|
}
|
|
99
105
|
],
|
|
100
106
|
"agentRules": [
|
|
@@ -160,13 +166,23 @@ Each **mcpServer** entry registers an MCP server into the agent's config file by
|
|
|
160
166
|
- **name** - Unique identifier (same format as skill names); used as the server's key in the config
|
|
161
167
|
- **agents** - Array of agent IDs to register this server with
|
|
162
168
|
- **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 `"workspace"`. 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
|
+
- `"global"` — unsupported; emits a warning and is skipped
|
|
171
|
+
- `"repo"` — deploys to `{repo}/.vscode/mcp.json` under the `servers` key
|
|
172
|
+
- `"workspace"` — deploys to `{workspace}/.vscode/mcp.json` under the `servers` key
|
|
163
173
|
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
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
|
+
|
|
176
|
+
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` or `{workspace}/.vscode/mcp.json` using the `"servers"` key).
|
|
166
178
|
- **TOML (Patch)**: `codex` (`~/.codex/config.toml`).
|
|
167
179
|
- **Markdown Frontmatter (Emit)**: `antigravity` (repo-local `.agents/rules/{name}.md` files).
|
|
168
180
|
|
|
169
|
-
|
|
181
|
+
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
|
+
|
|
183
|
+
Because Antigravity currently reuses `.agents/rules/{name}.md` for both MCP frontmatter emit and agent-definition files, planning now rejects a manifest when an `mcpServers` entry and an `agentDefinitions` entry would resolve to the same Antigravity target.
|
|
184
|
+
|
|
185
|
+
Revert removes the registered server entry from the respective configuration file or frontmatter block.
|
|
170
186
|
|
|
171
187
|
Each **agentRules** entry deploys a Markdown instruction file to an agent's supported instruction file location:
|
|
172
188
|
|
|
@@ -232,20 +248,28 @@ Valid `approval_policy` values are `"auto"`, `"manual"`, `"suggest"`, and `"on-f
|
|
|
232
248
|
|
|
233
249
|
Revert restores the previous config values using the undo patch recorded at deploy time.
|
|
234
250
|
|
|
235
|
-
Each **agentDefinitions** entry deploys
|
|
251
|
+
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"`:
|
|
236
252
|
|
|
237
253
|
- **name** - Unique identifier (same format as skill names); used as the definition filename
|
|
238
|
-
- **path** - Relative path to the source
|
|
254
|
+
- **path** - Relative path to the source file within the repo; `.md` or `.markdown` for Markdown definitions, `.toml` for Gemini CLI TOML subagent definitions
|
|
239
255
|
- **agents** - Array of agent IDs to deploy this definition to
|
|
240
256
|
|
|
241
|
-
Agent-definition deployment is supported for `claude-code`, `gemini-cli`, `antigravity`, `opencode`, and `github-copilot`. For `codex`, inception-engine emits a warning and skips the entry
|
|
257
|
+
Agent-definition deployment is supported for `claude-code`, `gemini-cli`, `antigravity`, `opencode`, and `github-copilot`. For `codex`, inception-engine emits a warning and skips the entry. Gemini CLI and OpenCode also support `scope: "global"` definitions; other supported agents are repo-local only.
|
|
258
|
+
|
|
259
|
+
Gemini CLI supports two definition formats: Markdown (`.md`) files deploy to `{scope}/.gemini/agents/{name}.md`, and TOML (`.toml`) subagent configuration files deploy to `{scope}/.gemini/agents/{name}.toml`. TOML files are deployed verbatim without frontmatter validation. Agents other than `gemini-cli` that do not have a TOML definition surface silently produce no action when a `.toml` source is specified.
|
|
242
260
|
|
|
243
|
-
|
|
261
|
+
Repo-local targets:
|
|
244
262
|
- **claude-code**: `{repo}/.claude/agents/{name}.md`
|
|
245
|
-
- **gemini-cli**: `{repo}/.gemini/agents/{name}.md`
|
|
263
|
+
- **gemini-cli**: `{repo}/.gemini/agents/{name}.md` (Markdown) or `{repo}/.gemini/agents/{name}.toml` (TOML)
|
|
246
264
|
- **antigravity**: `{repo}/.agents/rules/{name}.md`
|
|
247
265
|
- **opencode**: `{repo}/.opencode/agents/{name}.md`
|
|
248
|
-
- **github-copilot**: `{repo}/.github/agents/{name}.
|
|
266
|
+
- **github-copilot**: `{repo}/.github/copilot/agents/{name}.md`
|
|
267
|
+
|
|
268
|
+
Global targets where supported:
|
|
269
|
+
- **gemini-cli**: `~/.gemini/agents/{name}.md` or `~/.gemini/agents/{name}.toml`
|
|
270
|
+
- **opencode**: `~/.config/opencode/agents/{name}.md` on POSIX, `%APPDATA%\\opencode\\agents\\{name}.md` on Windows
|
|
271
|
+
|
|
272
|
+
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.
|
|
249
273
|
|
|
250
274
|
Revert removes the deployed agent-definition file.
|
|
251
275
|
|
|
@@ -277,11 +301,11 @@ Current `init` behavior:
|
|
|
277
301
|
- Applies either the `--agents` list or all currently known agent IDs
|
|
278
302
|
- Refuses to overwrite an existing `inception.json` unless `--force` is provided
|
|
279
303
|
- 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
|
|
304
|
+
- 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 unsupported agents plus shared-surface riders that should default to their primary deploy target
|
|
281
305
|
- Reads `mcp-servers.json` from the repo root (if present) and generates `mcpServers` entries; invalid entries are warned and skipped
|
|
282
306
|
- Reads `files-manifest.json` from the repo root (if present) and generates `files` entries; invalid entries are warned and skipped
|
|
283
307
|
- Reads `configs-manifest.json` from the repo root (if present) and generates `configs` entries; invalid entries are warned and skipped
|
|
284
|
-
- Reads `agent-definitions-manifest.json` from the repo root (if present) and generates `agentDefinitions` entries; if absent, auto-discovers agent-definition Markdown files from `.claude/agents/`, `.gemini/agents/`, `.agents/rules/`, `.opencode/agents/`, and `.github/agents/`; invalid entries are warned and skipped
|
|
308
|
+
- Reads `agent-definitions-manifest.json` from the repo root (if present) and generates `agentDefinitions` entries; if absent, auto-discovers agent-definition Markdown files from `.claude/agents/`, `.gemini/agents/`, `.agents/rules/`, `.opencode/agents/`, `.github/copilot/agents/`, and legacy `.github/agents/`; invalid entries are warned and skipped
|
|
285
309
|
- Emits guidance to create a sidecar manifest when a `files/` or `configs/` directory is detected but the corresponding sidecar file is absent
|
|
286
310
|
|
|
287
311
|
Current `init` limitations:
|
|
@@ -343,10 +367,12 @@ Place an `agent-definitions-manifest.json` file at the repo root to have `init`
|
|
|
343
367
|
]
|
|
344
368
|
```
|
|
345
369
|
|
|
346
|
-
If no `agent-definitions-manifest.json` is present, `init` auto-discovers agent-definition Markdown files from
|
|
370
|
+
If no `agent-definitions-manifest.json` is present, `init` auto-discovers agent-definition Markdown files from six conventional subdirectories: `.claude/agents/`, `.gemini/agents/`, `.agents/rules/`, `.opencode/agents/`, `.github/copilot/agents/`, and legacy `.github/agents/`. Each discovered file is mapped to the owning agent(s). GitHub Copilot files named `{name}.agent.md` in the legacy directory have the `.agent` infix stripped to derive the manifest name (e.g., `foo.agent.md` -> name `foo`).
|
|
347
371
|
|
|
348
372
|
Invalid entries are warned and skipped; the rest are written into the generated manifest verbatim.
|
|
349
373
|
|
|
374
|
+
For shared surfaces, `init` prefers the primary deploy target instead of emitting both agents. That means generated `skills` entries exclude `github-copilot` in favor of `claude-code`, and generated shared `GEMINI.md` `agentRules` entries exclude `antigravity` in favor of `gemini-cli`. This keeps starter manifests minimal while preserving deploy behavior for explicitly authored shared-rider entries.
|
|
375
|
+
|
|
350
376
|
## CLI Reference
|
|
351
377
|
|
|
352
378
|
```
|
|
@@ -433,11 +459,11 @@ Revert targets all agents listed in the manifest by default (regardless of detec
|
|
|
433
459
|
|
|
434
460
|
### Ownership Tracking and Safe Revert
|
|
435
461
|
|
|
436
|
-
inception-engine maintains a centralized deployment registry at `~/.inception-engine/registry.json`. Each deploy records the target path, skill name, agent ID, action-specific provenance (`source`/`method` for skill-dir, `source` for file-write, `patch`/`undoPatch` for config-patch), and timestamp. No files are written to the source repository.
|
|
462
|
+
inception-engine maintains a centralized deployment registry at `~/.inception-engine/registry.json`. Each deploy records the target path, skill name, agent ID, action-specific provenance (`source`/`method` for skill-dir, `source` for file-write, `patch`/`undoPatch` for config-patch, `patch`/`undoPatch` plus frontmatter-shape metadata for frontmatter-emit), and timestamp. Registry entries also carry a stable surface ID so future surface migrations can preserve ownership continuity. No files are written to the source repository.
|
|
437
463
|
|
|
438
464
|
- **Registry-based ownership**: On revert, the registry is checked before removing any target. Only targets with a valid registry entry are removed. On redeploy, unmanaged targets are never replaced.
|
|
439
465
|
|
|
440
|
-
- **Strong binding**: Each registry entry binds a specific target path to its skill, agent, and action kind. For `skill-dir` and `file-write`, ownership checks also require the recorded `source` to match before an existing target is treated as managed. For `config-patch`, overwrite protection is keyed by target path, kind, skill, and agent; the stored `patch` and `undoPatch` are used for revert bookkeeping rather than deploy-time identity checks.
|
|
466
|
+
- **Strong binding**: Each registry entry binds a specific target path to its skill, agent, and action kind. For `skill-dir` and `file-write`, ownership checks also require the recorded `source` to match before an existing target is treated as managed. For `config-patch` and `frontmatter-emit`, overwrite protection is keyed by target path, kind, skill, and agent; the stored `patch` and `undoPatch` are used for patch-level revert bookkeeping rather than deploy-time identity checks.
|
|
441
467
|
|
|
442
468
|
- **Atomic redeploy**: When overwriting an existing managed `skill-dir` target, the engine renames the old target to a backup, creates the new deployment, and only removes the backup on success. If the new deployment fails, the backup is restored. `file-write` and `config-patch` deployments write directly to the target without this backup/rollback model.
|
|
443
469
|
|
|
@@ -28,6 +28,22 @@ export const AGENT_REGISTRY = [
|
|
|
28
28
|
windows: ["{home}", ".claude.json"],
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
|
+
mcpRepoSupport: {
|
|
32
|
+
status: "supported",
|
|
33
|
+
schemaLabel: "repo-local .claude/mcp.json",
|
|
34
|
+
path: {
|
|
35
|
+
posix: ["{repo}", ".claude", "mcp.json"],
|
|
36
|
+
windows: ["{repo}", ".claude", "mcp.json"],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
mcpWorkspaceSupport: {
|
|
40
|
+
status: "supported",
|
|
41
|
+
schemaLabel: "workspace-local .claude/mcp.json",
|
|
42
|
+
path: {
|
|
43
|
+
posix: ["{workspace}", ".claude", "mcp.json"],
|
|
44
|
+
windows: ["{workspace}", ".claude", "mcp.json"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
31
47
|
agentRulesSupport: {
|
|
32
48
|
status: "supported",
|
|
33
49
|
schemaLabel: "global Markdown rules file",
|
|
@@ -52,7 +68,7 @@ export const AGENT_REGISTRY = [
|
|
|
52
68
|
windows: ["{home}", ".claude", "settings.json"],
|
|
53
69
|
},
|
|
54
70
|
},
|
|
55
|
-
|
|
71
|
+
agentDefinitionsRepoSupport: {
|
|
56
72
|
status: "supported",
|
|
57
73
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
58
74
|
path: {
|
|
@@ -120,7 +136,7 @@ export const AGENT_REGISTRY = [
|
|
|
120
136
|
windows: ["{home}", ".codex", "config.toml"],
|
|
121
137
|
},
|
|
122
138
|
},
|
|
123
|
-
|
|
139
|
+
agentDefinitionsRepoSupport: {
|
|
124
140
|
status: "unsupported",
|
|
125
141
|
schemaLabel: "dedicated agent definition directory",
|
|
126
142
|
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",
|
|
@@ -152,7 +168,7 @@ export const AGENT_REGISTRY = [
|
|
|
152
168
|
detectBinary: "documented",
|
|
153
169
|
mcpConfig: "documented",
|
|
154
170
|
agentRules: "documented",
|
|
155
|
-
agentDefinitions: "
|
|
171
|
+
agentDefinitions: "documented",
|
|
156
172
|
},
|
|
157
173
|
mcpSupport: {
|
|
158
174
|
status: "supported",
|
|
@@ -162,6 +178,9 @@ export const AGENT_REGISTRY = [
|
|
|
162
178
|
windows: ["{home}", ".gemini", "settings.json"],
|
|
163
179
|
},
|
|
164
180
|
},
|
|
181
|
+
// NOTE: Gemini CLI also reads AGENTS.md as a fallback when GEMINI.md is absent.
|
|
182
|
+
// inception-engine intentionally targets GEMINI.md to avoid ownership collisions
|
|
183
|
+
// with codex and opencode, which also write AGENTS.md.
|
|
165
184
|
agentRulesSupport: {
|
|
166
185
|
status: "supported",
|
|
167
186
|
schemaLabel: "global Markdown rules file",
|
|
@@ -184,6 +203,14 @@ export const AGENT_REGISTRY = [
|
|
|
184
203
|
reason: "Gemini CLI does not expose a documented global per-user permission or approval config surface",
|
|
185
204
|
},
|
|
186
205
|
agentDefinitionsSupport: {
|
|
206
|
+
status: "supported",
|
|
207
|
+
schemaLabel: "global agent definition Markdown file",
|
|
208
|
+
path: {
|
|
209
|
+
posix: ["{home}", ".gemini", "agents", "{name}.md"],
|
|
210
|
+
windows: ["{home}", ".gemini", "agents", "{name}.md"],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
agentDefinitionsRepoSupport: {
|
|
187
214
|
status: "supported",
|
|
188
215
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
189
216
|
path: {
|
|
@@ -191,6 +218,22 @@ export const AGENT_REGISTRY = [
|
|
|
191
218
|
windows: ["{repo}", ".gemini", "agents", "{name}.md"],
|
|
192
219
|
},
|
|
193
220
|
},
|
|
221
|
+
agentDefinitionsTomlSupport: {
|
|
222
|
+
status: "supported",
|
|
223
|
+
schemaLabel: "global agent definition TOML file",
|
|
224
|
+
path: {
|
|
225
|
+
posix: ["{home}", ".gemini", "agents", "{name}.toml"],
|
|
226
|
+
windows: ["{home}", ".gemini", "agents", "{name}.toml"],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
agentDefinitionsTomlRepoSupport: {
|
|
230
|
+
status: "supported",
|
|
231
|
+
schemaLabel: "repo-local agent definition TOML file",
|
|
232
|
+
path: {
|
|
233
|
+
posix: ["{repo}", ".gemini", "agents", "{name}.toml"],
|
|
234
|
+
windows: ["{repo}", ".gemini", "agents", "{name}.toml"],
|
|
235
|
+
},
|
|
236
|
+
},
|
|
194
237
|
agentRulesWorkspaceSupport: {
|
|
195
238
|
status: "supported",
|
|
196
239
|
schemaLabel: "workspace-local GEMINI.md",
|
|
@@ -253,7 +296,7 @@ export const AGENT_REGISTRY = [
|
|
|
253
296
|
schemaLabel: "global permissions surface",
|
|
254
297
|
reason: "Antigravity does not expose a documented global per-user permission or approval config surface",
|
|
255
298
|
},
|
|
256
|
-
|
|
299
|
+
agentDefinitionsRepoSupport: {
|
|
257
300
|
status: "supported",
|
|
258
301
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
259
302
|
path: {
|
|
@@ -286,6 +329,7 @@ export const AGENT_REGISTRY = [
|
|
|
286
329
|
detectBinary: "documented",
|
|
287
330
|
agentRules: "documented",
|
|
288
331
|
agentDefinitions: "documented",
|
|
332
|
+
permissions: "documented",
|
|
289
333
|
},
|
|
290
334
|
mcpSupport: {
|
|
291
335
|
status: "supported",
|
|
@@ -313,11 +357,22 @@ export const AGENT_REGISTRY = [
|
|
|
313
357
|
},
|
|
314
358
|
},
|
|
315
359
|
permissionsSupport: {
|
|
316
|
-
status: "
|
|
317
|
-
schemaLabel: "
|
|
318
|
-
|
|
360
|
+
status: "supported",
|
|
361
|
+
schemaLabel: "opencode.json permissions config",
|
|
362
|
+
path: {
|
|
363
|
+
posix: ["{xdg_config}", "opencode", "opencode.json"],
|
|
364
|
+
windows: ["{appdata}", "opencode", "opencode.json"],
|
|
365
|
+
},
|
|
319
366
|
},
|
|
320
367
|
agentDefinitionsSupport: {
|
|
368
|
+
status: "supported",
|
|
369
|
+
schemaLabel: "global agent definition Markdown file",
|
|
370
|
+
path: {
|
|
371
|
+
posix: ["{xdg_config}", "opencode", "agents", "{name}.md"],
|
|
372
|
+
windows: ["{appdata}", "opencode", "agents", "{name}.md"],
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
agentDefinitionsRepoSupport: {
|
|
321
376
|
status: "supported",
|
|
322
377
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
323
378
|
path: {
|
|
@@ -348,12 +403,30 @@ export const AGENT_REGISTRY = [
|
|
|
348
403
|
detectPaths: "documented",
|
|
349
404
|
detectBinary: "documented",
|
|
350
405
|
agentDefinitions: "documented",
|
|
406
|
+
mcpConfig: "documented",
|
|
351
407
|
},
|
|
352
408
|
mcpSupport: {
|
|
353
|
-
status: "
|
|
354
|
-
schemaLabel: "
|
|
355
|
-
|
|
356
|
-
|
|
409
|
+
status: "unsupported",
|
|
410
|
+
schemaLabel: "global MCP config",
|
|
411
|
+
reason: 'GitHub Copilot has no user-level MCP config file; use scope: "repo" or scope: "workspace" to target .vscode/mcp.json instead',
|
|
412
|
+
},
|
|
413
|
+
mcpRepoSupport: {
|
|
414
|
+
status: "supported",
|
|
415
|
+
schemaLabel: "repo-local .vscode/mcp.json",
|
|
416
|
+
mcpPatchKey: "servers",
|
|
417
|
+
path: {
|
|
418
|
+
posix: ["{repo}", ".vscode", "mcp.json"],
|
|
419
|
+
windows: ["{repo}", ".vscode", "mcp.json"],
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
mcpWorkspaceSupport: {
|
|
423
|
+
status: "supported",
|
|
424
|
+
schemaLabel: "workspace-local .vscode/mcp.json",
|
|
425
|
+
mcpPatchKey: "servers",
|
|
426
|
+
path: {
|
|
427
|
+
posix: ["{workspace}", ".vscode", "mcp.json"],
|
|
428
|
+
windows: ["{workspace}", ".vscode", "mcp.json"],
|
|
429
|
+
},
|
|
357
430
|
},
|
|
358
431
|
// GitHub Copilot reads Claude-native instruction files (CLAUDE.md) without
|
|
359
432
|
// a separate deploy action. These surfaces are marked shared-via claude-code
|
|
@@ -404,12 +477,12 @@ export const AGENT_REGISTRY = [
|
|
|
404
477
|
schemaLabel: "global permissions surface",
|
|
405
478
|
reason: "GitHub Copilot permissions are managed via organization policy, not a deployable per-user config surface",
|
|
406
479
|
},
|
|
407
|
-
|
|
480
|
+
agentDefinitionsRepoSupport: {
|
|
408
481
|
status: "supported",
|
|
409
482
|
schemaLabel: "repo-local agent definition Markdown file",
|
|
410
483
|
path: {
|
|
411
|
-
posix: ["{repo}", ".github", "agents", "{name}.
|
|
412
|
-
windows: ["{repo}", ".github", "agents", "{name}.
|
|
484
|
+
posix: ["{repo}", ".github", "copilot", "agents", "{name}.md"],
|
|
485
|
+
windows: ["{repo}", ".github", "copilot", "agents", "{name}.md"],
|
|
413
486
|
},
|
|
414
487
|
},
|
|
415
488
|
policyNote: "Organization policies may override locally deployed configuration. Verify with your GitHub org admin if deployed skills or rules are not active.",
|
|
@@ -4,17 +4,5 @@ export interface AgentDefinitionsAdapterResult {
|
|
|
4
4
|
actions: FileWriteDeployAction[];
|
|
5
5
|
warnings: PlanWarning[];
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
8
|
-
* Compiles deploy actions for agentDefinitions manifest entries.
|
|
9
|
-
*
|
|
10
|
-
* Agent definition files are Markdown files (typically with YAML frontmatter)
|
|
11
|
-
* that define custom agents or subagents for a given platform. Unlike
|
|
12
|
-
* agentRules (which target a single shared global file per agent), each
|
|
13
|
-
* definition entry produces a separate file named after the entry in the
|
|
14
|
-
* agent's dedicated agent-definitions directory (repo-local).
|
|
15
|
-
*
|
|
16
|
-
* Target paths use the `{repo}` placeholder so definitions land in the
|
|
17
|
-
* repository being deployed, not the user's home directory.
|
|
18
|
-
*/
|
|
19
7
|
export declare function compileAgentDefinitionActions(entry: AgentDefinitionEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, workspace?: string): Promise<AgentDefinitionsAdapterResult>;
|
|
20
8
|
export declare function compileAgentDefinitionReverts(entry: AgentDefinitionEntry, agentFilter: AgentId[] | null, home: string, repo?: string, workspace?: string): FileWriteRevertAction[];
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
|
|
3
|
+
import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
|
|
4
|
+
import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
|
|
5
|
+
import { validateAgentRuleMarkdownPath, validateInstructionFileRequirements, validateSourceFile, validateSourcePath, } from "../validation.js";
|
|
6
|
+
/**
|
|
7
|
+
* Compiles deploy actions for agentDefinitions manifest entries.
|
|
8
|
+
*
|
|
9
|
+
* Agent definition files are Markdown (typically with YAML frontmatter) or
|
|
10
|
+
* TOML files that define custom agents or subagents for a given platform.
|
|
11
|
+
* Unlike agentRules (which target a single shared global file per agent),
|
|
12
|
+
* each definition entry produces a separate file named after the entry in
|
|
13
|
+
* the agent's dedicated agent-definitions directory.
|
|
14
|
+
*
|
|
15
|
+
* Target paths use the `{repo}` placeholder so definitions land in the
|
|
16
|
+
* repository being deployed, not the user's home directory.
|
|
17
|
+
*
|
|
18
|
+
* TOML source files (e.g. Gemini CLI `.gemini/agents/*.toml`) bypass
|
|
19
|
+
* Markdown-specific validation and are deployed verbatim.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Returns the TOML-specific surface for an agent (global or repo-local),
|
|
23
|
+
* or undefined when the agent has no TOML definition surface.
|
|
24
|
+
*/
|
|
25
|
+
function resolveTomlDefinitionsSurface(agentId, scope) {
|
|
26
|
+
const agent = AGENT_REGISTRY_BY_ID[agentId];
|
|
27
|
+
if (!agent)
|
|
28
|
+
return undefined;
|
|
29
|
+
const tomlSupport = scope === "repo"
|
|
30
|
+
? (agent.agentDefinitionsTomlRepoSupport ??
|
|
31
|
+
agent.agentDefinitionsTomlSupport)
|
|
32
|
+
: agent.agentDefinitionsTomlSupport;
|
|
33
|
+
if (!tomlSupport || tomlSupport.status !== "supported")
|
|
34
|
+
return undefined;
|
|
35
|
+
return tomlSupport;
|
|
36
|
+
}
|
|
37
|
+
/** Returns a warning when the requested scope cannot be resolved, or null when it is fine. */
|
|
38
|
+
function scopeAvailabilityWarning(entry, agentId, repo, workspace) {
|
|
39
|
+
if (entry.scope === "repo" && !repo) {
|
|
40
|
+
return {
|
|
41
|
+
kind: "confidence",
|
|
42
|
+
message: `agentDefinitions: scope "repo" requires a repository path but none was resolved — skipping "${entry.name}" for agent "${agentId}"`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (entry.scope === "workspace" && !workspace && !repo) {
|
|
46
|
+
return {
|
|
47
|
+
kind: "confidence",
|
|
48
|
+
message: `agentDefinitions: scope "workspace" requires a workspace or repository path but none was resolved — skipping "${entry.name}" for agent "${agentId}"`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function resolveSupportedTargets(entry, targetAgents, home, repo, workspace) {
|
|
54
|
+
const targets = [];
|
|
55
|
+
const warnings = [];
|
|
56
|
+
const platform = getPlatformKey();
|
|
57
|
+
const isToml = path.extname(entry.path).toLowerCase() === ".toml";
|
|
58
|
+
for (const agentId of targetAgents) {
|
|
59
|
+
const plan = planCapabilityForDeploy({
|
|
60
|
+
agentId,
|
|
61
|
+
capability: "agentDefinitions",
|
|
62
|
+
entryName: entry.name,
|
|
63
|
+
targetAgentIds: targetAgents,
|
|
64
|
+
scope: entry.scope,
|
|
65
|
+
});
|
|
66
|
+
if (plan.outcome === "warn") {
|
|
67
|
+
warnings.push(plan.warning);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (plan.outcome === "native" || plan.outcome === "redundant")
|
|
71
|
+
continue;
|
|
72
|
+
// For TOML sources, use the agent's TOML-specific surface instead of the
|
|
73
|
+
// default Markdown surface. Agents without a TOML surface are skipped.
|
|
74
|
+
const support = isToml
|
|
75
|
+
? resolveTomlDefinitionsSurface(agentId, entry.scope)
|
|
76
|
+
: resolveCapabilitySurface(agentId, "agentDefinitions", entry.scope)
|
|
77
|
+
.support;
|
|
78
|
+
if (!support)
|
|
79
|
+
continue;
|
|
80
|
+
const scopeWarning = scopeAvailabilityWarning(entry, agentId, repo, workspace);
|
|
81
|
+
if (scopeWarning) {
|
|
82
|
+
warnings.push(scopeWarning);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
targets.push({
|
|
86
|
+
agentId,
|
|
87
|
+
confidence: plan.confidence ?? "provisional",
|
|
88
|
+
target: resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { targets, warnings };
|
|
92
|
+
}
|
|
93
|
+
async function createAgentDefinitionActions(entry, source, supportedTargets, home, repo, workspace) {
|
|
94
|
+
const actions = [];
|
|
95
|
+
const isToml = path.extname(entry.path).toLowerCase() === ".toml";
|
|
96
|
+
for (const target of supportedTargets) {
|
|
97
|
+
// TOML definition files have no YAML frontmatter — skip Markdown validation.
|
|
98
|
+
if (!isToml) {
|
|
99
|
+
validateAgentRuleMarkdownPath(entry.path, target.agentId);
|
|
100
|
+
await validateInstructionFileRequirements(source, entry.path, target.agentId);
|
|
101
|
+
}
|
|
102
|
+
let migratedFrom;
|
|
103
|
+
if (target.agentId === "github-copilot") {
|
|
104
|
+
migratedFrom = [
|
|
105
|
+
resolvePlaceholders(["{repo}", ".github", "agents", "{name}.agent.md"], entry.name, home, repo, workspace),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
actions.push({
|
|
109
|
+
kind: "file-write",
|
|
110
|
+
skill: entry.name,
|
|
111
|
+
agent: target.agentId,
|
|
112
|
+
source,
|
|
113
|
+
target: target.target,
|
|
114
|
+
confidence: target.confidence,
|
|
115
|
+
migratedFrom,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return actions;
|
|
119
|
+
}
|
|
120
|
+
export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace) {
|
|
121
|
+
const targetAgents = entry.agents.filter((agentId) => detectedAgents.includes(agentId));
|
|
122
|
+
if (targetAgents.length === 0) {
|
|
123
|
+
return { actions: [], warnings: [] };
|
|
124
|
+
}
|
|
125
|
+
const { targets: supportedTargets, warnings } = resolveSupportedTargets(entry, targetAgents, home, repo, workspace);
|
|
126
|
+
if (supportedTargets.length === 0) {
|
|
127
|
+
return { actions: [], warnings };
|
|
128
|
+
}
|
|
129
|
+
// Validate the shared source file only when at least one target is active.
|
|
130
|
+
const source = path.resolve(sourceDir, entry.path);
|
|
131
|
+
await validateSourcePath(source, entry.path, resolvedSourceDir, realRoot);
|
|
132
|
+
await validateSourceFile(source, entry.path);
|
|
133
|
+
const actions = await createAgentDefinitionActions(entry, source, supportedTargets, home, repo, workspace);
|
|
134
|
+
return { actions, warnings };
|
|
135
|
+
}
|
|
136
|
+
export function compileAgentDefinitionReverts(entry, agentFilter, home, repo, workspace) {
|
|
137
|
+
const actions = [];
|
|
138
|
+
const platform = getPlatformKey();
|
|
139
|
+
const isToml = path.extname(entry.path).toLowerCase() === ".toml";
|
|
140
|
+
for (const agentId of entry.agents) {
|
|
141
|
+
if (agentFilter && !agentFilter.includes(agentId))
|
|
142
|
+
continue;
|
|
143
|
+
const support = isToml
|
|
144
|
+
? resolveTomlDefinitionsSurface(agentId, entry.scope)
|
|
145
|
+
: resolveCapabilitySurface(agentId, "agentDefinitions", entry.scope)
|
|
146
|
+
.support;
|
|
147
|
+
if (!support)
|
|
148
|
+
continue;
|
|
149
|
+
if (entry.scope === "repo" && !repo)
|
|
150
|
+
continue;
|
|
151
|
+
if (entry.scope === "workspace" && !workspace && !repo)
|
|
152
|
+
continue;
|
|
153
|
+
const target = resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace);
|
|
154
|
+
actions.push({
|
|
155
|
+
kind: "file-write",
|
|
156
|
+
skill: entry.name,
|
|
157
|
+
agent: agentId,
|
|
158
|
+
target,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return actions;
|
|
162
|
+
}
|
|
@@ -12,6 +12,7 @@ export declare function splitFrontmatter(raw: string): {
|
|
|
12
12
|
export declare function parseFrontmatterDocument<T = Record<string, unknown>>(raw: string): {
|
|
13
13
|
attributes: T;
|
|
14
14
|
body: string;
|
|
15
|
+
hasFrontmatter: boolean;
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
17
18
|
* Serializes an object to a YAML block.
|
|
@@ -21,6 +22,9 @@ export declare function serializeFrontmatter(data: Record<string, unknown>): str
|
|
|
21
22
|
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
22
23
|
*/
|
|
23
24
|
export declare function buildFrontmatterDocument(frontmatter: Record<string, unknown>, body?: string): string;
|
|
25
|
+
export declare function buildMarkdownDocument(frontmatter: Record<string, unknown>, body?: string, options?: {
|
|
26
|
+
hasFrontmatter?: boolean;
|
|
27
|
+
}): string;
|
|
24
28
|
/**
|
|
25
29
|
* Reads an existing `.md` file and parses its frontmatter.
|
|
26
30
|
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
@@ -29,6 +33,12 @@ export declare function readFrontmatterFile(filePath: string): Promise<{
|
|
|
29
33
|
attributes: Record<string, unknown>;
|
|
30
34
|
body: string;
|
|
31
35
|
}>;
|
|
36
|
+
export declare function readFrontmatterDocumentFile(filePath: string): Promise<{
|
|
37
|
+
exists: boolean;
|
|
38
|
+
hasFrontmatter: boolean;
|
|
39
|
+
attributes: Record<string, unknown>;
|
|
40
|
+
body: string;
|
|
41
|
+
}>;
|
|
32
42
|
/**
|
|
33
43
|
* Atomically writes a Markdown file with the given frontmatter and optional
|
|
34
44
|
* body. Preserves any existing body content when `preserveBody` is true.
|
|
@@ -26,10 +26,10 @@ export function splitFrontmatter(raw) {
|
|
|
26
26
|
export function parseFrontmatterDocument(raw) {
|
|
27
27
|
const { frontmatter, body } = splitFrontmatter(raw);
|
|
28
28
|
if (!(frontmatter || raw.startsWith("---"))) {
|
|
29
|
-
return { attributes: {}, body };
|
|
29
|
+
return { attributes: {}, body, hasFrontmatter: false };
|
|
30
30
|
}
|
|
31
31
|
const attributes = YAML.parse(frontmatter);
|
|
32
|
-
return { attributes: (attributes || {}), body };
|
|
32
|
+
return { attributes: (attributes || {}), body, hasFrontmatter: true };
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Serializes an object to a YAML block.
|
|
@@ -42,9 +42,15 @@ export function serializeFrontmatter(data) {
|
|
|
42
42
|
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
43
43
|
*/
|
|
44
44
|
export function buildFrontmatterDocument(frontmatter, body = "") {
|
|
45
|
+
return buildMarkdownDocument(frontmatter, body, { hasFrontmatter: true });
|
|
46
|
+
}
|
|
47
|
+
export function buildMarkdownDocument(frontmatter, body = "", options = {}) {
|
|
48
|
+
const cleanBody = body.trimStart();
|
|
49
|
+
if (Object.keys(frontmatter).length === 0 && !options.hasFrontmatter) {
|
|
50
|
+
return cleanBody;
|
|
51
|
+
}
|
|
45
52
|
const serialized = serializeFrontmatter(frontmatter);
|
|
46
53
|
// Ensure exactly one newline after the closing delimiter before the body
|
|
47
|
-
const cleanBody = body.trimStart();
|
|
48
54
|
const separator = cleanBody ? "\n\n" : "\n";
|
|
49
55
|
return `---\n${serialized}\n---\n${separator}${cleanBody}`;
|
|
50
56
|
}
|
|
@@ -58,17 +64,28 @@ function createAtomicTempPath(targetPath) {
|
|
|
58
64
|
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
59
65
|
*/
|
|
60
66
|
export async function readFrontmatterFile(filePath) {
|
|
67
|
+
const document = await readFrontmatterDocumentFile(filePath);
|
|
68
|
+
return { attributes: document.attributes, body: document.body };
|
|
69
|
+
}
|
|
70
|
+
export async function readFrontmatterDocumentFile(filePath) {
|
|
61
71
|
let raw;
|
|
62
72
|
try {
|
|
63
73
|
raw = await readFile(filePath, "utf-8");
|
|
64
74
|
}
|
|
65
75
|
catch (err) {
|
|
66
76
|
const code = err.code;
|
|
67
|
-
if (code === "ENOENT")
|
|
68
|
-
return {
|
|
77
|
+
if (code === "ENOENT") {
|
|
78
|
+
return {
|
|
79
|
+
exists: false,
|
|
80
|
+
hasFrontmatter: false,
|
|
81
|
+
attributes: {},
|
|
82
|
+
body: "",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
69
85
|
throw err;
|
|
70
86
|
}
|
|
71
|
-
|
|
87
|
+
const parsed = parseFrontmatterDocument(raw);
|
|
88
|
+
return { exists: true, ...parsed };
|
|
72
89
|
}
|
|
73
90
|
/**
|
|
74
91
|
* Atomically writes a Markdown file with the given frontmatter and optional
|