@kuznai/inception-engine 0.11.1 → 0.13.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 +13 -8
- package/dist/config/agents.js +87 -27
- package/dist/core/adapters/frontmatter.d.ts +26 -0
- package/dist/core/adapters/frontmatter.js +120 -0
- package/dist/core/adapters/index.d.ts +3 -3
- package/dist/core/adapters/index.js +3 -3
- package/dist/core/adapters/mcp.d.ts +4 -4
- package/dist/core/adapters/mcp.js +84 -23
- package/dist/core/adapters/rules.d.ts +2 -2
- package/dist/core/adapters/rules.js +29 -22
- package/dist/core/adapters/toml.d.ts +19 -0
- package/dist/core/adapters/toml.js +96 -0
- package/dist/core/deploy.js +128 -47
- package/dist/core/resolve.d.ts +1 -1
- package/dist/core/resolve.js +3 -2
- package/dist/core/revert.d.ts +2 -2
- package/dist/core/revert.js +68 -7
- package/dist/core/runtime-paths.d.ts +1 -1
- package/dist/core/runtime-paths.js +16 -3
- package/dist/core/validation.d.ts +3 -0
- package/dist/core/validation.js +97 -1
- package/dist/schemas/manifest.js +4 -2
- package/dist/types.d.ts +47 -7
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -48,8 +48,8 @@ Managed skills overwrite their previous version. If a target exists but was not
|
|
|
48
48
|
| Skills (SKILL.md) | All agents via manifest and CLI | All agents |
|
|
49
49
|
| File write | All agents via manifest and CLI | All agents |
|
|
50
50
|
| Config patch (JSON merge) | All agents via manifest and CLI | All agents |
|
|
51
|
-
| MCP Servers | claude-code, gemini-cli;
|
|
52
|
-
| Global Rules Files |
|
|
51
|
+
| 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 | All agents (antigravity uses repo-local `.agents/rules/`); github-copilot reads CLAUDE.md natively (deploy via claude-code) | All agents |
|
|
53
53
|
| `init` manifest generation | Scans `SKILL.md` directories and writes starter `skills` entries | N/A |
|
|
54
54
|
|
|
55
55
|
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.
|
|
@@ -128,17 +128,22 @@ Each **mcpServer** entry registers an MCP server into the agent's config file by
|
|
|
128
128
|
|
|
129
129
|
- **name** - Unique identifier (same format as skill names); used as the server's key in the config
|
|
130
130
|
- **agents** - Array of agent IDs to register this server with
|
|
131
|
-
- **config** - Raw server descriptor object
|
|
131
|
+
- **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.
|
|
132
132
|
|
|
133
|
-
MCP server registration is
|
|
133
|
+
MCP server registration is supported for all agents except GitHub Copilot. Inception-engine automatically uses the correct adapter for each agent's configuration schema:
|
|
134
|
+
- **JSON (Merge Patch)**: `claude-code` (`~/.claude.json`), `gemini-cli` (`~/.gemini/settings.json`), and `opencode` (`~/.config/opencode/opencode.json` using the custom `"mcp"` key).
|
|
135
|
+
- **TOML (Patch)**: `codex` (`~/.codex/config.toml`).
|
|
136
|
+
- **Markdown Frontmatter (Emit)**: `antigravity` (repo-local `.agents/rules/{name}.md` files).
|
|
137
|
+
|
|
138
|
+
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.
|
|
134
139
|
|
|
135
140
|
Each **agentRules** entry deploys a Markdown instruction file to an agent's supported global rules file location:
|
|
136
141
|
|
|
137
142
|
- **name** - Unique identifier (same format as skill names)
|
|
138
|
-
- **path** - Relative path to the source Markdown file within the repo
|
|
143
|
+
- **path** - Relative path to the source Markdown file within the repo; supported global rules adapters require a `.md` or `.markdown` source path
|
|
139
144
|
- **agents** - Array of agent IDs to deploy this file to
|
|
140
145
|
|
|
141
|
-
|
|
146
|
+
Instruction rule deployment is supported for all agents. For most agents, this targets a single global rules file (e.g., `~/.claude/CLAUDE.md` for `claude-code`, `~/.codex/AGENTS.md` for `codex`, `~/.gemini/GEMINI.md` for `gemini-cli`, and `~/.config/opencode/AGENTS.md` for `opencode`). For `antigravity`, inception-engine deploys to repo-local instruction surfaces at `{repo}/.agents/rules/{name}.md`. For `github-copilot`, no separate deployment is needed because Copilot reads `CLAUDE.md` natively — target it via the `claude-code` agentRules entry and it reaches Copilot automatically. Revert removes the deployed rules file.
|
|
142
147
|
|
|
143
148
|
## Creating Skills
|
|
144
149
|
|
|
@@ -155,7 +160,7 @@ description: What this skill does and when to use it
|
|
|
155
160
|
Instructions for the AI agent...
|
|
156
161
|
```
|
|
157
162
|
|
|
158
|
-
The `name` and `description` fields in the frontmatter are used by most agents. The description determines when the agent activates the skill. inception-engine
|
|
163
|
+
The `name` and `description` fields in the frontmatter are used by most agents. The description determines when the agent activates the skill. inception-engine now validates this minimum contract during deploy: `SKILL.md` must start with YAML frontmatter and include non-empty single-line `name` and `description` fields. It still does not attempt full YAML/schema validation beyond that targeted check.
|
|
159
164
|
|
|
160
165
|
## `init` Command
|
|
161
166
|
|
|
@@ -171,7 +176,7 @@ Current `init` behavior:
|
|
|
171
176
|
|
|
172
177
|
Current `init` limitations:
|
|
173
178
|
|
|
174
|
-
- It does not
|
|
179
|
+
- It does not reconcile generated manifest entries against `SKILL.md` frontmatter values
|
|
175
180
|
- It does not infer `files`, `configs`, `mcpServers`, or `agentRules`
|
|
176
181
|
- It does not reconcile generated output with the longer-term Claude-first portability direction
|
|
177
182
|
|
package/dist/config/agents.js
CHANGED
|
@@ -18,13 +18,21 @@ export const AGENT_REGISTRY = [
|
|
|
18
18
|
mcpConfig: "documented",
|
|
19
19
|
agentRules: "documented",
|
|
20
20
|
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
mcpSupport: {
|
|
22
|
+
status: "supported",
|
|
23
|
+
schemaLabel: "JSON mcpServers config",
|
|
24
|
+
path: {
|
|
25
|
+
posix: ["{home}", ".claude.json"],
|
|
26
|
+
windows: ["{home}", ".claude.json"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
agentRulesSupport: {
|
|
30
|
+
status: "supported",
|
|
31
|
+
schemaLabel: "global Markdown rules file",
|
|
32
|
+
path: {
|
|
33
|
+
posix: ["{home}", ".claude", "CLAUDE.md"],
|
|
34
|
+
windows: ["{home}", ".claude", "CLAUDE.md"],
|
|
35
|
+
},
|
|
28
36
|
},
|
|
29
37
|
},
|
|
30
38
|
{
|
|
@@ -45,10 +53,21 @@ export const AGENT_REGISTRY = [
|
|
|
45
53
|
detectBinary: "documented",
|
|
46
54
|
agentRules: "documented",
|
|
47
55
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
mcpSupport: {
|
|
57
|
+
status: "supported",
|
|
58
|
+
schemaLabel: "TOML mcpServers config",
|
|
59
|
+
path: {
|
|
60
|
+
posix: ["{home}", ".codex", "config.toml"],
|
|
61
|
+
windows: ["{home}", ".codex", "config.toml"],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
agentRulesSupport: {
|
|
65
|
+
status: "supported",
|
|
66
|
+
schemaLabel: "global Markdown rules file",
|
|
67
|
+
path: {
|
|
68
|
+
posix: ["{home}", ".codex", "AGENTS.md"],
|
|
69
|
+
windows: ["{home}", ".codex", "AGENTS.md"],
|
|
70
|
+
},
|
|
52
71
|
},
|
|
53
72
|
},
|
|
54
73
|
{
|
|
@@ -70,13 +89,21 @@ export const AGENT_REGISTRY = [
|
|
|
70
89
|
mcpConfig: "documented",
|
|
71
90
|
agentRules: "documented",
|
|
72
91
|
},
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
mcpSupport: {
|
|
93
|
+
status: "supported",
|
|
94
|
+
schemaLabel: "JSON mcpServers config",
|
|
95
|
+
path: {
|
|
96
|
+
posix: ["{home}", ".gemini", "settings.json"],
|
|
97
|
+
windows: ["{home}", ".gemini", "settings.json"],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
agentRulesSupport: {
|
|
101
|
+
status: "supported",
|
|
102
|
+
schemaLabel: "global Markdown rules file",
|
|
103
|
+
path: {
|
|
104
|
+
posix: ["{home}", ".gemini", "GEMINI.md"],
|
|
105
|
+
windows: ["{home}", ".gemini", "GEMINI.md"],
|
|
106
|
+
},
|
|
80
107
|
},
|
|
81
108
|
},
|
|
82
109
|
{
|
|
@@ -96,7 +123,22 @@ export const AGENT_REGISTRY = [
|
|
|
96
123
|
detectPaths: "implementation-only",
|
|
97
124
|
detectBinary: "provisional",
|
|
98
125
|
},
|
|
99
|
-
|
|
126
|
+
mcpSupport: {
|
|
127
|
+
status: "supported",
|
|
128
|
+
schemaLabel: "repo-local frontmatter-emit MCP rules",
|
|
129
|
+
path: {
|
|
130
|
+
posix: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
131
|
+
windows: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
agentRulesSupport: {
|
|
135
|
+
status: "supported",
|
|
136
|
+
schemaLabel: "repo-local Markdown rules file",
|
|
137
|
+
path: {
|
|
138
|
+
posix: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
139
|
+
windows: ["{repo}", ".agents", "rules", "{name}.md"],
|
|
140
|
+
},
|
|
141
|
+
},
|
|
100
142
|
},
|
|
101
143
|
{
|
|
102
144
|
id: "opencode",
|
|
@@ -116,10 +158,22 @@ export const AGENT_REGISTRY = [
|
|
|
116
158
|
detectBinary: "documented",
|
|
117
159
|
agentRules: "documented",
|
|
118
160
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
161
|
+
mcpSupport: {
|
|
162
|
+
status: "supported",
|
|
163
|
+
schemaLabel: "opencode.json MCP config",
|
|
164
|
+
path: {
|
|
165
|
+
posix: ["{xdg_config}", "opencode", "opencode.json"],
|
|
166
|
+
windows: ["{appdata}", "opencode", "opencode.json"],
|
|
167
|
+
},
|
|
168
|
+
mcpPatchKey: "mcp",
|
|
169
|
+
},
|
|
170
|
+
agentRulesSupport: {
|
|
171
|
+
status: "supported",
|
|
172
|
+
schemaLabel: "global Markdown rules file",
|
|
173
|
+
path: {
|
|
174
|
+
posix: ["{xdg_config}", "opencode", "AGENTS.md"],
|
|
175
|
+
windows: ["{appdata}", "opencode", "AGENTS.md"],
|
|
176
|
+
},
|
|
123
177
|
},
|
|
124
178
|
},
|
|
125
179
|
{
|
|
@@ -139,10 +193,16 @@ export const AGENT_REGISTRY = [
|
|
|
139
193
|
detectPaths: "documented",
|
|
140
194
|
detectBinary: "documented",
|
|
141
195
|
},
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
196
|
+
mcpSupport: {
|
|
197
|
+
status: "unsupported",
|
|
198
|
+
schemaLabel: "repo-scoped MCP surfaces",
|
|
199
|
+
reason: "GitHub Copilot MCP support depends on repo-scoped files such as devcontainer or agent-frontmatter mappings, which are not translated here",
|
|
200
|
+
},
|
|
201
|
+
agentRulesSupport: {
|
|
202
|
+
status: "unsupported",
|
|
203
|
+
schemaLabel: "Claude-native shared instructions",
|
|
204
|
+
reason: 'GitHub Copilot reads CLAUDE.md natively, so deploy via the "claude-code" agentRules target instead of a separate rules surface',
|
|
205
|
+
},
|
|
146
206
|
policyNote: "Organization policies may override locally deployed skills. Verify with your GitHub org admin if deployed skills are not active.",
|
|
147
207
|
},
|
|
148
208
|
];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serializes a flat (one-level) object to a YAML block suitable for use inside
|
|
3
|
+
* `---` frontmatter delimiters.
|
|
4
|
+
*/
|
|
5
|
+
export declare function serializeFrontmatter(data: Record<string, unknown>): string;
|
|
6
|
+
/**
|
|
7
|
+
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
8
|
+
* If `body` is provided it is appended after the closing delimiter.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildFrontmatterDocument(frontmatter: Record<string, unknown>, body?: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Reads an existing `.md` file and parses its frontmatter (using the
|
|
13
|
+
* `front-matter` package). Returns the parsed attributes and raw body.
|
|
14
|
+
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readFrontmatterFile(filePath: string): Promise<{
|
|
17
|
+
attributes: Record<string, unknown>;
|
|
18
|
+
body: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Atomically writes a Markdown file with the given frontmatter and optional
|
|
22
|
+
* body. Preserves any existing body content when `preserveBody` is true.
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeFrontmatterFile(filePath: string, frontmatter: Record<string, unknown>, options?: {
|
|
25
|
+
preserveBody?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const _require = createRequire(import.meta.url);
|
|
5
|
+
// front-matter is a CommonJS module whose export is the callable parse function.
|
|
6
|
+
const parseFrontmatter = _require("front-matter");
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Hand-rolled flat-YAML serializer
|
|
9
|
+
// Handles the shapes found in MCP server descriptors: strings, numbers,
|
|
10
|
+
// booleans, string arrays, and one-level nested objects (e.g. "env").
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
function serializeScalar(value) {
|
|
13
|
+
if (typeof value === "string") {
|
|
14
|
+
const needsQuotes = /[:#[\]{},|>&*!'"@`]|^\s|\s$/.test(value);
|
|
15
|
+
return needsQuotes
|
|
16
|
+
? `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`
|
|
17
|
+
: value;
|
|
18
|
+
}
|
|
19
|
+
return String(value);
|
|
20
|
+
}
|
|
21
|
+
function serializeArray(key, arr, pad) {
|
|
22
|
+
if (arr.length === 0)
|
|
23
|
+
return `${pad}${key}: []`;
|
|
24
|
+
const items = arr.map((item) => {
|
|
25
|
+
const scalar = typeof item === "string" ||
|
|
26
|
+
typeof item === "number" ||
|
|
27
|
+
typeof item === "boolean"
|
|
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}: {}`;
|
|
37
|
+
}
|
|
38
|
+
function serializeFrontmatterAtDepth(data, pad) {
|
|
39
|
+
const lines = [];
|
|
40
|
+
for (const [key, value] of Object.entries(data)) {
|
|
41
|
+
if (value === null || value === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
lines.push(serializeArray(key, value, pad));
|
|
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
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Serializes a flat (one-level) object to a YAML block suitable for use inside
|
|
57
|
+
* `---` frontmatter delimiters.
|
|
58
|
+
*/
|
|
59
|
+
export function serializeFrontmatter(data) {
|
|
60
|
+
return serializeFrontmatterAtDepth(data, "");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds the full content of a frontmatter-bearing Markdown file.
|
|
64
|
+
* If `body` is provided it is appended after the closing delimiter.
|
|
65
|
+
*/
|
|
66
|
+
export function buildFrontmatterDocument(frontmatter, body = "") {
|
|
67
|
+
const serialized = serializeFrontmatter(frontmatter);
|
|
68
|
+
return `---\n${serialized}\n---\n${body}`;
|
|
69
|
+
}
|
|
70
|
+
function createAtomicTempPath(targetPath) {
|
|
71
|
+
return `${targetPath}.inception-tmp-${process.pid}-${Date.now()}-${Math.random()
|
|
72
|
+
.toString(36)
|
|
73
|
+
.slice(2)}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Reads an existing `.md` file and parses its frontmatter (using the
|
|
77
|
+
* `front-matter` package). Returns the parsed attributes and raw body.
|
|
78
|
+
* Returns `{ attributes: {}, body: "" }` if the file does not exist.
|
|
79
|
+
*/
|
|
80
|
+
export async function readFrontmatterFile(filePath) {
|
|
81
|
+
let raw;
|
|
82
|
+
try {
|
|
83
|
+
raw = await readFile(filePath, "utf-8");
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const code = err.code;
|
|
87
|
+
if (code === "ENOENT")
|
|
88
|
+
return { attributes: {}, body: "" };
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
const parsed = parseFrontmatter(raw);
|
|
92
|
+
return { attributes: parsed.attributes, body: parsed.body };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Atomically writes a Markdown file with the given frontmatter and optional
|
|
96
|
+
* body. Preserves any existing body content when `preserveBody` is true.
|
|
97
|
+
*/
|
|
98
|
+
export async function writeFrontmatterFile(filePath, frontmatter, options = {}) {
|
|
99
|
+
let body = "";
|
|
100
|
+
if (options.preserveBody) {
|
|
101
|
+
const existing = await readFrontmatterFile(filePath);
|
|
102
|
+
body = existing.body;
|
|
103
|
+
}
|
|
104
|
+
const content = buildFrontmatterDocument(frontmatter, body);
|
|
105
|
+
const tempPath = createAtomicTempPath(filePath);
|
|
106
|
+
try {
|
|
107
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
108
|
+
await writeFile(tempPath, content, "utf-8");
|
|
109
|
+
await rename(tempPath, filePath);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
try {
|
|
113
|
+
await rm(tempPath, { force: true });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
/* best-effort cleanup */
|
|
117
|
+
}
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { AgentRuleEntry, McpServerEntry } from "../../schemas/manifest.ts";
|
|
2
|
-
import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, PlanWarning } from "../../types.ts";
|
|
2
|
+
import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, FrontmatterEmitDeployAction, PlanWarning, TomlPatchDeployAction } from "../../types.ts";
|
|
3
3
|
import { compileMcpServerReverts } from "./mcp.ts";
|
|
4
4
|
import { compileAgentRuleReverts } from "./rules.ts";
|
|
5
5
|
export { compileAgentRuleReverts, compileMcpServerReverts };
|
|
6
|
-
export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction;
|
|
6
|
+
export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction;
|
|
7
7
|
export interface AdapterResult {
|
|
8
8
|
actions: AdapterAction[];
|
|
9
9
|
warnings: PlanWarning[];
|
|
10
10
|
}
|
|
11
|
-
export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string): Promise<AdapterResult>;
|
|
11
|
+
export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string): Promise<AdapterResult>;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
|
|
2
2
|
import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
|
|
3
3
|
export { compileAgentRuleReverts, compileMcpServerReverts };
|
|
4
|
-
export async function compileAdapterActions(mcpServers, agentRules, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home) {
|
|
4
|
+
export async function compileAdapterActions(mcpServers, agentRules, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo) {
|
|
5
5
|
const actions = [];
|
|
6
6
|
const warnings = [];
|
|
7
7
|
for (const entry of mcpServers) {
|
|
8
|
-
const r = compileMcpServerActions(entry, detectedAgents, home);
|
|
8
|
+
const r = compileMcpServerActions(entry, detectedAgents, home, repo);
|
|
9
9
|
actions.push(...r.actions);
|
|
10
10
|
warnings.push(...r.warnings);
|
|
11
11
|
}
|
|
12
12
|
for (const entry of agentRules) {
|
|
13
|
-
const r = await compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home);
|
|
13
|
+
const r = await compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo);
|
|
14
14
|
actions.push(...r.actions);
|
|
15
15
|
warnings.push(...r.warnings);
|
|
16
16
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { McpServerEntry } from "../../schemas/manifest.ts";
|
|
2
|
-
import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, PlanWarning } from "../../types.ts";
|
|
2
|
+
import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, FrontmatterEmitDeployAction, FrontmatterEmitRevertAction, PlanWarning, TomlPatchDeployAction, TomlPatchRevertAction } from "../../types.ts";
|
|
3
3
|
export interface McpAdapterResult {
|
|
4
|
-
actions: ConfigPatchDeployAction
|
|
4
|
+
actions: Array<ConfigPatchDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction>;
|
|
5
5
|
warnings: PlanWarning[];
|
|
6
6
|
}
|
|
7
|
-
export declare function compileMcpServerActions(entry: McpServerEntry, detectedAgents: AgentId[], home: string): McpAdapterResult;
|
|
8
|
-
export declare function compileMcpServerReverts(entry: McpServerEntry, agentFilter: AgentId[] | null, home: string): ConfigPatchRevertAction
|
|
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>;
|
|
@@ -1,7 +1,52 @@
|
|
|
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
|
-
|
|
4
|
+
import { validateMcpServerConfigShape } from "../validation.js";
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether a resolved config path targets a TOML file.
|
|
7
|
+
*/
|
|
8
|
+
function isTomlTarget(targetPath) {
|
|
9
|
+
return path.extname(targetPath).toLowerCase() === ".toml";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Determines whether a resolved config path targets a Markdown file
|
|
13
|
+
* (indicates a frontmatter-emit surface, e.g. Antigravity's .agents/rules/).
|
|
14
|
+
*/
|
|
15
|
+
function isMarkdownTarget(targetPath) {
|
|
16
|
+
const ext = path.extname(targetPath).toLowerCase();
|
|
17
|
+
return ext === ".md" || ext === ".markdown";
|
|
18
|
+
}
|
|
19
|
+
function buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPatchKey) {
|
|
20
|
+
if (isMarkdownTarget(resolvedTarget)) {
|
|
21
|
+
return {
|
|
22
|
+
kind: "frontmatter-emit",
|
|
23
|
+
skill: entry.name,
|
|
24
|
+
agent: agentId,
|
|
25
|
+
target: resolvedTarget,
|
|
26
|
+
frontmatter: { "mcp-servers": { [entry.name]: entry.config } },
|
|
27
|
+
confidence,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (isTomlTarget(resolvedTarget)) {
|
|
31
|
+
return {
|
|
32
|
+
kind: "toml-patch",
|
|
33
|
+
skill: entry.name,
|
|
34
|
+
agent: agentId,
|
|
35
|
+
target: resolvedTarget,
|
|
36
|
+
config: entry.config,
|
|
37
|
+
confidence,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
kind: "config-patch",
|
|
42
|
+
skill: entry.name,
|
|
43
|
+
agent: agentId,
|
|
44
|
+
target: resolvedTarget,
|
|
45
|
+
patch: { [mcpPatchKey]: { [entry.name]: entry.config } },
|
|
46
|
+
confidence,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function compileMcpServerActions(entry, detectedAgents, home, repo) {
|
|
5
50
|
const actions = [];
|
|
6
51
|
const warnings = [];
|
|
7
52
|
const platform = getPlatformKey();
|
|
@@ -9,43 +54,59 @@ export function compileMcpServerActions(entry, detectedAgents, home) {
|
|
|
9
54
|
if (!detectedAgents.includes(agentId))
|
|
10
55
|
continue;
|
|
11
56
|
const agent = AGENT_REGISTRY_BY_ID[agentId];
|
|
12
|
-
|
|
57
|
+
const support = agent?.mcpSupport;
|
|
58
|
+
if (!support || support.status === "unsupported") {
|
|
13
59
|
warnings.push({
|
|
14
60
|
kind: "confidence",
|
|
15
|
-
message: `mcpServers: agent "${agentId}" does not
|
|
61
|
+
message: `mcpServers: agent "${agentId}" uses ${support?.schemaLabel ?? "an unsupported MCP schema"} and ${support?.status === "unsupported" ? support.reason : "does not expose a supported MCP adapter"} — skipping "${entry.name}"`,
|
|
16
62
|
});
|
|
17
63
|
continue;
|
|
18
64
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const resolvedTarget = path.resolve(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
agent: agentId,
|
|
26
|
-
target: resolvedTarget,
|
|
27
|
-
patch: { mcpServers: { [entry.name]: entry.config } },
|
|
28
|
-
confidence: agent.provenance.mcpConfig ?? "provisional",
|
|
29
|
-
});
|
|
65
|
+
validateMcpServerConfigShape(entry.config, entry.name, agentId);
|
|
66
|
+
const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo);
|
|
67
|
+
const resolvedTarget = path.resolve(rawTarget);
|
|
68
|
+
const confidence = agent.provenance.mcpConfig ?? "provisional";
|
|
69
|
+
const mcpPatchKey = support.mcpPatchKey ?? "mcpServers";
|
|
70
|
+
actions.push(buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPatchKey));
|
|
30
71
|
}
|
|
31
72
|
return { actions, warnings };
|
|
32
73
|
}
|
|
33
|
-
export function compileMcpServerReverts(entry, agentFilter, home) {
|
|
74
|
+
export function compileMcpServerReverts(entry, agentFilter, home, repo) {
|
|
34
75
|
const actions = [];
|
|
35
76
|
const platform = getPlatformKey();
|
|
36
77
|
for (const agentId of entry.agents) {
|
|
37
78
|
if (agentFilter && !agentFilter.includes(agentId))
|
|
38
79
|
continue;
|
|
39
80
|
const agent = AGENT_REGISTRY_BY_ID[agentId];
|
|
40
|
-
|
|
81
|
+
const support = agent?.mcpSupport;
|
|
82
|
+
if (!support || support.status === "unsupported")
|
|
41
83
|
continue;
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
84
|
+
const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo);
|
|
85
|
+
const target = path.resolve(rawTarget);
|
|
86
|
+
if (isMarkdownTarget(target)) {
|
|
87
|
+
actions.push({
|
|
88
|
+
kind: "frontmatter-emit",
|
|
89
|
+
skill: entry.name,
|
|
90
|
+
agent: agentId,
|
|
91
|
+
target,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else if (isTomlTarget(target)) {
|
|
95
|
+
actions.push({
|
|
96
|
+
kind: "toml-patch",
|
|
97
|
+
skill: entry.name,
|
|
98
|
+
agent: agentId,
|
|
99
|
+
target,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
actions.push({
|
|
104
|
+
kind: "config-patch",
|
|
105
|
+
skill: entry.name,
|
|
106
|
+
agent: agentId,
|
|
107
|
+
target,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
49
110
|
}
|
|
50
111
|
return actions;
|
|
51
112
|
}
|
|
@@ -4,5 +4,5 @@ export interface RulesAdapterResult {
|
|
|
4
4
|
actions: FileWriteDeployAction[];
|
|
5
5
|
warnings: PlanWarning[];
|
|
6
6
|
}
|
|
7
|
-
export declare function compileAgentRuleActions(entry: AgentRuleEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string): Promise<RulesAdapterResult>;
|
|
8
|
-
export declare function compileAgentRuleReverts(entry: AgentRuleEntry, agentFilter: AgentId[] | null, home: string): FileWriteRevertAction[];
|
|
7
|
+
export declare function compileAgentRuleActions(entry: AgentRuleEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string): Promise<RulesAdapterResult>;
|
|
8
|
+
export declare function compileAgentRuleReverts(entry: AgentRuleEntry, agentFilter: AgentId[] | null, home: string, repo?: string): FileWriteRevertAction[];
|
|
@@ -1,57 +1,64 @@
|
|
|
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 { validateSourceFile, validateSourcePath } from "../validation.js";
|
|
5
|
-
export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home) {
|
|
4
|
+
import { validateAgentRuleMarkdownPath, validateSourceFile, validateSourcePath, } from "../validation.js";
|
|
5
|
+
export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo) {
|
|
6
6
|
const actions = [];
|
|
7
7
|
const warnings = [];
|
|
8
8
|
const platform = getPlatformKey();
|
|
9
9
|
const targetAgents = entry.agents.filter((agentId) => detectedAgents.includes(agentId));
|
|
10
|
+
const supportedTargets = [];
|
|
10
11
|
if (targetAgents.length === 0) {
|
|
11
12
|
return { actions, warnings };
|
|
12
13
|
}
|
|
13
|
-
// Validate the source file once (before iterating agents) since it is shared.
|
|
14
|
-
const source = path.resolve(sourceDir, entry.path);
|
|
15
|
-
await validateSourcePath(source, entry.path, resolvedSourceDir, realRoot);
|
|
16
|
-
await validateSourceFile(source, entry.path);
|
|
17
14
|
for (const agentId of targetAgents) {
|
|
18
15
|
const agent = AGENT_REGISTRY_BY_ID[agentId];
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
kind: "confidence",
|
|
22
|
-
message: `agentRules: agent "${agentId}" reads CLAUDE.md natively — deploy via "claude-code" target to reach Copilot automatically; no separate deployment needed`,
|
|
23
|
-
});
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (!agent?.agentRulesPath) {
|
|
16
|
+
const support = agent?.agentRulesSupport;
|
|
17
|
+
if (!support || support.status === "unsupported") {
|
|
27
18
|
warnings.push({
|
|
28
19
|
kind: "confidence",
|
|
29
|
-
message: `agentRules: agent "${agentId}" does not
|
|
20
|
+
message: `agentRules: agent "${agentId}" uses ${support?.schemaLabel ?? "an unsupported instruction schema"} and ${support?.status === "unsupported" ? support.reason : "does not expose a supported rules adapter"} — skipping "${entry.name}"`,
|
|
30
21
|
});
|
|
31
22
|
continue;
|
|
32
23
|
}
|
|
33
|
-
|
|
24
|
+
supportedTargets.push({
|
|
25
|
+
agentId,
|
|
26
|
+
confidence: agent.provenance.agentRules ?? "provisional",
|
|
27
|
+
target: resolvePlaceholders(support.path[platform], entry.name, home, repo),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (supportedTargets.length === 0) {
|
|
31
|
+
return { actions, warnings };
|
|
32
|
+
}
|
|
33
|
+
// Validate the shared source file only when at least one target uses the
|
|
34
|
+
// current global-Markdown adapter surface.
|
|
35
|
+
const source = path.resolve(sourceDir, entry.path);
|
|
36
|
+
await validateSourcePath(source, entry.path, resolvedSourceDir, realRoot);
|
|
37
|
+
await validateSourceFile(source, entry.path);
|
|
38
|
+
for (const target of supportedTargets) {
|
|
39
|
+
validateAgentRuleMarkdownPath(entry.path, target.agentId);
|
|
34
40
|
actions.push({
|
|
35
41
|
kind: "file-write",
|
|
36
42
|
skill: entry.name,
|
|
37
|
-
agent: agentId,
|
|
43
|
+
agent: target.agentId,
|
|
38
44
|
source,
|
|
39
|
-
target,
|
|
40
|
-
confidence:
|
|
45
|
+
target: target.target,
|
|
46
|
+
confidence: target.confidence,
|
|
41
47
|
});
|
|
42
48
|
}
|
|
43
49
|
return { actions, warnings };
|
|
44
50
|
}
|
|
45
|
-
export function compileAgentRuleReverts(entry, agentFilter, home) {
|
|
51
|
+
export function compileAgentRuleReverts(entry, agentFilter, home, repo) {
|
|
46
52
|
const actions = [];
|
|
47
53
|
const platform = getPlatformKey();
|
|
48
54
|
for (const agentId of entry.agents) {
|
|
49
55
|
if (agentFilter && !agentFilter.includes(agentId))
|
|
50
56
|
continue;
|
|
51
57
|
const agent = AGENT_REGISTRY_BY_ID[agentId];
|
|
52
|
-
|
|
58
|
+
const support = agent?.agentRulesSupport;
|
|
59
|
+
if (!support || support.status === "unsupported")
|
|
53
60
|
continue;
|
|
54
|
-
const target = resolvePlaceholders(
|
|
61
|
+
const target = resolvePlaceholders(support.path[platform], entry.name, home, repo);
|
|
55
62
|
actions.push({
|
|
56
63
|
kind: "file-write",
|
|
57
64
|
skill: entry.name,
|