@kuznai/inception-engine 0.18.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 +72 -43
- package/dist/{config → src/config}/agents.js +174 -24
- package/dist/src/core/adapters/agent-definitions.d.ts +8 -0
- 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/index.d.ts +1 -1
- package/dist/{core → src/core}/adapters/index.js +4 -4
- package/dist/{core → src/core}/adapters/mcp.d.ts +2 -2
- package/dist/{core → src/core}/adapters/mcp.js +21 -24
- package/dist/{core → src/core}/adapters/permissions.js +16 -20
- package/dist/{core → src/core}/adapters/rules.d.ts +2 -2
- package/dist/src/core/adapters/rules.js +126 -0
- package/dist/src/core/capabilities.d.ts +47 -0
- package/dist/src/core/capabilities.js +280 -0
- package/dist/{core → src/core}/deploy.d.ts +1 -1
- package/dist/{core → src/core}/deploy.js +273 -92
- package/dist/{core → src/core}/init.js +126 -52
- 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.d.ts +2 -2
- package/dist/{core → src/core}/ownership.js +13 -0
- package/dist/{core → src/core}/preflight.d.ts +1 -1
- package/dist/src/core/preflight.js +280 -0
- package/dist/{core → src/core}/resolve.d.ts +1 -1
- package/dist/{core → src/core}/resolve.js +7 -4
- package/dist/{core → src/core}/revert.js +95 -33
- package/dist/{core → src/core}/runtime-paths.d.ts +2 -1
- package/dist/{core → src/core}/runtime-paths.js +30 -23
- package/dist/{core → src/core}/validation.d.ts +10 -1
- package/dist/{core → src/core}/validation.js +75 -0
- package/dist/src/formatters.d.ts +5 -0
- package/dist/src/formatters.js +58 -0
- package/dist/{index.js → src/index.js} +8 -24
- package/dist/src/logger.js +62 -0
- package/dist/{schemas → src/schemas}/manifest.d.ts +22 -0
- package/dist/{schemas → src/schemas}/manifest.js +19 -5
- package/dist/{schemas → src/schemas}/registry.d.ts +74 -0
- package/dist/{schemas → src/schemas}/registry.js +18 -3
- package/dist/{types.d.ts → src/types.d.ts} +60 -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.d.ts +0 -20
- package/dist/core/adapters/agent-definitions.js +0 -90
- package/dist/core/adapters/rules.js +0 -103
- package/dist/core/preflight.js +0 -98
- package/dist/logger.js +0 -61
- /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/permissions.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}/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}/revert.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/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{logger.d.ts → src/logger.d.ts} +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
|
@@ -15,7 +15,7 @@ const SAFE_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
|
15
15
|
// is valid, while "{home}/../.ssh/config" is rejected.
|
|
16
16
|
// {repo} resolves to the manifest directory at deploy time, enabling repo-local
|
|
17
17
|
// targets (e.g. Antigravity's .agents/rules/ surface).
|
|
18
|
-
const TARGET_TEMPLATE_RE = /^\{(home|appdata|xdg_config|repo)\}(?:[\\/].*)?$/;
|
|
18
|
+
const TARGET_TEMPLATE_RE = /^\{(home|appdata|xdg_config|repo|workspace)\}(?:[\\/].*)?$/;
|
|
19
19
|
// Standalone schema used for type derivation and single-ID validation (e.g. index.ts).
|
|
20
20
|
export const AgentIdSchema = z.enum(AGENT_IDS);
|
|
21
21
|
// Used inside SkillEntrySchema.agents so that enum failures embed the received
|
|
@@ -83,16 +83,25 @@ export const McpServerEntrySchema = z.object({
|
|
|
83
83
|
// Raw server descriptor passed verbatim to each agent adapter.
|
|
84
84
|
// Adapters are responsible for validating the shape they need.
|
|
85
85
|
config: z.record(z.string(), z.unknown()),
|
|
86
|
+
// Deployment scope: "global" (default) targets the agent's user-level MCP
|
|
87
|
+
// config file. "repo" and "workspace" target repo- or workspace-relative
|
|
88
|
+
// config files for agents that support them (e.g. GitHub Copilot's
|
|
89
|
+
// .vscode/mcp.json). For agents without scope-specific surfaces the
|
|
90
|
+
// adapter falls back to the global surface or emits a warning.
|
|
91
|
+
scope: z.enum(["global", "repo", "workspace"]).default("global"),
|
|
86
92
|
});
|
|
87
93
|
export const AgentRuleEntrySchema = z.object({
|
|
88
94
|
name: nameField,
|
|
89
95
|
agents: agentsField,
|
|
90
96
|
// Relative path to the rules/instruction file within the source bundle.
|
|
97
|
+
// Must be a .md or .markdown file. Structural requirements (e.g. YAML
|
|
98
|
+
// frontmatter) are validated per agent requirements by the adapter.
|
|
91
99
|
path: sourcePathField,
|
|
92
100
|
// Deployment scope: "global" targets the agent's home-directory instruction
|
|
93
101
|
// file (default), "repo" targets the project-root instruction file within the
|
|
94
|
-
// deployed repository (e.g. {repo}/CLAUDE.md for claude-code)
|
|
95
|
-
|
|
102
|
+
// deployed repository (e.g. {repo}/CLAUDE.md for claude-code), and "workspace"
|
|
103
|
+
// targets the agent's workspace-local instruction surface.
|
|
104
|
+
scope: z.enum(["global", "repo", "workspace"]).default("global"),
|
|
96
105
|
});
|
|
97
106
|
export const PermissionsEntrySchema = z.object({
|
|
98
107
|
name: nameField,
|
|
@@ -100,15 +109,20 @@ export const PermissionsEntrySchema = z.object({
|
|
|
100
109
|
// Raw permission config payload validated per agent by the permissions adapter.
|
|
101
110
|
// For claude-code: { permissions: { allow?: string[], deny?: string[] } }
|
|
102
111
|
// For codex: { approval_policy?: "auto" | "manual" | "suggest" | "on-failure" }
|
|
112
|
+
// For opencode: { permissions: { allow?: string[], ask?: string[], deny?: string[] } }
|
|
103
113
|
config: z.record(z.string(), z.unknown()),
|
|
104
114
|
});
|
|
105
115
|
export const AgentDefinitionEntrySchema = z.object({
|
|
106
116
|
name: nameField,
|
|
107
117
|
agents: agentsField,
|
|
108
118
|
// Relative path to the agent definition Markdown file within the source bundle.
|
|
109
|
-
// Must be a .md or .markdown file.
|
|
110
|
-
//
|
|
119
|
+
// Must be a .md or .markdown file. Structural requirements (e.g. YAML
|
|
120
|
+
// frontmatter) are validated per agent requirements by the adapter.
|
|
111
121
|
path: sourcePathField,
|
|
122
|
+
// Deployment scope: "global" targets the agent's home-directory definition
|
|
123
|
+
// directory (if supported), "repo" targets the project-root definition directory
|
|
124
|
+
// within the deployed repository (default).
|
|
125
|
+
scope: z.enum(["global", "repo", "workspace"]).default("repo"),
|
|
112
126
|
});
|
|
113
127
|
export const ManifestSchema = z.object({
|
|
114
128
|
skills: z.array(SkillEntrySchema).superRefine((skills, ctx) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
declare const SkillDirRegistryEntrySchema: z.ZodObject<{
|
|
3
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
4
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3
5
|
kind: z.ZodLiteral<"skill-dir">;
|
|
4
6
|
source: z.ZodString;
|
|
5
7
|
skill: z.ZodString;
|
|
@@ -18,6 +20,8 @@ declare const SkillDirRegistryEntrySchema: z.ZodObject<{
|
|
|
18
20
|
deployed: z.ZodString;
|
|
19
21
|
}, z.core.$strip>;
|
|
20
22
|
declare const FileWriteRegistryEntrySchema: z.ZodObject<{
|
|
23
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
24
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
21
25
|
kind: z.ZodLiteral<"file-write">;
|
|
22
26
|
source: z.ZodString;
|
|
23
27
|
skill: z.ZodString;
|
|
@@ -32,6 +36,8 @@ declare const FileWriteRegistryEntrySchema: z.ZodObject<{
|
|
|
32
36
|
deployed: z.ZodString;
|
|
33
37
|
}, z.core.$strip>;
|
|
34
38
|
declare const ConfigPatchRegistryEntrySchema: z.ZodObject<{
|
|
39
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
40
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
35
41
|
kind: z.ZodLiteral<"config-patch">;
|
|
36
42
|
patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
37
43
|
undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
@@ -46,7 +52,28 @@ declare const ConfigPatchRegistryEntrySchema: z.ZodObject<{
|
|
|
46
52
|
}>;
|
|
47
53
|
deployed: z.ZodString;
|
|
48
54
|
}, z.core.$strip>;
|
|
55
|
+
declare const FrontmatterEmitRegistryEntrySchema: z.ZodObject<{
|
|
56
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
57
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
58
|
+
kind: z.ZodLiteral<"frontmatter-emit">;
|
|
59
|
+
patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
60
|
+
undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
61
|
+
created: z.ZodOptional<z.ZodBoolean>;
|
|
62
|
+
hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
skill: z.ZodString;
|
|
64
|
+
agent: z.ZodEnum<{
|
|
65
|
+
"claude-code": "claude-code";
|
|
66
|
+
codex: "codex";
|
|
67
|
+
"gemini-cli": "gemini-cli";
|
|
68
|
+
antigravity: "antigravity";
|
|
69
|
+
opencode: "opencode";
|
|
70
|
+
"github-copilot": "github-copilot";
|
|
71
|
+
}>;
|
|
72
|
+
deployed: z.ZodString;
|
|
73
|
+
}, z.core.$strip>;
|
|
49
74
|
export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
75
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
76
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
50
77
|
kind: z.ZodLiteral<"skill-dir">;
|
|
51
78
|
source: z.ZodString;
|
|
52
79
|
skill: z.ZodString;
|
|
@@ -64,6 +91,8 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
64
91
|
}>>;
|
|
65
92
|
deployed: z.ZodString;
|
|
66
93
|
}, z.core.$strip>, z.ZodObject<{
|
|
94
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
95
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
67
96
|
kind: z.ZodLiteral<"file-write">;
|
|
68
97
|
source: z.ZodString;
|
|
69
98
|
skill: z.ZodString;
|
|
@@ -77,6 +106,8 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
77
106
|
}>;
|
|
78
107
|
deployed: z.ZodString;
|
|
79
108
|
}, z.core.$strip>, z.ZodObject<{
|
|
109
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
110
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
80
111
|
kind: z.ZodLiteral<"config-patch">;
|
|
81
112
|
patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
82
113
|
undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
@@ -90,10 +121,30 @@ export declare const RegistryEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
90
121
|
"github-copilot": "github-copilot";
|
|
91
122
|
}>;
|
|
92
123
|
deployed: z.ZodString;
|
|
124
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
125
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
126
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
127
|
+
kind: z.ZodLiteral<"frontmatter-emit">;
|
|
128
|
+
patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
129
|
+
undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
130
|
+
created: z.ZodOptional<z.ZodBoolean>;
|
|
131
|
+
hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
|
|
132
|
+
skill: z.ZodString;
|
|
133
|
+
agent: z.ZodEnum<{
|
|
134
|
+
"claude-code": "claude-code";
|
|
135
|
+
codex: "codex";
|
|
136
|
+
"gemini-cli": "gemini-cli";
|
|
137
|
+
antigravity: "antigravity";
|
|
138
|
+
opencode: "opencode";
|
|
139
|
+
"github-copilot": "github-copilot";
|
|
140
|
+
}>;
|
|
141
|
+
deployed: z.ZodString;
|
|
93
142
|
}, z.core.$strip>], "kind">;
|
|
94
143
|
export declare const RegistrySchema: z.ZodObject<{
|
|
95
144
|
version: z.ZodLiteral<1>;
|
|
96
145
|
deployments: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
146
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
147
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
97
148
|
kind: z.ZodLiteral<"skill-dir">;
|
|
98
149
|
source: z.ZodString;
|
|
99
150
|
skill: z.ZodString;
|
|
@@ -111,6 +162,8 @@ export declare const RegistrySchema: z.ZodObject<{
|
|
|
111
162
|
}>>;
|
|
112
163
|
deployed: z.ZodString;
|
|
113
164
|
}, z.core.$strip>, z.ZodObject<{
|
|
165
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
166
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
114
167
|
kind: z.ZodLiteral<"file-write">;
|
|
115
168
|
source: z.ZodString;
|
|
116
169
|
skill: z.ZodString;
|
|
@@ -124,6 +177,8 @@ export declare const RegistrySchema: z.ZodObject<{
|
|
|
124
177
|
}>;
|
|
125
178
|
deployed: z.ZodString;
|
|
126
179
|
}, z.core.$strip>, z.ZodObject<{
|
|
180
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
181
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
127
182
|
kind: z.ZodLiteral<"config-patch">;
|
|
128
183
|
patch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
129
184
|
undoPatch: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
@@ -137,11 +192,30 @@ export declare const RegistrySchema: z.ZodObject<{
|
|
|
137
192
|
"github-copilot": "github-copilot";
|
|
138
193
|
}>;
|
|
139
194
|
deployed: z.ZodString;
|
|
195
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
196
|
+
surfaceId: z.ZodOptional<z.ZodString>;
|
|
197
|
+
migratedFrom: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
198
|
+
kind: z.ZodLiteral<"frontmatter-emit">;
|
|
199
|
+
patch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
200
|
+
undoPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
201
|
+
created: z.ZodOptional<z.ZodBoolean>;
|
|
202
|
+
hadFrontmatter: z.ZodOptional<z.ZodBoolean>;
|
|
203
|
+
skill: z.ZodString;
|
|
204
|
+
agent: z.ZodEnum<{
|
|
205
|
+
"claude-code": "claude-code";
|
|
206
|
+
codex: "codex";
|
|
207
|
+
"gemini-cli": "gemini-cli";
|
|
208
|
+
antigravity: "antigravity";
|
|
209
|
+
opencode: "opencode";
|
|
210
|
+
"github-copilot": "github-copilot";
|
|
211
|
+
}>;
|
|
212
|
+
deployed: z.ZodString;
|
|
140
213
|
}, z.core.$strip>], "kind">>;
|
|
141
214
|
}, z.core.$strip>;
|
|
142
215
|
export type SkillDirRegistryEntry = z.infer<typeof SkillDirRegistryEntrySchema>;
|
|
143
216
|
export type FileWriteRegistryEntry = z.infer<typeof FileWriteRegistryEntrySchema>;
|
|
144
217
|
export type ConfigPatchRegistryEntry = z.infer<typeof ConfigPatchRegistryEntrySchema>;
|
|
218
|
+
export type FrontmatterEmitRegistryEntry = z.infer<typeof FrontmatterEmitRegistryEntrySchema>;
|
|
145
219
|
export type RegistryEntry = z.infer<typeof RegistryEntrySchema>;
|
|
146
220
|
export type Registry = z.infer<typeof RegistrySchema>;
|
|
147
221
|
export {};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AgentIdSchema } from "./manifest.js";
|
|
3
|
-
const
|
|
3
|
+
const RegistryOwnershipMetadataSchema = z.object({
|
|
4
|
+
surfaceId: z.string().optional(),
|
|
5
|
+
migratedFrom: z.array(z.string()).optional(),
|
|
6
|
+
});
|
|
7
|
+
const SkillDirRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
|
|
4
8
|
kind: z.literal("skill-dir"),
|
|
5
9
|
source: z.string(),
|
|
6
10
|
skill: z.string(),
|
|
@@ -8,14 +12,14 @@ const SkillDirRegistryEntrySchema = z.object({
|
|
|
8
12
|
method: z.enum(["symlink", "copy"]).optional(),
|
|
9
13
|
deployed: z.string(),
|
|
10
14
|
});
|
|
11
|
-
const FileWriteRegistryEntrySchema =
|
|
15
|
+
const FileWriteRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
|
|
12
16
|
kind: z.literal("file-write"),
|
|
13
17
|
source: z.string(),
|
|
14
18
|
skill: z.string(),
|
|
15
19
|
agent: AgentIdSchema,
|
|
16
20
|
deployed: z.string(),
|
|
17
21
|
});
|
|
18
|
-
const ConfigPatchRegistryEntrySchema =
|
|
22
|
+
const ConfigPatchRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
|
|
19
23
|
kind: z.literal("config-patch"),
|
|
20
24
|
patch: z.record(z.string(), z.unknown()),
|
|
21
25
|
undoPatch: z.record(z.string(), z.unknown()),
|
|
@@ -23,10 +27,21 @@ const ConfigPatchRegistryEntrySchema = z.object({
|
|
|
23
27
|
agent: AgentIdSchema,
|
|
24
28
|
deployed: z.string(),
|
|
25
29
|
});
|
|
30
|
+
const FrontmatterEmitRegistryEntrySchema = RegistryOwnershipMetadataSchema.extend({
|
|
31
|
+
kind: z.literal("frontmatter-emit"),
|
|
32
|
+
patch: z.record(z.string(), z.unknown()).optional(),
|
|
33
|
+
undoPatch: z.record(z.string(), z.unknown()).optional(),
|
|
34
|
+
created: z.boolean().optional(),
|
|
35
|
+
hadFrontmatter: z.boolean().optional(),
|
|
36
|
+
skill: z.string(),
|
|
37
|
+
agent: AgentIdSchema,
|
|
38
|
+
deployed: z.string(),
|
|
39
|
+
});
|
|
26
40
|
export const RegistryEntrySchema = z.discriminatedUnion("kind", [
|
|
27
41
|
SkillDirRegistryEntrySchema,
|
|
28
42
|
FileWriteRegistryEntrySchema,
|
|
29
43
|
ConfigPatchRegistryEntrySchema,
|
|
44
|
+
FrontmatterEmitRegistryEntrySchema,
|
|
30
45
|
]);
|
|
31
46
|
export const RegistrySchema = z.object({
|
|
32
47
|
version: z.literal(1),
|
|
@@ -5,8 +5,36 @@ export interface AgentPaths {
|
|
|
5
5
|
windows: string[];
|
|
6
6
|
}
|
|
7
7
|
export type Confidence = "documented" | "implementation-only" | "provisional";
|
|
8
|
+
export type CapabilityKind = "skills" | "mcpServers" | "agentRules" | "permissions" | "agentDefinitions";
|
|
8
9
|
export interface SupportedAgentSurface {
|
|
9
10
|
status: "supported";
|
|
11
|
+
/**
|
|
12
|
+
* Declares how this agent relates to the surface:
|
|
13
|
+
* - "agent-specific" (default when absent): the agent owns this surface
|
|
14
|
+
* independently and deploy emits a normal action.
|
|
15
|
+
* - "native": the agent reads this surface autonomously without any deploy
|
|
16
|
+
* action from inception-engine; no action is emitted.
|
|
17
|
+
* - "shared-via": this agent rides another agent's deployment. When the
|
|
18
|
+
* primary agent (`via`) is also in the target list, deploy skips this
|
|
19
|
+
* agent's action (the primary writes the shared file). When the primary
|
|
20
|
+
* is absent, a guidance warning is emitted instead.
|
|
21
|
+
*/
|
|
22
|
+
surfaceKind?: {
|
|
23
|
+
kind: "agent-specific";
|
|
24
|
+
} | {
|
|
25
|
+
kind: "native";
|
|
26
|
+
} | {
|
|
27
|
+
kind: "shared-via";
|
|
28
|
+
via: AgentId;
|
|
29
|
+
/**
|
|
30
|
+
* When true, this agent cannot deploy to the surface independently —
|
|
31
|
+
* the primary agent (`via`) must also be in the target list. If the
|
|
32
|
+
* primary is absent, a guidance warning is emitted and no action is
|
|
33
|
+
* generated. When false or absent, the agent can deploy to the surface
|
|
34
|
+
* on its own if the primary is not present.
|
|
35
|
+
*/
|
|
36
|
+
requiresPrimary?: boolean;
|
|
37
|
+
};
|
|
10
38
|
path: AgentPaths;
|
|
11
39
|
schemaLabel: string;
|
|
12
40
|
mcpPatchKey?: string;
|
|
@@ -50,15 +78,46 @@ export interface AgentConfig {
|
|
|
50
78
|
* (e.g. GitHub Copilot reads `.claude/skills/` directly).
|
|
51
79
|
*/
|
|
52
80
|
skills?: AgentPaths;
|
|
81
|
+
/**
|
|
82
|
+
* When `skills` is absent, this field explains why. Currently only
|
|
83
|
+
* "shared-via" is used — the agent reads skills from the `via` agent's
|
|
84
|
+
* deployment path natively and needs no separate skills deploy action.
|
|
85
|
+
*/
|
|
86
|
+
skillsSurfaceKind?: {
|
|
87
|
+
kind: "shared-via";
|
|
88
|
+
via: AgentId;
|
|
89
|
+
};
|
|
53
90
|
detectPaths: AgentPaths;
|
|
54
91
|
detectBinary: string | null;
|
|
55
92
|
provenance: AgentProvenance;
|
|
56
93
|
mcpSupport?: AgentSurfaceSupport;
|
|
94
|
+
mcpRepoSupport?: AgentSurfaceSupport;
|
|
95
|
+
mcpWorkspaceSupport?: AgentSurfaceSupport;
|
|
57
96
|
agentRulesSupport?: AgentSurfaceSupport;
|
|
58
97
|
agentRulesRepoSupport?: AgentSurfaceSupport;
|
|
98
|
+
agentRulesWorkspaceSupport?: AgentSurfaceSupport;
|
|
59
99
|
permissionsSupport?: AgentSurfaceSupport;
|
|
60
100
|
agentDefinitionsSupport?: AgentSurfaceSupport;
|
|
101
|
+
agentDefinitionsRepoSupport?: AgentSurfaceSupport;
|
|
102
|
+
agentDefinitionsWorkspaceSupport?: AgentSurfaceSupport;
|
|
103
|
+
agentDefinitionsTomlSupport?: AgentSurfaceSupport;
|
|
104
|
+
agentDefinitionsTomlRepoSupport?: AgentSurfaceSupport;
|
|
61
105
|
policyNote?: string;
|
|
106
|
+
/**
|
|
107
|
+
* A list of documented surfaces that are currently not safe to support directly.
|
|
108
|
+
* Preflight will emit warnings for these if the agent is targeted.
|
|
109
|
+
*/
|
|
110
|
+
unsupportedSurfaces?: AgentSurfaceSupport[];
|
|
111
|
+
/**
|
|
112
|
+
* When true, instruction files deployed to this agent must include valid
|
|
113
|
+
* YAML frontmatter. Drives validateInstructionFileRequirements without
|
|
114
|
+
* hardcoded agent-ID checks.
|
|
115
|
+
*/
|
|
116
|
+
instructionFrontmatterRequired?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* When true, preflight runs enterprise-policy detection for this agent.
|
|
119
|
+
*/
|
|
120
|
+
enterprisePolicyDetection?: boolean;
|
|
62
121
|
}
|
|
63
122
|
export interface PlanWarning {
|
|
64
123
|
kind: "confidence" | "collision" | "ambiguity";
|
|
@@ -80,6 +139,7 @@ export interface FileWriteDeployAction {
|
|
|
80
139
|
source: string;
|
|
81
140
|
target: string;
|
|
82
141
|
confidence?: Confidence;
|
|
142
|
+
migratedFrom?: string[];
|
|
83
143
|
}
|
|
84
144
|
export interface ConfigPatchDeployAction {
|
|
85
145
|
kind: "config-patch";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { access, mkdir } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export async function exists(p) {
|
|
5
|
+
try {
|
|
6
|
+
await access(p);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function makeTmpDir(prefix = "ie-test-dir") {
|
|
14
|
+
const dir = path.join(os.tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
15
|
+
await mkdir(dir, { recursive: true });
|
|
16
|
+
return dir;
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize path separators to forward slashes for cross-platform path assertions.
|
|
3
|
+
* Use this instead of hard-coding POSIX separators in expected strings.
|
|
4
|
+
*/
|
|
5
|
+
export declare function normalizeSlashes(value: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Assert that a path ends with the given POSIX-style suffix, normalizing separators.
|
|
8
|
+
* Use instead of: assert.ok(normalizeSlashes(p).endsWith("some/suffix"))
|
|
9
|
+
*/
|
|
10
|
+
export declare function assertPathEndsWith(actual: string, suffix: string, msg?: string): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize path separators to forward slashes for cross-platform path assertions.
|
|
4
|
+
* Use this instead of hard-coding POSIX separators in expected strings.
|
|
5
|
+
*/
|
|
6
|
+
export function normalizeSlashes(value) {
|
|
7
|
+
return value.replaceAll("\\", "/");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Assert that a path ends with the given POSIX-style suffix, normalizing separators.
|
|
11
|
+
* Use instead of: assert.ok(normalizeSlashes(p).endsWith("some/suffix"))
|
|
12
|
+
*/
|
|
13
|
+
export function assertPathEndsWith(actual, suffix, msg) {
|
|
14
|
+
assert.ok(normalizeSlashes(actual).endsWith(suffix), msg ?? `Expected path "${actual}" to end with "${suffix}"`);
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface SkillDirScenarioOptions {
|
|
2
|
+
method: "symlink" | "copy";
|
|
3
|
+
assertManagedTarget(target: string, source: string, expectedSkillMd: string): Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
export declare function registerSharedSkillDirDeployScenarios(options: SkillDirScenarioOptions): void;
|
|
6
|
+
export declare function registerSharedSkillDirRevertScenarios(options: SkillDirScenarioOptions): void;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { it } from "node:test";
|
|
5
|
+
import { executeDeploy, planDeploy } from "../../src/core/deploy.js";
|
|
6
|
+
import { lookupDeployment, registerDeployment, } from "../../src/core/ownership.js";
|
|
7
|
+
import { executeRevert, planRevert } from "../../src/core/revert.js";
|
|
8
|
+
import { exists, makeTmpDir } from "./fs.js";
|
|
9
|
+
import { createFailingRegistryPersistence, createSkillSource, testSkillManifest, } from "./skill-dir.js";
|
|
10
|
+
const FIRST_SKILL_MD = "---\nname: test\ndescription: First skill\n---\n# First";
|
|
11
|
+
const SECOND_SKILL_MD = "---\nname: test\ndescription: Second skill\n---\n# Second";
|
|
12
|
+
export function registerSharedSkillDirDeployScenarios(options) {
|
|
13
|
+
it("first deploy succeeds", async () => {
|
|
14
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
15
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
16
|
+
try {
|
|
17
|
+
const source = await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
18
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
19
|
+
const { succeeded, failed } = await executeDeploy(actions, false, false, home);
|
|
20
|
+
assert.equal(succeeded, 1);
|
|
21
|
+
assert.equal(failed.length, 0);
|
|
22
|
+
await options.assertManagedTarget(actions[0]?.target, source, FIRST_SKILL_MD);
|
|
23
|
+
const entry = await lookupDeployment(home, actions[0]?.target);
|
|
24
|
+
assert.ok(entry);
|
|
25
|
+
assert.equal(entry.kind, "skill-dir");
|
|
26
|
+
assert.equal(entry.method, options.method);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
30
|
+
await rm(home, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
it("dry-run reports the planned skill-dir change only", async () => {
|
|
34
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
35
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
36
|
+
try {
|
|
37
|
+
await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
38
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
39
|
+
const { succeeded, failed, planned } = await executeDeploy(actions, true, false, home);
|
|
40
|
+
assert.equal(succeeded, 1);
|
|
41
|
+
assert.equal(failed.length, 0);
|
|
42
|
+
assert.equal(planned.length, 1);
|
|
43
|
+
assert.equal(planned[0]?.verb, options.method === "symlink" ? "create-symlink" : "copy-dir");
|
|
44
|
+
assert.ok(!(await exists(actions[0]?.target)));
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
48
|
+
await rm(home, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it("refuses to overwrite an unmanaged target", async () => {
|
|
52
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
53
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
54
|
+
try {
|
|
55
|
+
await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
56
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
57
|
+
const target = actions[0]?.target;
|
|
58
|
+
await mkdir(target, { recursive: true });
|
|
59
|
+
await writeFile(path.join(target, "user.txt"), "user content");
|
|
60
|
+
const { succeeded, failed } = await executeDeploy(actions, false, false, home);
|
|
61
|
+
assert.equal(succeeded, 0);
|
|
62
|
+
assert.equal(failed.length, 1);
|
|
63
|
+
assert.match(failed[0]?.error, /not managed by inception-engine/);
|
|
64
|
+
assert.equal(await readFile(path.join(target, "user.txt"), "utf-8"), "user content");
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
68
|
+
await rm(home, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
it("refuses to overwrite a target with a mismatched registry entry", async () => {
|
|
72
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
73
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
74
|
+
try {
|
|
75
|
+
await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
76
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
77
|
+
const target = actions[0]?.target;
|
|
78
|
+
await mkdir(target, { recursive: true });
|
|
79
|
+
await writeFile(path.join(target, "SKILL.md"), "other");
|
|
80
|
+
await registerDeployment(home, target, {
|
|
81
|
+
kind: "skill-dir",
|
|
82
|
+
source: "/other/source",
|
|
83
|
+
skill: "other-skill",
|
|
84
|
+
agent: "codex",
|
|
85
|
+
method: options.method,
|
|
86
|
+
});
|
|
87
|
+
const { succeeded, failed } = await executeDeploy(actions, false, false, home);
|
|
88
|
+
assert.equal(succeeded, 0);
|
|
89
|
+
assert.equal(failed.length, 1);
|
|
90
|
+
assert.match(failed[0]?.error, /not managed by inception-engine/);
|
|
91
|
+
assert.equal(await readFile(path.join(target, "SKILL.md"), "utf-8"), "other");
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
95
|
+
await rm(home, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it("managed redeploy succeeds", async () => {
|
|
99
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
100
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
101
|
+
try {
|
|
102
|
+
const source = await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
103
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
104
|
+
await executeDeploy(actions, false, false, home);
|
|
105
|
+
const { succeeded, failed } = await executeDeploy(actions, false, false, home);
|
|
106
|
+
assert.equal(succeeded, 1);
|
|
107
|
+
assert.equal(failed.length, 0);
|
|
108
|
+
await options.assertManagedTarget(actions[0]?.target, source, FIRST_SKILL_MD);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
112
|
+
await rm(home, { recursive: true, force: true });
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
it("restores the prior managed target when registry persistence fails", async () => {
|
|
116
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
117
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
118
|
+
try {
|
|
119
|
+
const firstSource = await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
120
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
121
|
+
const firstAction = actions[0];
|
|
122
|
+
await executeDeploy([firstAction], false, false, home);
|
|
123
|
+
await writeFile(path.join(firstSource, "SKILL.md"), SECOND_SKILL_MD);
|
|
124
|
+
const failAction = {
|
|
125
|
+
...firstAction,
|
|
126
|
+
};
|
|
127
|
+
const { succeeded, failed } = await executeDeploy([failAction], false, false, home, {
|
|
128
|
+
registry: createFailingRegistryPersistence(),
|
|
129
|
+
});
|
|
130
|
+
assert.equal(succeeded, 0);
|
|
131
|
+
assert.equal(failed.length, 1);
|
|
132
|
+
assert.match(failed[0]?.error, /simulated registry persistence failure/);
|
|
133
|
+
await options.assertManagedTarget(firstAction.target, firstSource, FIRST_SKILL_MD);
|
|
134
|
+
assert.ok(!(await exists(`${firstAction.target}.inception-backup`)));
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
138
|
+
await rm(home, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
export function registerSharedSkillDirRevertScenarios(options) {
|
|
143
|
+
it("reverts a managed skill-dir target", async () => {
|
|
144
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
145
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
146
|
+
try {
|
|
147
|
+
await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
148
|
+
const { actions } = await planDeploy(testSkillManifest, sourceDir, ["claude-code"], home);
|
|
149
|
+
await executeDeploy(actions, false, false, home);
|
|
150
|
+
const revertActions = planRevert(testSkillManifest, ["claude-code"], home);
|
|
151
|
+
const { succeeded, skipped, failed } = await executeRevert(revertActions, false, false, home);
|
|
152
|
+
assert.equal(succeeded, 1);
|
|
153
|
+
assert.equal(skipped, 0);
|
|
154
|
+
assert.equal(failed.length, 0);
|
|
155
|
+
assert.ok(!(await exists(actions[0]?.target)));
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
159
|
+
await rm(home, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
it("skips an unmanaged skill-dir target", async () => {
|
|
163
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
164
|
+
try {
|
|
165
|
+
const revertActions = planRevert(testSkillManifest, ["claude-code"], home);
|
|
166
|
+
const target = revertActions[0]?.target;
|
|
167
|
+
await mkdir(target, { recursive: true });
|
|
168
|
+
await writeFile(path.join(target, "SKILL.md"), FIRST_SKILL_MD);
|
|
169
|
+
const { succeeded, skipped, failed } = await executeRevert(revertActions, false, false, home);
|
|
170
|
+
assert.equal(succeeded, 0);
|
|
171
|
+
assert.equal(skipped, 1);
|
|
172
|
+
assert.equal(failed.length, 0);
|
|
173
|
+
assert.ok(await exists(target));
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
await rm(home, { recursive: true, force: true });
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
it("skips a target whose registry entry belongs to a different skill", async () => {
|
|
180
|
+
const sourceDir = await makeTmpDir("ie-skill-dir-source");
|
|
181
|
+
const home = await makeTmpDir("ie-skill-dir-home");
|
|
182
|
+
try {
|
|
183
|
+
const source = await createSkillSource(sourceDir, "skills/test-skill", FIRST_SKILL_MD);
|
|
184
|
+
const revertActions = planRevert(testSkillManifest, ["claude-code"], home);
|
|
185
|
+
const target = revertActions[0]?.target;
|
|
186
|
+
await mkdir(target, { recursive: true });
|
|
187
|
+
await writeFile(path.join(target, "SKILL.md"), FIRST_SKILL_MD);
|
|
188
|
+
await registerDeployment(home, target, {
|
|
189
|
+
kind: "skill-dir",
|
|
190
|
+
source,
|
|
191
|
+
skill: "different-skill",
|
|
192
|
+
agent: "codex",
|
|
193
|
+
method: options.method,
|
|
194
|
+
});
|
|
195
|
+
const { succeeded, skipped, failed } = await executeRevert(revertActions, false, false, home);
|
|
196
|
+
assert.equal(succeeded, 0);
|
|
197
|
+
assert.equal(skipped, 1);
|
|
198
|
+
assert.equal(failed.length, 0);
|
|
199
|
+
assert.ok(await exists(target));
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
await rm(sourceDir, { recursive: true, force: true });
|
|
203
|
+
await rm(home, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RegistryPersistence } from "../../src/core/ownership.ts";
|
|
2
|
+
import type { Manifest } from "../../src/types.ts";
|
|
3
|
+
export declare function createSkillSource(baseDir: string, skillPath?: string, skillBody?: string): Promise<string>;
|
|
4
|
+
export declare const testSkillManifest: Manifest;
|
|
5
|
+
export declare function createFailingRegistryPersistence(error?: Error): RegistryPersistence;
|
|
6
|
+
export declare function assertSymlinkTarget(target: string, source: string): Promise<void>;
|
|
7
|
+
export declare function assertCopyTarget(target: string, expectedSkillMd: string): Promise<void>;
|