@kuznai/inception-engine 0.19.0 → 0.21.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.
Files changed (111) hide show
  1. package/README.md +50 -22
  2. package/dist/{config → src/config}/agents.js +113 -14
  3. package/dist/{core → src/core}/adapters/agent-definitions.d.ts +0 -12
  4. package/dist/src/core/adapters/agent-definitions.js +162 -0
  5. package/dist/{core → src/core}/adapters/frontmatter.d.ts +10 -0
  6. package/dist/{core → src/core}/adapters/frontmatter.js +23 -6
  7. package/dist/src/core/adapters/index.js +25 -0
  8. package/dist/{core → src/core}/adapters/mcp.js +17 -20
  9. package/dist/{core → src/core}/adapters/permissions.js +16 -20
  10. package/dist/{core → src/core}/adapters/rules.js +26 -50
  11. package/dist/src/core/capabilities.d.ts +47 -0
  12. package/dist/src/core/capabilities.js +280 -0
  13. package/dist/{core → src/core}/deploy.js +82 -54
  14. package/dist/{core → src/core}/detect.js +2 -7
  15. package/dist/{core → src/core}/init.js +20 -25
  16. package/dist/src/core/merge-patch.d.ts +4 -0
  17. package/dist/src/core/merge-patch.js +46 -0
  18. package/dist/{core → src/core}/ownership.js +13 -0
  19. package/dist/src/core/preflight.js +296 -0
  20. package/dist/{core → src/core}/revert.js +86 -26
  21. package/dist/{core → src/core}/validation.js +31 -0
  22. package/dist/{errors.d.ts → src/errors.d.ts} +3 -1
  23. package/dist/{errors.js → src/errors.js} +2 -2
  24. package/dist/{schemas → src/schemas}/manifest.d.ts +20 -0
  25. package/dist/{schemas → src/schemas}/manifest.js +11 -0
  26. package/dist/{schemas → src/schemas}/registry.d.ts +36 -0
  27. package/dist/{schemas → src/schemas}/registry.js +12 -4
  28. package/dist/{types.d.ts → src/types.d.ts} +15 -0
  29. package/dist/test/helpers/fs.d.ts +2 -0
  30. package/dist/test/helpers/fs.js +17 -0
  31. package/dist/test/helpers/path.d.ts +10 -0
  32. package/dist/test/helpers/path.js +15 -0
  33. package/dist/test/helpers/skill-dir-scenarios.d.ts +7 -0
  34. package/dist/test/helpers/skill-dir-scenarios.js +206 -0
  35. package/dist/test/helpers/skill-dir.d.ts +7 -0
  36. package/dist/test/helpers/skill-dir.js +46 -0
  37. package/dist/test/os/cross-platform/cross-platform.test.d.ts +1 -0
  38. package/dist/test/os/cross-platform/cross-platform.test.js +328 -0
  39. package/dist/test/os/posix/skill-dir.test.d.ts +1 -0
  40. package/dist/test/os/posix/skill-dir.test.js +19 -0
  41. package/dist/test/os/windows/agentRules-integration.test.d.ts +1 -0
  42. package/dist/test/os/windows/agentRules-integration.test.js +245 -0
  43. package/dist/test/os/windows/revert-integration.test.d.ts +1 -0
  44. package/dist/test/os/windows/revert-integration.test.js +72 -0
  45. package/dist/test/os/windows/skill-dir.test.d.ts +1 -0
  46. package/dist/test/os/windows/skill-dir.test.js +19 -0
  47. package/dist/test/unit/adapters.test.d.ts +1 -0
  48. package/dist/test/unit/adapters.test.js +1017 -0
  49. package/dist/test/unit/capabilities.test.d.ts +1 -0
  50. package/dist/test/unit/capabilities.test.js +71 -0
  51. package/dist/test/unit/cli.test.d.ts +1 -0
  52. package/dist/test/unit/cli.test.js +834 -0
  53. package/dist/test/unit/deploy.test.d.ts +1 -0
  54. package/dist/test/unit/deploy.test.js +2481 -0
  55. package/dist/test/unit/detect.test.d.ts +1 -0
  56. package/dist/test/unit/detect.test.js +192 -0
  57. package/dist/test/unit/enterprise.test.d.ts +1 -0
  58. package/dist/test/unit/enterprise.test.js +106 -0
  59. package/dist/test/unit/frontmatter.test.d.ts +1 -0
  60. package/dist/test/unit/frontmatter.test.js +102 -0
  61. package/dist/test/unit/gemini-north-star.test.d.ts +1 -0
  62. package/dist/test/unit/gemini-north-star.test.js +243 -0
  63. package/dist/test/unit/init-fixture.test.d.ts +1 -0
  64. package/dist/test/unit/init-fixture.test.js +153 -0
  65. package/dist/test/unit/manifest.test.d.ts +1 -0
  66. package/dist/test/unit/manifest.test.js +737 -0
  67. package/dist/test/unit/migration-golden.test.d.ts +1 -0
  68. package/dist/test/unit/migration-golden.test.js +197 -0
  69. package/dist/test/unit/ownership.test.d.ts +1 -0
  70. package/dist/test/unit/ownership.test.js +587 -0
  71. package/dist/test/unit/preflight.test.d.ts +1 -0
  72. package/dist/test/unit/preflight.test.js +521 -0
  73. package/dist/test/unit/resolve.test.d.ts +1 -0
  74. package/dist/test/unit/resolve.test.js +119 -0
  75. package/dist/test/unit/revert.test.d.ts +1 -0
  76. package/dist/test/unit/revert.test.js +1004 -0
  77. package/dist/test/unit/toml.test.d.ts +1 -0
  78. package/dist/test/unit/toml.test.js +55 -0
  79. package/package.json +1 -1
  80. package/dist/core/adapters/agent-definitions.js +0 -91
  81. package/dist/core/adapters/index.js +0 -30
  82. package/dist/core/preflight.js +0 -168
  83. /package/dist/{config → src/config}/agents.d.ts +0 -0
  84. /package/dist/{config → src/config}/manifest.d.ts +0 -0
  85. /package/dist/{config → src/config}/manifest.js +0 -0
  86. /package/dist/{core → src/core}/adapters/index.d.ts +0 -0
  87. /package/dist/{core → src/core}/adapters/mcp.d.ts +0 -0
  88. /package/dist/{core → src/core}/adapters/permissions.d.ts +0 -0
  89. /package/dist/{core → src/core}/adapters/rules.d.ts +0 -0
  90. /package/dist/{core → src/core}/adapters/toml.d.ts +0 -0
  91. /package/dist/{core → src/core}/adapters/toml.js +0 -0
  92. /package/dist/{core → src/core}/deploy.d.ts +0 -0
  93. /package/dist/{core → src/core}/detect.d.ts +0 -0
  94. /package/dist/{core → src/core}/init.d.ts +0 -0
  95. /package/dist/{core → src/core}/ownership.d.ts +0 -0
  96. /package/dist/{core → src/core}/preflight.d.ts +0 -0
  97. /package/dist/{core → src/core}/resolve.d.ts +0 -0
  98. /package/dist/{core → src/core}/resolve.js +0 -0
  99. /package/dist/{core → src/core}/revert.d.ts +0 -0
  100. /package/dist/{core → src/core}/runtime-paths.d.ts +0 -0
  101. /package/dist/{core → src/core}/runtime-paths.js +0 -0
  102. /package/dist/{core → src/core}/validation.d.ts +0 -0
  103. /package/dist/{formatters.d.ts → src/formatters.d.ts} +0 -0
  104. /package/dist/{formatters.js → src/formatters.js} +0 -0
  105. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  106. /package/dist/{index.js → src/index.js} +0 -0
  107. /package/dist/{logger.d.ts → src/logger.d.ts} +0 -0
  108. /package/dist/{logger.js → src/logger.js} +0 -0
  109. /package/dist/{schemas → src/schemas}/errors.d.ts +0 -0
  110. /package/dist/{schemas → src/schemas}/errors.js +0 -0
  111. /package/dist/{types.js → src/types.js} +0 -0
@@ -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 { attributes: {}, body: "" };
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
- return parseFrontmatterDocument(raw);
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
@@ -0,0 +1,25 @@
1
+ import { compileAgentDefinitionActions, compileAgentDefinitionReverts, } from "./agent-definitions.js";
2
+ import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
3
+ import { compilePermissionsActions, compilePermissionsReverts, } from "./permissions.js";
4
+ import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
5
+ export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
6
+ async function compileAll(entries, fn) {
7
+ const results = await Promise.all(entries.map(fn));
8
+ return {
9
+ actions: results.flatMap((r) => r.actions),
10
+ warnings: results.flatMap((r) => r.warnings),
11
+ };
12
+ }
13
+ export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions, workspace) {
14
+ const actions = [];
15
+ const warnings = [];
16
+ const [mcp, rules, perms, defs] = await Promise.all([
17
+ compileAll(mcpServers, (entry) => compileMcpServerActions(entry, detectedAgents, home, repo, workspace)),
18
+ compileAll(agentRules, (entry) => compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
19
+ compileAll(permissions, (entry) => compilePermissionsActions(entry, detectedAgents, home)),
20
+ compileAll(agentDefinitions ?? [], (entry) => compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
21
+ ]);
22
+ actions.push(...mcp.actions, ...rules.actions, ...perms.actions, ...defs.actions);
23
+ warnings.push(...mcp.warnings, ...rules.warnings, ...perms.warnings, ...defs.warnings);
24
+ return { actions, warnings };
25
+ }
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
2
+ import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
3
3
  import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
4
  import { validateMcpServerConfigShape } from "../validation.js";
5
5
  /**
@@ -53,26 +53,26 @@ export function compileMcpServerActions(entry, detectedAgents, home, repo, works
53
53
  for (const agentId of entry.agents) {
54
54
  if (!detectedAgents.includes(agentId))
55
55
  continue;
56
- const agent = AGENT_REGISTRY_BY_ID[agentId];
57
- const support = agent?.mcpSupport;
58
- if (!support || support.status === "unsupported") {
59
- warnings.push({
60
- kind: "confidence",
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}"`,
62
- });
56
+ const plan = planCapabilityForDeploy({
57
+ agentId,
58
+ capability: "mcpServers",
59
+ entryName: entry.name,
60
+ targetAgentIds: entry.agents,
61
+ scope: entry.scope,
62
+ });
63
+ if (plan.outcome === "warn") {
64
+ warnings.push(plan.warning);
63
65
  continue;
64
66
  }
65
- if (support.status === "planned") {
66
- warnings.push({
67
- kind: "confidence",
68
- message: `mcpServers: agent "${agentId}" MCP support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
69
- });
67
+ if (plan.outcome === "native" || plan.outcome === "redundant")
68
+ continue;
69
+ const support = resolveCapabilitySurface(agentId, "mcpServers", entry.scope).support;
70
+ if (!support)
70
71
  continue;
71
- }
72
72
  validateMcpServerConfigShape(entry.config, entry.name, agentId);
73
73
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace);
74
74
  const resolvedTarget = path.resolve(rawTarget);
75
- const confidence = agent.provenance.mcpConfig ?? "provisional";
75
+ const confidence = plan.confidence ?? "provisional";
76
76
  const mcpPatchKey = support.mcpPatchKey ?? "mcpServers";
77
77
  actions.push(buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPatchKey));
78
78
  }
@@ -84,11 +84,8 @@ export function compileMcpServerReverts(entry, agentFilter, home, repo, workspac
84
84
  for (const agentId of entry.agents) {
85
85
  if (agentFilter && !agentFilter.includes(agentId))
86
86
  continue;
87
- const agent = AGENT_REGISTRY_BY_ID[agentId];
88
- const support = agent?.mcpSupport;
89
- if (!support ||
90
- support.status === "unsupported" ||
91
- support.status === "planned")
87
+ const support = resolveCapabilitySurface(agentId, "mcpServers", entry.scope).support;
88
+ if (!support)
92
89
  continue;
93
90
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace);
94
91
  const target = path.resolve(rawTarget);
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
2
+ import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
3
3
  import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
4
  import { validatePermissionsConfigShape } from "../validation.js";
5
5
  function isTomlTarget(targetPath) {
@@ -12,26 +12,25 @@ export function compilePermissionsActions(entry, detectedAgents, home) {
12
12
  for (const agentId of entry.agents) {
13
13
  if (!detectedAgents.includes(agentId))
14
14
  continue;
15
- const agent = AGENT_REGISTRY_BY_ID[agentId];
16
- const support = agent?.permissionsSupport;
17
- if (!support || support.status === "unsupported") {
18
- warnings.push({
19
- kind: "confidence",
20
- message: `permissions: agent "${agentId}" ${support?.status === "unsupported" ? support.reason : "does not expose a supported permissions adapter"} — skipping "${entry.name}"`,
21
- });
15
+ const plan = planCapabilityForDeploy({
16
+ agentId,
17
+ capability: "permissions",
18
+ entryName: entry.name,
19
+ targetAgentIds: entry.agents,
20
+ });
21
+ if (plan.outcome === "warn") {
22
+ warnings.push(plan.warning);
22
23
  continue;
23
24
  }
24
- if (support.status === "planned") {
25
- warnings.push({
26
- kind: "confidence",
27
- message: `permissions: agent "${agentId}" permissions support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
28
- });
25
+ if (plan.outcome === "native" || plan.outcome === "redundant")
26
+ continue;
27
+ const support = resolveCapabilitySurface(agentId, "permissions").support;
28
+ if (!support)
29
29
  continue;
30
- }
31
30
  validatePermissionsConfigShape(entry.config, entry.name, agentId);
32
31
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
33
32
  const resolvedTarget = path.resolve(rawTarget);
34
- const confidence = agent.provenance.permissions ?? "provisional";
33
+ const confidence = plan.confidence ?? "provisional";
35
34
  if (isTomlTarget(resolvedTarget)) {
36
35
  actions.push({
37
36
  kind: "toml-patch",
@@ -61,11 +60,8 @@ export function compilePermissionsReverts(entry, agentFilter, home) {
61
60
  for (const agentId of entry.agents) {
62
61
  if (agentFilter && !agentFilter.includes(agentId))
63
62
  continue;
64
- const agent = AGENT_REGISTRY_BY_ID[agentId];
65
- const support = agent?.permissionsSupport;
66
- if (!support ||
67
- support.status === "unsupported" ||
68
- support.status === "planned")
63
+ const support = resolveCapabilitySurface(agentId, "permissions").support;
64
+ if (!support)
69
65
  continue;
70
66
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
71
67
  const target = path.resolve(rawTarget);
@@ -1,44 +1,21 @@
1
1
  import path from "node:path";
2
- import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
2
+ import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
3
3
  import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
4
  import { validateAgentRuleMarkdownPath, validateInstructionFileRequirements, validateSourceFile, validateSourcePath, } from "../validation.js";
5
- function resolveRulesSupport(agentId, scope) {
6
- const agent = AGENT_REGISTRY_BY_ID[agentId];
7
- if (scope === "repo") {
8
- return agent?.agentRulesRepoSupport ?? agent?.agentRulesSupport;
9
- }
10
- if (scope === "workspace") {
11
- return (agent?.agentRulesWorkspaceSupport ??
12
- agent?.agentRulesRepoSupport ??
13
- agent?.agentRulesSupport);
14
- }
15
- return agent?.agentRulesSupport;
16
- }
17
5
  function resolveAgentTarget(agentId, entry, home, repo, platform, workspace, allTargetAgentIds) {
18
- const support = resolveRulesSupport(agentId, entry.scope);
19
- if (!support || support.status === "unsupported") {
20
- return {
21
- kind: "confidence",
22
- message: `agentRules: agent "${agentId}" uses ${support?.schemaLabel ?? "an unsupported instruction schema"} (unsupported) and ${support?.status === "unsupported" ? support.reason : "does not expose a supported rules adapter"} — skipping "${entry.name}"`,
23
- };
24
- }
25
- if (support.status === "planned") {
26
- return {
27
- kind: "confidence",
28
- message: `agentRules: agent "${agentId}" rules support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
29
- };
30
- }
31
- // shared-via: when requiresPrimary is set and the primary agent is absent
32
- // from the target list, emit a guidance warning instead of deploying.
33
- if (support.surfaceKind?.kind === "shared-via" &&
34
- support.surfaceKind.requiresPrimary &&
35
- allTargetAgentIds &&
36
- !allTargetAgentIds.includes(support.surfaceKind.via)) {
37
- return {
38
- kind: "confidence",
39
- message: `agentRules: agent "${agentId}" reads this surface via "${support.surfaceKind.via}" — add "${support.surfaceKind.via}" to the entry's agents list to deploy to this surface, or deploy via the "${support.surfaceKind.via}" agentRules target instead`,
40
- };
41
- }
6
+ const plan = planCapabilityForDeploy({
7
+ agentId,
8
+ capability: "agentRules",
9
+ entryName: entry.name,
10
+ targetAgentIds: allTargetAgentIds ?? [agentId],
11
+ scope: entry.scope,
12
+ });
13
+ if (plan.outcome === "warn")
14
+ return plan.warning;
15
+ if (plan.outcome === "native" || plan.outcome === "redundant")
16
+ return null;
17
+ const surface = resolveCapabilitySurface(agentId, "agentRules", entry.scope);
18
+ const support = surface.support;
42
19
  if (entry.scope === "repo" && !repo) {
43
20
  return {
44
21
  kind: "confidence",
@@ -51,11 +28,10 @@ function resolveAgentTarget(agentId, entry, home, repo, platform, workspace, all
51
28
  message: `agentRules: scope "workspace" requires a workspace or repository path but none was resolved — skipping "${entry.name}" for agent "${agentId}"`,
52
29
  };
53
30
  }
54
- const agent = AGENT_REGISTRY_BY_ID[agentId];
55
31
  return {
56
32
  agentId,
57
- confidence: agent?.provenance.agentRules ?? "provisional",
58
- target: resolvePlaceholders(support.path[platform], entry.name, home, repo, workspace),
33
+ confidence: plan.confidence,
34
+ target: resolvePlaceholders(support?.path[platform] ?? [], entry.name, home, repo, workspace),
59
35
  };
60
36
  }
61
37
  export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace) {
@@ -69,6 +45,9 @@ export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDi
69
45
  }
70
46
  for (const agentId of targetAgents) {
71
47
  const result = resolveAgentTarget(agentId, entry, home, repo, platform, workspace, targetAgents);
48
+ if (result === null) {
49
+ continue;
50
+ }
72
51
  if ("kind" in result) {
73
52
  warnings.push(result);
74
53
  }
@@ -85,12 +64,10 @@ export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDi
85
64
  const seenTargetPaths = new Set();
86
65
  const dedupedTargets = [];
87
66
  for (const t of supportedTargets) {
88
- const sup = resolveRulesSupport(t.agentId, entry.scope);
89
- if (sup?.status === "supported" &&
90
- sup.surfaceKind?.kind === "shared-via" &&
91
- supportedTargets.some((o) => o.agentId ===
92
- sup.surfaceKind.via &&
93
- o.target === t.target)) {
67
+ const surface = resolveCapabilitySurface(t.agentId, "agentRules", entry.scope);
68
+ if (surface.surfaceKind === "shared-via" &&
69
+ surface.sharedVia &&
70
+ supportedTargets.some((o) => o.agentId === surface.sharedVia && o.target === t.target)) {
94
71
  // Primary agent is present and writes the same target — skip rider.
95
72
  continue;
96
73
  }
@@ -125,10 +102,9 @@ export function compileAgentRuleReverts(entry, agentFilter, home, repo, workspac
125
102
  for (const agentId of entry.agents) {
126
103
  if (agentFilter && !agentFilter.includes(agentId))
127
104
  continue;
128
- const support = resolveRulesSupport(agentId, entry.scope);
129
- if (!support ||
130
- support.status === "unsupported" ||
131
- support.status === "planned") {
105
+ const surface = resolveCapabilitySurface(agentId, "agentRules", entry.scope);
106
+ const support = surface.support;
107
+ if (surface.supportStatus !== "supported" || !support) {
132
108
  continue;
133
109
  }
134
110
  if (entry.scope === "repo" && !repo)
@@ -0,0 +1,47 @@
1
+ import type { AgentId, AgentSurfaceSupport, CapabilityKind, Confidence, PlanWarning, SupportedAgentSurface } from "../types.ts";
2
+ type CapabilityScope = "global" | "repo" | "workspace";
3
+ export interface ResolvedCapabilitySurface {
4
+ agentId: AgentId;
5
+ capability: CapabilityKind;
6
+ supportStatus: "supported" | "unsupported" | "planned";
7
+ support?: SupportedAgentSurface;
8
+ supportRecord?: AgentSurfaceSupport;
9
+ confidence?: Confidence;
10
+ schemaLabel: string;
11
+ surfaceKind: "agent-specific" | "native" | "shared-via";
12
+ sharedVia?: AgentId;
13
+ requiresPrimary: boolean;
14
+ canDeployDirectlyWhenPrimaryAbsent: boolean;
15
+ includeInInitByDefault: boolean;
16
+ reason?: string;
17
+ plannedSurface?: string;
18
+ }
19
+ export type DeployCapabilityPlan = {
20
+ outcome: "action";
21
+ confidence?: Confidence;
22
+ support?: SupportedAgentSurface;
23
+ } | {
24
+ outcome: "redundant";
25
+ confidence?: Confidence;
26
+ support?: SupportedAgentSurface;
27
+ sharedVia: AgentId;
28
+ } | {
29
+ outcome: "warn";
30
+ warning: PlanWarning;
31
+ } | {
32
+ outcome: "native";
33
+ };
34
+ export declare function resolveCapabilitySurface(agentId: AgentId, capability: CapabilityKind, scope?: CapabilityScope): ResolvedCapabilitySurface;
35
+ export declare function planCapabilityForDeploy(opts: {
36
+ agentId: AgentId;
37
+ capability: CapabilityKind;
38
+ entryName: string;
39
+ targetAgentIds: AgentId[];
40
+ scope?: CapabilityScope;
41
+ }): DeployCapabilityPlan;
42
+ export declare function shouldInitIncludeAgent(agentId: AgentId, capability: CapabilityKind, scope?: CapabilityScope): boolean;
43
+ export declare function describeCapabilityConfidence(agentId: AgentId, capability: CapabilityKind, scope?: CapabilityScope): {
44
+ confidence?: Confidence;
45
+ message: string | null;
46
+ };
47
+ export {};
@@ -0,0 +1,280 @@
1
+ import { AGENT_REGISTRY_BY_ID } from "../config/agents.js";
2
+ function resolveAgentRulesSupport(agentId, scope) {
3
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
4
+ if (scope === "repo") {
5
+ return agent?.agentRulesRepoSupport ?? agent?.agentRulesSupport;
6
+ }
7
+ if (scope === "workspace") {
8
+ return (agent?.agentRulesWorkspaceSupport ??
9
+ agent?.agentRulesRepoSupport ??
10
+ agent?.agentRulesSupport);
11
+ }
12
+ return agent?.agentRulesSupport;
13
+ }
14
+ function resolveMcpSupport(agentId, scope) {
15
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
16
+ if (scope === "repo") {
17
+ return agent?.mcpRepoSupport ?? agent?.mcpSupport;
18
+ }
19
+ if (scope === "workspace") {
20
+ return (agent?.mcpWorkspaceSupport ?? agent?.mcpRepoSupport ?? agent?.mcpSupport);
21
+ }
22
+ return agent?.mcpSupport;
23
+ }
24
+ function resolveAgentDefinitionsSupport(agentId, scope) {
25
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
26
+ if (scope === "repo") {
27
+ return agent?.agentDefinitionsRepoSupport ?? agent?.agentDefinitionsSupport;
28
+ }
29
+ if (scope === "workspace") {
30
+ return (agent?.agentDefinitionsWorkspaceSupport ??
31
+ agent?.agentDefinitionsRepoSupport ??
32
+ agent?.agentDefinitionsSupport);
33
+ }
34
+ return agent?.agentDefinitionsSupport;
35
+ }
36
+ function capabilityLabel(capability) {
37
+ switch (capability) {
38
+ case "skills":
39
+ return "skills";
40
+ case "mcpServers":
41
+ return "mcpServers";
42
+ case "agentRules":
43
+ return "agentRules";
44
+ case "permissions":
45
+ return "permissions";
46
+ case "agentDefinitions":
47
+ return "agentDefinitions";
48
+ }
49
+ }
50
+ function capabilitySurfaceLabel(capability) {
51
+ switch (capability) {
52
+ case "skills":
53
+ return "skill";
54
+ case "mcpServers":
55
+ return "MCP";
56
+ case "agentRules":
57
+ return "rules";
58
+ case "permissions":
59
+ return "permissions";
60
+ case "agentDefinitions":
61
+ return "agent-definitions";
62
+ }
63
+ }
64
+ function resolveSkillsCapability(agentId) {
65
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
66
+ if (agent.skills) {
67
+ return {
68
+ agentId,
69
+ capability: "skills",
70
+ supportStatus: "supported",
71
+ confidence: agent.provenance.skills ?? "provisional",
72
+ schemaLabel: "dedicated skill directory",
73
+ surfaceKind: "agent-specific",
74
+ requiresPrimary: false,
75
+ canDeployDirectlyWhenPrimaryAbsent: true,
76
+ includeInInitByDefault: true,
77
+ };
78
+ }
79
+ const via = agent.skillsSurfaceKind?.via;
80
+ return {
81
+ agentId,
82
+ capability: "skills",
83
+ supportStatus: "supported",
84
+ confidence: agent.provenance.skills,
85
+ schemaLabel: "shared native skill directory",
86
+ surfaceKind: agent.skillsSurfaceKind?.kind === "shared-via" ? "shared-via" : "native",
87
+ sharedVia: via,
88
+ requiresPrimary: true,
89
+ canDeployDirectlyWhenPrimaryAbsent: false,
90
+ includeInInitByDefault: false,
91
+ };
92
+ }
93
+ function getSurfaceRecordAndConfidence(agentId, capability, scope) {
94
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
95
+ if (capability === "mcpServers") {
96
+ return {
97
+ supportRecord: resolveMcpSupport(agentId, scope),
98
+ confidence: agent.provenance.mcpConfig,
99
+ };
100
+ }
101
+ if (capability === "agentRules") {
102
+ return {
103
+ supportRecord: resolveAgentRulesSupport(agentId, scope),
104
+ confidence: agent.provenance.agentRules,
105
+ };
106
+ }
107
+ if (capability === "permissions") {
108
+ return {
109
+ supportRecord: agent.permissionsSupport,
110
+ confidence: agent.provenance.permissions,
111
+ };
112
+ }
113
+ return {
114
+ supportRecord: resolveAgentDefinitionsSupport(agentId, scope),
115
+ confidence: agent.provenance.agentDefinitions,
116
+ };
117
+ }
118
+ function resolveUnsupportedSurface(agentId, capability, supportRecord, confidence) {
119
+ return {
120
+ agentId,
121
+ capability,
122
+ supportStatus: "unsupported",
123
+ supportRecord,
124
+ confidence,
125
+ schemaLabel: supportRecord?.schemaLabel ?? "an unsupported surface",
126
+ surfaceKind: "agent-specific",
127
+ requiresPrimary: false,
128
+ canDeployDirectlyWhenPrimaryAbsent: false,
129
+ includeInInitByDefault: false,
130
+ reason: supportRecord?.status === "unsupported"
131
+ ? supportRecord.reason
132
+ : undefined,
133
+ };
134
+ }
135
+ function resolvePlannedSurface(agentId, capability, supportRecord, confidence) {
136
+ return {
137
+ agentId,
138
+ capability,
139
+ supportStatus: "planned",
140
+ supportRecord,
141
+ confidence,
142
+ schemaLabel: supportRecord.schemaLabel,
143
+ surfaceKind: "agent-specific",
144
+ requiresPrimary: false,
145
+ canDeployDirectlyWhenPrimaryAbsent: false,
146
+ includeInInitByDefault: false,
147
+ reason: supportRecord.reason,
148
+ plannedSurface: supportRecord.plannedSurface,
149
+ };
150
+ }
151
+ function resolveSupportedSurface(agentId, capability, supportRecord, confidence) {
152
+ const surfaceKind = supportRecord.surfaceKind?.kind ?? "agent-specific";
153
+ const sharedVia = supportRecord.surfaceKind?.kind === "shared-via"
154
+ ? supportRecord.surfaceKind.via
155
+ : undefined;
156
+ const requiresPrimary = supportRecord.surfaceKind?.kind === "shared-via" &&
157
+ supportRecord.surfaceKind.requiresPrimary === true;
158
+ return {
159
+ agentId,
160
+ capability,
161
+ supportStatus: "supported",
162
+ support: supportRecord,
163
+ supportRecord,
164
+ confidence: confidence ?? "provisional",
165
+ schemaLabel: supportRecord.schemaLabel,
166
+ surfaceKind,
167
+ sharedVia,
168
+ requiresPrimary,
169
+ canDeployDirectlyWhenPrimaryAbsent: surfaceKind !== "shared-via" || !requiresPrimary,
170
+ includeInInitByDefault: surfaceKind === "agent-specific",
171
+ };
172
+ }
173
+ export function resolveCapabilitySurface(agentId, capability, scope = "global") {
174
+ if (capability === "skills")
175
+ return resolveSkillsCapability(agentId);
176
+ const { supportRecord, confidence } = getSurfaceRecordAndConfidence(agentId, capability, scope);
177
+ if (!supportRecord || supportRecord.status === "unsupported") {
178
+ return resolveUnsupportedSurface(agentId, capability, supportRecord, confidence);
179
+ }
180
+ if (supportRecord.status === "planned") {
181
+ return resolvePlannedSurface(agentId, capability, supportRecord, confidence);
182
+ }
183
+ return resolveSupportedSurface(agentId, capability, supportRecord, confidence);
184
+ }
185
+ function createSurfaceWarning(surface, entryName) {
186
+ const label = capabilityLabel(surface.capability);
187
+ if (surface.supportStatus === "unsupported") {
188
+ return {
189
+ kind: "confidence",
190
+ message: `${label}: agent "${surface.agentId}" uses ${surface.schemaLabel} (unsupported) and ${surface.reason ?? "does not expose a supported adapter"} — skipping "${entryName}"`,
191
+ };
192
+ }
193
+ if (surface.supportStatus === "planned") {
194
+ return {
195
+ kind: "confidence",
196
+ message: `${label}: agent "${surface.agentId}" ${capabilitySurfaceLabel(surface.capability)} support is planned via ${surface.plannedSurface} — skipping "${entryName}" until that surface is implemented`,
197
+ };
198
+ }
199
+ if (surface.surfaceKind === "shared-via" && surface.sharedVia) {
200
+ return {
201
+ kind: "confidence",
202
+ message: `${label}: agent "${surface.agentId}" reads this surface via "${surface.sharedVia}" — add "${surface.sharedVia}" to the entry's agents list to deploy to this surface, or deploy via the "${surface.sharedVia}" ${label} target instead`,
203
+ };
204
+ }
205
+ return {
206
+ kind: "confidence",
207
+ message: `${label}: agent "${surface.agentId}" does not expose a directly deployable surface — skipping "${entryName}"`,
208
+ };
209
+ }
210
+ export function planCapabilityForDeploy(opts) {
211
+ const surface = resolveCapabilitySurface(opts.agentId, opts.capability, opts.scope);
212
+ if (surface.supportStatus !== "supported") {
213
+ return {
214
+ outcome: "warn",
215
+ warning: createSurfaceWarning(surface, opts.entryName),
216
+ };
217
+ }
218
+ if (surface.surfaceKind === "native") {
219
+ return { outcome: "native" };
220
+ }
221
+ if (surface.surfaceKind === "shared-via" && surface.sharedVia) {
222
+ if (opts.targetAgentIds.includes(surface.sharedVia)) {
223
+ return {
224
+ outcome: "redundant",
225
+ confidence: surface.confidence,
226
+ support: surface.support,
227
+ sharedVia: surface.sharedVia,
228
+ };
229
+ }
230
+ if (!surface.canDeployDirectlyWhenPrimaryAbsent) {
231
+ return {
232
+ outcome: "warn",
233
+ warning: createSurfaceWarning(surface, opts.entryName),
234
+ };
235
+ }
236
+ }
237
+ return {
238
+ outcome: "action",
239
+ confidence: surface.confidence,
240
+ support: surface.support,
241
+ };
242
+ }
243
+ export function shouldInitIncludeAgent(agentId, capability, scope = "global") {
244
+ return resolveCapabilitySurface(agentId, capability, scope)
245
+ .includeInInitByDefault;
246
+ }
247
+ export function describeCapabilityConfidence(agentId, capability, scope = "global") {
248
+ const surface = resolveCapabilitySurface(agentId, capability, scope);
249
+ if (surface.supportStatus === "planned") {
250
+ return {
251
+ confidence: surface.confidence,
252
+ message: `Agent "${agentId}" ${capabilitySurfaceLabel(capability)} support remains planned via ${surface.plannedSurface}.`,
253
+ };
254
+ }
255
+ if (surface.supportStatus === "unsupported") {
256
+ return {
257
+ confidence: surface.confidence,
258
+ message: `Agent "${agentId}" ${capabilitySurfaceLabel(capability)} surface is unsupported: ${surface.reason ?? surface.schemaLabel}.`,
259
+ };
260
+ }
261
+ if (surface.surfaceKind === "shared-via" && surface.sharedVia) {
262
+ return {
263
+ confidence: surface.confidence,
264
+ message: `Agent "${agentId}" ${capabilitySurfaceLabel(capability)} surface is shared through "${surface.sharedVia}"${surface.requiresPrimary ? " and requires the primary target to deploy" : ""}.`,
265
+ };
266
+ }
267
+ if (surface.confidence === "implementation-only") {
268
+ return {
269
+ confidence: surface.confidence,
270
+ message: `Agent "${agentId}" ${capabilitySurfaceLabel(capability)} support is implementation-only: behavior is based on registry inspection and local validation, not published documentation.`,
271
+ };
272
+ }
273
+ if (surface.confidence === "provisional") {
274
+ return {
275
+ confidence: surface.confidence,
276
+ message: `Agent "${agentId}" ${capabilitySurfaceLabel(capability)} support is provisional: behavior has not been independently verified.`,
277
+ };
278
+ }
279
+ return { confidence: surface.confidence, message: null };
280
+ }