dryai 2.2.0 → 3.0.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 +25 -21
- package/dest/cli.d.ts +68 -0
- package/dest/cli.js +147 -0
- package/dest/commands/skills/add.d.ts +2 -2
- package/dest/commands/skills/add.js +23 -7
- package/dest/commands/skills/index.d.ts +3 -3
- package/dest/commands/skills/index.js +10 -11
- package/dest/commands/skills/list.d.ts +2 -2
- package/dest/commands/skills/list.js +4 -3
- package/dest/commands/skills/rehash-all.d.ts +2 -2
- package/dest/commands/skills/rehash-all.js +6 -5
- package/dest/commands/skills/rehash.d.ts +2 -2
- package/dest/commands/skills/rehash.js +3 -2
- package/dest/commands/skills/remove.d.ts +2 -2
- package/dest/commands/skills/remove.js +3 -2
- package/dest/commands/skills/update-all.d.ts +2 -2
- package/dest/commands/skills/update-all.js +8 -7
- package/dest/commands/skills/update.d.ts +2 -2
- package/dest/commands/skills/update.js +6 -5
- package/dest/commands/sync.d.ts +6 -0
- package/dest/commands/sync.js +8 -0
- package/dest/lib/agent-definition-helpers.d.ts +74 -0
- package/dest/lib/agent-definition-helpers.js +68 -0
- package/dest/lib/agent-definitions.d.ts +333 -0
- package/dest/lib/agent-definitions.js +301 -0
- package/dest/lib/agent-types.d.ts +46 -0
- package/dest/lib/agent-types.js +1 -0
- package/dest/lib/agents.d.ts +81 -0
- package/dest/lib/agents.js +301 -0
- package/dest/lib/command-options.d.ts +1 -1
- package/dest/lib/command-options.js +1 -1
- package/dest/lib/context.d.ts +8 -25
- package/dest/lib/context.js +8 -26
- package/dest/lib/frontmatter.d.ts +27 -70
- package/dest/lib/frontmatter.js +23 -42
- package/dest/lib/object-helpers.d.ts +5 -0
- package/dest/lib/object-helpers.js +6 -0
- package/dest/lib/skills.d.ts +17 -93
- package/dest/lib/skills.js +25 -7
- package/dest/lib/sync.d.ts +7 -0
- package/dest/lib/sync.js +503 -0
- package/dest/main.js +6 -86
- package/package.json +3 -3
- package/dest/commands/install.d.ts +0 -3
- package/dest/commands/install.js +0 -4
- package/dest/lib/install.d.ts +0 -8
- package/dest/lib/install.js +0 -380
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { AGENT_DEFINITIONS } from './agent-definitions.js';
|
|
3
|
+
import {} from './agent-types.js';
|
|
4
|
+
export { AGENT_DEFINITIONS } from './agent-definitions.js';
|
|
5
|
+
export { SYNC_ITEM_KINDS, } from './agent-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Returns whether a string is a recognized sync agent name.
|
|
8
|
+
*/
|
|
9
|
+
export function isSyncAgent(value) {
|
|
10
|
+
return Object.hasOwn(AGENT_DEFINITIONS, value);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Returns all sync agent names from the registry, in definition order.
|
|
14
|
+
*/
|
|
15
|
+
function collectSyncAgents() {
|
|
16
|
+
const agents = [];
|
|
17
|
+
for (const value in AGENT_DEFINITIONS) {
|
|
18
|
+
if (isSyncAgent(value)) {
|
|
19
|
+
agents.push(value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return agents;
|
|
23
|
+
}
|
|
24
|
+
export const SYNC_AGENTS = collectSyncAgents();
|
|
25
|
+
/**
|
|
26
|
+
* Returns the definition for the given sync agent from the central registry.
|
|
27
|
+
*/
|
|
28
|
+
function getAgentDefinition(agent) {
|
|
29
|
+
return AGENT_DEFINITIONS[agent];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns the command source definition for the given agent.
|
|
33
|
+
*/
|
|
34
|
+
function getCommandSourceDefinition(agent) {
|
|
35
|
+
return getAgentDefinition(agent).command.frontmatterSection;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns the rule source definition for the given agent.
|
|
39
|
+
*/
|
|
40
|
+
function getRuleSourceDefinition(agent) {
|
|
41
|
+
return getAgentDefinition(agent).rule.frontmatterSection;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Returns all ownership definitions registered across every agent and item kind.
|
|
45
|
+
*/
|
|
46
|
+
function listOwnershipDefinitions() {
|
|
47
|
+
return SYNC_AGENTS.flatMap((agent) => {
|
|
48
|
+
const definition = getAgentDefinition(agent);
|
|
49
|
+
return [
|
|
50
|
+
definition.command.ownershipKey,
|
|
51
|
+
definition.rule.ownershipKey,
|
|
52
|
+
definition.skill.ownershipKey,
|
|
53
|
+
];
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds the map of output root directory paths for every agent, each resolved relative to baseDir.
|
|
58
|
+
*/
|
|
59
|
+
export function createTargetRoots(baseDir) {
|
|
60
|
+
return Object.fromEntries(SYNC_AGENTS.map((agent) => [
|
|
61
|
+
agent,
|
|
62
|
+
Object.fromEntries(Object.entries(getAgentDefinition(agent).targetRoots).map(([rootName, pathSegments]) => [
|
|
63
|
+
rootName,
|
|
64
|
+
path.join(baseDir, ...pathSegments),
|
|
65
|
+
])),
|
|
66
|
+
]));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns the display label used for one agent in user-facing sync reports.
|
|
70
|
+
*/
|
|
71
|
+
export function getAgentLabel(agent) {
|
|
72
|
+
return getAgentDefinition(agent).displayLabel;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the supported agent names joined as a natural English list.
|
|
76
|
+
*/
|
|
77
|
+
export function describeSupportedAgents() {
|
|
78
|
+
return formatLabelList(SYNC_AGENTS.map(getAgentLabel));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns every output root directory path from the given TargetRoots map.
|
|
82
|
+
*/
|
|
83
|
+
export function listTargetRootPaths(targetRoots) {
|
|
84
|
+
return SYNC_AGENTS.flatMap((agent) => Object.values(targetRoots[agent]));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Builds one sync target per supported agent for the given item kind and input.
|
|
88
|
+
*/
|
|
89
|
+
export function buildSyncTargets(value) {
|
|
90
|
+
switch (value.kind) {
|
|
91
|
+
case 'command': {
|
|
92
|
+
return SYNC_AGENTS.map((agent) => getAgentDefinition(agent).command.target.buildTarget({
|
|
93
|
+
input: value.input,
|
|
94
|
+
targetRoots: value.targetRoots,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
case 'rule': {
|
|
98
|
+
return SYNC_AGENTS.map((agent) => getAgentDefinition(agent).rule.target.buildTarget({
|
|
99
|
+
input: value.input,
|
|
100
|
+
targetRoots: value.targetRoots,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
case 'skill': {
|
|
104
|
+
return SYNC_AGENTS.map((agent) => getAgentDefinition(agent).skill.target.buildTarget({
|
|
105
|
+
input: value.input,
|
|
106
|
+
targetRoots: value.targetRoots,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns the ownership key for the given agent, item kind, and input.
|
|
113
|
+
*/
|
|
114
|
+
export function createOwnershipKey(agent, kind, value) {
|
|
115
|
+
switch (kind) {
|
|
116
|
+
case 'command': {
|
|
117
|
+
return getAgentDefinition(agent).command.ownershipKey.createKeyForInput(value);
|
|
118
|
+
}
|
|
119
|
+
case 'rule': {
|
|
120
|
+
return getAgentDefinition(agent).rule.ownershipKey.createKeyForInput(value);
|
|
121
|
+
}
|
|
122
|
+
case 'skill': {
|
|
123
|
+
return getAgentDefinition(agent).skill.ownershipKey.createKeyForInput(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns whether an ownership key starts with the given prefix.
|
|
129
|
+
*/
|
|
130
|
+
function hasOwnershipKeyPrefix(ownershipKey, prefix) {
|
|
131
|
+
return ownershipKey.startsWith(prefix);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Strips the given prefix from an ownership key and returns the remainder.
|
|
135
|
+
*/
|
|
136
|
+
function stripOwnershipKeyPrefix(ownershipKey, prefix) {
|
|
137
|
+
return ownershipKey.slice(prefix.length);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Formats an ownership key as a human-readable phrase for use in warning messages.
|
|
141
|
+
*/
|
|
142
|
+
export function describeOwnershipKey(ownershipKey) {
|
|
143
|
+
for (const definition of listOwnershipDefinitions()) {
|
|
144
|
+
if (hasOwnershipKeyPrefix(ownershipKey, definition.prefix)) {
|
|
145
|
+
return `${definition.descriptionLabel} "${stripOwnershipKeyPrefix(ownershipKey, definition.prefix)}"`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return `output namespace "${ownershipKey}"`;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Formats a list of strings as a natural English enumeration (e.g. "a, b, and c").
|
|
152
|
+
*/
|
|
153
|
+
function formatLabelList(values) {
|
|
154
|
+
if (values.length === 0) {
|
|
155
|
+
return '';
|
|
156
|
+
}
|
|
157
|
+
if (values.length === 1) {
|
|
158
|
+
return values[0];
|
|
159
|
+
}
|
|
160
|
+
if (values.length === 2) {
|
|
161
|
+
return `${values[0]} and ${values[1]}`;
|
|
162
|
+
}
|
|
163
|
+
return `${values.slice(0, -1).join(', ')}, and ${values.at(-1)}`;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Serializes validation errors as dot-qualified field paths paired with messages, joined by semicolons.
|
|
167
|
+
*/
|
|
168
|
+
function formatValidationIssues(input) {
|
|
169
|
+
return input.issues
|
|
170
|
+
.map((issue) => {
|
|
171
|
+
const fieldPath = issue.path.length > 0
|
|
172
|
+
? `${input.pathPrefix}.${issue.path.join('.')}`
|
|
173
|
+
: input.pathPrefix;
|
|
174
|
+
return `${fieldPath}: ${issue.message}`;
|
|
175
|
+
})
|
|
176
|
+
.join('; ');
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Reads the per-agent blocks from parsed frontmatter and returns a map of agent → raw section value.
|
|
180
|
+
*/
|
|
181
|
+
function collectAgentSectionValues(runtime, input) {
|
|
182
|
+
const sectionValues = new Map();
|
|
183
|
+
if (!input.sections) {
|
|
184
|
+
return sectionValues;
|
|
185
|
+
}
|
|
186
|
+
const unknownAgents = [];
|
|
187
|
+
for (const [agent, value] of Object.entries(input.sections)) {
|
|
188
|
+
if (isSyncAgent(agent)) {
|
|
189
|
+
sectionValues.set(agent, value);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
unknownAgents.push(agent);
|
|
193
|
+
}
|
|
194
|
+
if (unknownAgents.length > 0) {
|
|
195
|
+
runtime.logInfo(`Skipping invalid ${input.kind} frontmatter in ${input.filePath}: ${unknownAgents
|
|
196
|
+
.map((agent) => `agents.${agent}: Unsupported agent`)
|
|
197
|
+
.join('; ')}`);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
return sectionValues;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Validates each per-agent frontmatter block and merges the results into the base command sync input. Returns null if any block is invalid.
|
|
204
|
+
*/
|
|
205
|
+
function extendCommandSyncInputFromAgentSections(runtime, input) {
|
|
206
|
+
const sectionValues = collectAgentSectionValues(runtime, {
|
|
207
|
+
filePath: input.filePath,
|
|
208
|
+
kind: 'command',
|
|
209
|
+
sections: input.sections,
|
|
210
|
+
});
|
|
211
|
+
if (!sectionValues) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
let currentInput = input.currentInput;
|
|
215
|
+
for (const agent of SYNC_AGENTS) {
|
|
216
|
+
const sourceDefinition = getCommandSourceDefinition(agent);
|
|
217
|
+
const result = sourceDefinition.createSyncInputExtension(sectionValues.get(agent), {
|
|
218
|
+
currentInput,
|
|
219
|
+
sectionValues,
|
|
220
|
+
});
|
|
221
|
+
if (!result.success) {
|
|
222
|
+
runtime.logInfo(`Skipping invalid command frontmatter in ${input.filePath}: ${formatValidationIssues({
|
|
223
|
+
issues: result.issues,
|
|
224
|
+
pathPrefix: `agents.${agent}`,
|
|
225
|
+
})}`);
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
currentInput = {
|
|
229
|
+
...currentInput,
|
|
230
|
+
...result.data,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return currentInput;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Validates each per-agent frontmatter block and merges the results into the base rule sync input. Returns null if any block is invalid.
|
|
237
|
+
*/
|
|
238
|
+
function extendRuleSyncInputFromAgentSections(runtime, input) {
|
|
239
|
+
const sectionValues = collectAgentSectionValues(runtime, {
|
|
240
|
+
filePath: input.filePath,
|
|
241
|
+
kind: 'rule',
|
|
242
|
+
sections: input.sections,
|
|
243
|
+
});
|
|
244
|
+
if (!sectionValues) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
let currentInput = input.currentInput;
|
|
248
|
+
for (const agent of SYNC_AGENTS) {
|
|
249
|
+
const sourceDefinition = getRuleSourceDefinition(agent);
|
|
250
|
+
const result = sourceDefinition.createSyncInputExtension(sectionValues.get(agent), {
|
|
251
|
+
currentInput,
|
|
252
|
+
sectionValues,
|
|
253
|
+
});
|
|
254
|
+
if (!result.success) {
|
|
255
|
+
runtime.logInfo(`Skipping invalid rule frontmatter in ${input.filePath}: ${formatValidationIssues({
|
|
256
|
+
issues: result.issues,
|
|
257
|
+
pathPrefix: `agents.${agent}`,
|
|
258
|
+
})}`);
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
currentInput = {
|
|
262
|
+
...currentInput,
|
|
263
|
+
...result.data,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return currentInput;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Builds a CommandSyncSource from parsed command frontmatter. Returns null if any per-agent section fails validation.
|
|
270
|
+
*/
|
|
271
|
+
export function createAgentCmdSyncSpec(runtime, input) {
|
|
272
|
+
return extendCommandSyncInputFromAgentSections(runtime, {
|
|
273
|
+
filePath: input.filePath,
|
|
274
|
+
currentInput: {
|
|
275
|
+
name: input.frontmatter.name,
|
|
276
|
+
description: input.frontmatter.description,
|
|
277
|
+
sourceFileStem: input.sourceFileStem,
|
|
278
|
+
body: input.body,
|
|
279
|
+
disableModelInvocation: undefined,
|
|
280
|
+
},
|
|
281
|
+
sections: input.frontmatter.agents,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Builds a RuleSyncSource from parsed rule frontmatter. Returns null if any per-agent section fails validation.
|
|
286
|
+
*/
|
|
287
|
+
export function createAgentRuleSyncSpec(runtime, input) {
|
|
288
|
+
return extendRuleSyncInputFromAgentSections(runtime, {
|
|
289
|
+
filePath: input.filePath,
|
|
290
|
+
currentInput: {
|
|
291
|
+
name: input.sourceFileStem,
|
|
292
|
+
description: input.frontmatter.description,
|
|
293
|
+
sourceFileStem: input.sourceFileStem,
|
|
294
|
+
body: input.body,
|
|
295
|
+
applyTo: '',
|
|
296
|
+
globs: undefined,
|
|
297
|
+
alwaysApply: false,
|
|
298
|
+
},
|
|
299
|
+
sections: input.frontmatter.agents,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const nonEmptyOptionStringSchema: z.ZodString;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Returns a Commander option parser function that validates the raw string value with the given Zod schema.
|
|
5
5
|
*/
|
|
6
6
|
export declare function parseOptionValue<TSchema extends z.ZodTypeAny>({ schema, optionLabel, }: {
|
|
7
7
|
schema: TSchema;
|
|
@@ -18,7 +18,7 @@ function parseWithSchema({ schema, value, label, }) {
|
|
|
18
18
|
throw new InvalidArgumentError(`${label}: ${issues}`);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Returns a Commander option parser function that validates the raw string value with the given Zod schema.
|
|
22
22
|
*/
|
|
23
23
|
export function parseOptionValue({ schema, optionLabel, }) {
|
|
24
24
|
return (value) => parseWithSchema({ schema, value, label: optionLabel });
|
package/dest/lib/context.d.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
copilotPrompts: string;
|
|
3
|
-
copilotInstructions: string;
|
|
4
|
-
copilotSkills: string;
|
|
5
|
-
cursorRules: string;
|
|
6
|
-
cursorSkills: string;
|
|
7
|
-
};
|
|
1
|
+
import { type TargetRoots } from './agents.js';
|
|
8
2
|
export type SourceRoots = {
|
|
9
3
|
commands: string;
|
|
10
4
|
rules: string;
|
|
@@ -14,27 +8,18 @@ export type AgentsContext = {
|
|
|
14
8
|
inputRoot: string;
|
|
15
9
|
outputRoot: string;
|
|
16
10
|
skillsLockfilePath: string;
|
|
11
|
+
syncManifestPath: string;
|
|
17
12
|
sourceRoots: SourceRoots;
|
|
18
13
|
targetRoots: TargetRoots;
|
|
19
14
|
};
|
|
20
15
|
export declare const DEFAULT_INPUT_ROOT_SEGMENTS: readonly [".config", "dryai"];
|
|
21
16
|
export declare const DEFAULT_TEST_OUTPUT_DIR_NAME = "output-test";
|
|
17
|
+
export declare const DEFAULT_SYNC_MANIFEST_FILE_NAME = "sync-manifest.json";
|
|
22
18
|
export declare const DEFAULT_SOURCE_ROOT_NAMES: {
|
|
23
19
|
readonly commands: "commands";
|
|
24
20
|
readonly rules: "rules";
|
|
25
21
|
readonly skills: "skills";
|
|
26
22
|
};
|
|
27
|
-
export declare const DEFAULT_TARGET_ROOT_SEGMENTS: {
|
|
28
|
-
readonly copilotPrompts: readonly [".copilot", "prompts"];
|
|
29
|
-
readonly copilotInstructions: readonly [".copilot", "instructions"];
|
|
30
|
-
readonly copilotSkills: readonly [".copilot", "skills"];
|
|
31
|
-
readonly cursorRules: readonly [".cursor", "rules"];
|
|
32
|
-
readonly cursorSkills: readonly [".cursor", "skills"];
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Creates the Copilot and Cursor output root paths under one base directory.
|
|
36
|
-
*/
|
|
37
|
-
export declare function createTargetRoots(baseDir: string): TargetRoots;
|
|
38
23
|
/**
|
|
39
24
|
* Creates the commands, rules, and skills input roots under one base directory.
|
|
40
25
|
*/
|
|
@@ -44,33 +29,31 @@ export declare function createSourceRoots(baseDir: string): SourceRoots;
|
|
|
44
29
|
*/
|
|
45
30
|
export declare function expandHomePath(inputPath: string, homeDir: string): string;
|
|
46
31
|
/**
|
|
47
|
-
* Returns the
|
|
32
|
+
* Returns the explicit output root if --output-root or --test was passed, or undefined if neither was set.
|
|
48
33
|
*/
|
|
49
34
|
export declare function resolveRequestedOutputRoot(input: {
|
|
50
35
|
test: boolean;
|
|
51
36
|
outputRoot?: string;
|
|
52
37
|
}): string | undefined;
|
|
53
38
|
/**
|
|
54
|
-
* Returns the
|
|
39
|
+
* Returns the --config-root value if provided, or undefined.
|
|
55
40
|
*/
|
|
56
41
|
export declare function resolveRequestedConfigRoot(input: {
|
|
57
42
|
configRoot?: string;
|
|
58
43
|
}): string | undefined;
|
|
59
44
|
/**
|
|
60
|
-
*
|
|
45
|
+
* Resolves the absolute output root path, expanding ~ and defaulting to homeDir when no override is given.
|
|
61
46
|
*/
|
|
62
47
|
export declare function resolveOutputRoot(input: {
|
|
63
48
|
homeDir: string;
|
|
64
49
|
outputRoot?: string;
|
|
65
50
|
}): string;
|
|
66
51
|
/**
|
|
67
|
-
* Returns a copy of
|
|
68
|
-
* explicit output root.
|
|
52
|
+
* Returns a shallow copy of context with outputRoot and targetRoots updated to the given path.
|
|
69
53
|
*/
|
|
70
54
|
export declare function resolveOutputContext(context: AgentsContext, outputRoot: string): AgentsContext;
|
|
71
55
|
/**
|
|
72
|
-
*
|
|
73
|
-
* resolved.
|
|
56
|
+
* Builds the AgentsContext by resolving input and output roots, applying ~ expansion and test-mode defaults.
|
|
74
57
|
*/
|
|
75
58
|
export declare function createAgentsContext(options?: {
|
|
76
59
|
inputRoot?: string;
|
package/dest/lib/context.js
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { createTargetRoots } from './agents.js';
|
|
3
4
|
export const DEFAULT_INPUT_ROOT_SEGMENTS = ['.config', 'dryai'];
|
|
4
5
|
export const DEFAULT_TEST_OUTPUT_DIR_NAME = 'output-test';
|
|
6
|
+
export const DEFAULT_SYNC_MANIFEST_FILE_NAME = 'sync-manifest.json';
|
|
5
7
|
export const DEFAULT_SOURCE_ROOT_NAMES = {
|
|
6
8
|
commands: 'commands',
|
|
7
9
|
rules: 'rules',
|
|
8
10
|
skills: 'skills',
|
|
9
11
|
};
|
|
10
|
-
export const DEFAULT_TARGET_ROOT_SEGMENTS = {
|
|
11
|
-
copilotPrompts: ['.copilot', 'prompts'],
|
|
12
|
-
copilotInstructions: ['.copilot', 'instructions'],
|
|
13
|
-
copilotSkills: ['.copilot', 'skills'],
|
|
14
|
-
cursorRules: ['.cursor', 'rules'],
|
|
15
|
-
cursorSkills: ['.cursor', 'skills'],
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Creates the Copilot and Cursor output root paths under one base directory.
|
|
19
|
-
*/
|
|
20
|
-
export function createTargetRoots(baseDir) {
|
|
21
|
-
return {
|
|
22
|
-
copilotPrompts: path.join(baseDir, ...DEFAULT_TARGET_ROOT_SEGMENTS.copilotPrompts),
|
|
23
|
-
copilotInstructions: path.join(baseDir, ...DEFAULT_TARGET_ROOT_SEGMENTS.copilotInstructions),
|
|
24
|
-
copilotSkills: path.join(baseDir, ...DEFAULT_TARGET_ROOT_SEGMENTS.copilotSkills),
|
|
25
|
-
cursorRules: path.join(baseDir, ...DEFAULT_TARGET_ROOT_SEGMENTS.cursorRules),
|
|
26
|
-
cursorSkills: path.join(baseDir, ...DEFAULT_TARGET_ROOT_SEGMENTS.cursorSkills),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
12
|
/**
|
|
30
13
|
* Creates the commands, rules, and skills input roots under one base directory.
|
|
31
14
|
*/
|
|
@@ -49,7 +32,7 @@ export function expandHomePath(inputPath, homeDir) {
|
|
|
49
32
|
return inputPath;
|
|
50
33
|
}
|
|
51
34
|
/**
|
|
52
|
-
* Returns the
|
|
35
|
+
* Returns the explicit output root if --output-root or --test was passed, or undefined if neither was set.
|
|
53
36
|
*/
|
|
54
37
|
export function resolveRequestedOutputRoot(input) {
|
|
55
38
|
if (input.outputRoot) {
|
|
@@ -58,13 +41,13 @@ export function resolveRequestedOutputRoot(input) {
|
|
|
58
41
|
return input.test ? `./${DEFAULT_TEST_OUTPUT_DIR_NAME}` : undefined;
|
|
59
42
|
}
|
|
60
43
|
/**
|
|
61
|
-
* Returns the
|
|
44
|
+
* Returns the --config-root value if provided, or undefined.
|
|
62
45
|
*/
|
|
63
46
|
export function resolveRequestedConfigRoot(input) {
|
|
64
47
|
return input.configRoot;
|
|
65
48
|
}
|
|
66
49
|
/**
|
|
67
|
-
*
|
|
50
|
+
* Resolves the absolute output root path, expanding ~ and defaulting to homeDir when no override is given.
|
|
68
51
|
*/
|
|
69
52
|
export function resolveOutputRoot(input) {
|
|
70
53
|
if (input.outputRoot) {
|
|
@@ -73,8 +56,7 @@ export function resolveOutputRoot(input) {
|
|
|
73
56
|
return input.homeDir;
|
|
74
57
|
}
|
|
75
58
|
/**
|
|
76
|
-
* Returns a copy of
|
|
77
|
-
* explicit output root.
|
|
59
|
+
* Returns a shallow copy of context with outputRoot and targetRoots updated to the given path.
|
|
78
60
|
*/
|
|
79
61
|
export function resolveOutputContext(context, outputRoot) {
|
|
80
62
|
return {
|
|
@@ -84,8 +66,7 @@ export function resolveOutputContext(context, outputRoot) {
|
|
|
84
66
|
};
|
|
85
67
|
}
|
|
86
68
|
/**
|
|
87
|
-
*
|
|
88
|
-
* resolved.
|
|
69
|
+
* Builds the AgentsContext by resolving input and output roots, applying ~ expansion and test-mode defaults.
|
|
89
70
|
*/
|
|
90
71
|
export function createAgentsContext(options) {
|
|
91
72
|
const homeDir = os.homedir();
|
|
@@ -104,6 +85,7 @@ export function createAgentsContext(options) {
|
|
|
104
85
|
inputRoot,
|
|
105
86
|
outputRoot,
|
|
106
87
|
skillsLockfilePath: path.join(inputRoot, 'skills.lock.json'),
|
|
88
|
+
syncManifestPath: path.join(inputRoot, DEFAULT_SYNC_MANIFEST_FILE_NAME),
|
|
107
89
|
sourceRoots: createSourceRoots(inputRoot),
|
|
108
90
|
targetRoots: createTargetRoots(outputRoot),
|
|
109
91
|
};
|
|
@@ -1,72 +1,37 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import type { CLIRuntime } from '../cli.js';
|
|
3
|
+
export { compactObject } from './object-helpers.js';
|
|
2
4
|
export declare const nonEmptyStringSchema: z.ZodString;
|
|
5
|
+
export declare const agentFrontmatterSectionSchema: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
|
|
6
|
+
export declare const agentFrontmatterSectionsSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>;
|
|
7
|
+
/**
|
|
8
|
+
* Builds the Zod schema for the `agents:` frontmatter section by combining each agent's per-kind source schema from the registry.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createAgentFrontmatterSectionsSchema(kind: 'command' | 'rule'): z.ZodOptional<z.ZodObject<{
|
|
11
|
+
[x: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
12
|
+
}, z.core.$catchall<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>>;
|
|
13
|
+
export declare const commandAgentFrontmatterSectionsSchema: z.ZodOptional<z.ZodObject<{
|
|
14
|
+
[x: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
15
|
+
}, z.core.$catchall<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>>;
|
|
16
|
+
export declare const ruleAgentFrontmatterSectionsSchema: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
[x: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
18
|
+
}, z.core.$catchall<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>>;
|
|
3
19
|
export declare const commandFrontmatterSchema: z.ZodObject<{
|
|
4
20
|
name: z.ZodString;
|
|
5
21
|
description: z.ZodString;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
}, {
|
|
11
|
-
'disable-model-invocation'?: boolean | undefined;
|
|
12
|
-
}>>;
|
|
13
|
-
}, "strict", z.ZodTypeAny, {
|
|
14
|
-
name: string;
|
|
15
|
-
description: string;
|
|
16
|
-
cursor?: {
|
|
17
|
-
'disable-model-invocation'?: boolean | undefined;
|
|
18
|
-
} | undefined;
|
|
19
|
-
}, {
|
|
20
|
-
name: string;
|
|
21
|
-
description: string;
|
|
22
|
-
cursor?: {
|
|
23
|
-
'disable-model-invocation'?: boolean | undefined;
|
|
24
|
-
} | undefined;
|
|
25
|
-
}>;
|
|
22
|
+
agents: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
[x: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
24
|
+
}, z.core.$catchall<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>>;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
26
|
export declare const ruleFrontmatterSchema: z.ZodObject<{
|
|
27
27
|
description: z.ZodString;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
applyTo: string;
|
|
34
|
-
}>;
|
|
35
|
-
cursor: z.ZodOptional<z.ZodObject<{
|
|
36
|
-
alwaysApply: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
-
globs: z.ZodOptional<z.ZodString>;
|
|
38
|
-
}, "strict", z.ZodTypeAny, {
|
|
39
|
-
alwaysApply?: boolean | undefined;
|
|
40
|
-
globs?: string | undefined;
|
|
41
|
-
}, {
|
|
42
|
-
alwaysApply?: boolean | undefined;
|
|
43
|
-
globs?: string | undefined;
|
|
44
|
-
}>>;
|
|
45
|
-
}, "strict", z.ZodTypeAny, {
|
|
46
|
-
description: string;
|
|
47
|
-
copilot: {
|
|
48
|
-
applyTo: string;
|
|
49
|
-
};
|
|
50
|
-
cursor?: {
|
|
51
|
-
alwaysApply?: boolean | undefined;
|
|
52
|
-
globs?: string | undefined;
|
|
53
|
-
} | undefined;
|
|
54
|
-
}, {
|
|
55
|
-
description: string;
|
|
56
|
-
copilot: {
|
|
57
|
-
applyTo: string;
|
|
58
|
-
};
|
|
59
|
-
cursor?: {
|
|
60
|
-
alwaysApply?: boolean | undefined;
|
|
61
|
-
globs?: string | undefined;
|
|
62
|
-
} | undefined;
|
|
63
|
-
}>;
|
|
28
|
+
agents: z.ZodOptional<z.ZodObject<{
|
|
29
|
+
[x: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
30
|
+
}, z.core.$catchall<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>>>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
export type AgentFrontmatterSections = z.infer<typeof agentFrontmatterSectionsSchema>;
|
|
64
33
|
export type CommandFrontmatter = z.infer<typeof commandFrontmatterSchema>;
|
|
65
34
|
export type RuleFrontmatter = z.infer<typeof ruleFrontmatterSchema>;
|
|
66
|
-
/**
|
|
67
|
-
* Returns a copy of an object with all undefined-valued entries removed.
|
|
68
|
-
*/
|
|
69
|
-
export declare function compactObject(value: Record<string, unknown>): Record<string, unknown>;
|
|
70
35
|
/**
|
|
71
36
|
* Returns whether a value is a non-null plain object and not an array.
|
|
72
37
|
*/
|
|
@@ -81,21 +46,13 @@ export declare function parseFrontmatter(fileContent: string): {
|
|
|
81
46
|
/**
|
|
82
47
|
* Validates parsed frontmatter against a schema and logs a skip message when validation fails.
|
|
83
48
|
*/
|
|
84
|
-
export declare function validateFrontmatter<T>({ filePath, metadata, schema, }: {
|
|
49
|
+
export declare function validateFrontmatter<T>(runtime: CLIRuntime, { filePath, metadata, schema, }: {
|
|
85
50
|
filePath: string;
|
|
86
51
|
metadata: Record<string, unknown>;
|
|
87
52
|
schema: z.ZodType<T>;
|
|
88
53
|
}): T | null;
|
|
89
54
|
/**
|
|
90
|
-
*
|
|
91
|
-
*/
|
|
92
|
-
export declare function normalizeRuleMetadata(metadata: RuleFrontmatter): {
|
|
93
|
-
alwaysApply: boolean;
|
|
94
|
-
globs: string | undefined;
|
|
95
|
-
applyTo: string;
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* Renders metadata and markdown body content back into a frontmatter document string.
|
|
55
|
+
* Serializes metadata as YAML frontmatter and combines it with the markdown body into a single document string.
|
|
99
56
|
*/
|
|
100
57
|
export declare function renderMarkdown({ metadata, body, }: {
|
|
101
58
|
metadata: Record<string, unknown>;
|