agentloom 0.1.0 → 0.1.1
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 +91 -72
- package/bin/cli.mjs +3 -2
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +149 -17
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.js +122 -31
- package/dist/commands/agent.d.ts +2 -0
- package/dist/commands/agent.js +85 -0
- package/dist/commands/command.d.ts +2 -0
- package/dist/commands/command.js +98 -0
- package/dist/commands/delete.d.ts +9 -0
- package/dist/commands/delete.js +444 -0
- package/dist/commands/entity-utils.d.ts +13 -0
- package/dist/commands/entity-utils.js +58 -0
- package/dist/commands/find.d.ts +21 -0
- package/dist/commands/find.js +944 -0
- package/dist/commands/mcp.js +133 -55
- package/dist/commands/skills.d.ts +2 -1
- package/dist/commands/skills.js +105 -9
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.js +12 -10
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.js +286 -21
- package/dist/core/argv.d.ts +2 -1
- package/dist/core/argv.js +42 -2
- package/dist/core/commands.d.ts +13 -0
- package/dist/core/commands.js +65 -0
- package/dist/core/copy.d.ts +6 -0
- package/dist/core/copy.js +126 -65
- package/dist/core/importer.d.ts +28 -1
- package/dist/core/importer.js +1104 -41
- package/dist/core/lockfile.js +86 -3
- package/dist/core/manage-agents-bootstrap.d.ts +10 -0
- package/dist/core/manage-agents-bootstrap.js +40 -0
- package/dist/core/manifest.js +7 -1
- package/dist/core/router.d.ts +16 -0
- package/dist/core/router.js +66 -0
- package/dist/core/scope.d.ts +1 -1
- package/dist/core/scope.js +12 -8
- package/dist/core/settings.d.ts +4 -3
- package/dist/core/settings.js +10 -8
- package/dist/core/skills.d.ts +23 -0
- package/dist/core/skills.js +328 -0
- package/dist/core/sources.d.ts +3 -1
- package/dist/core/sources.js +31 -1
- package/dist/core/telemetry.d.ts +26 -0
- package/dist/core/telemetry.js +124 -0
- package/dist/sync/index.d.ts +7 -1
- package/dist/sync/index.js +395 -131
- package/dist/types.d.ts +16 -1
- package/package.json +5 -4
package/dist/commands/update.js
CHANGED
|
@@ -1,30 +1,69 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { parseProvidersFlag } from "../core/argv.js";
|
|
1
3
|
import { importSource, NonInteractiveConflictError } from "../core/importer.js";
|
|
4
|
+
import { normalizeCommandSelector, stripCommandFileExtension, } from "../core/commands.js";
|
|
2
5
|
import { readLockfile } from "../core/lockfile.js";
|
|
3
|
-
import {
|
|
4
|
-
import { prepareSource } from "../core/sources.js";
|
|
5
|
-
import { parseProvidersFlag } from "../core/argv.js";
|
|
6
|
+
import { prepareSource, parseSourceSpec } from "../core/sources.js";
|
|
6
7
|
import { getUpdateHelpText } from "../core/copy.js";
|
|
7
|
-
import {
|
|
8
|
+
import { resolveProvidersForSync } from "../sync/index.js";
|
|
9
|
+
import { getNonInteractiveMode, resolvePathsForCommand, runPostMutationSync, } from "./entity-utils.js";
|
|
8
10
|
export async function runUpdateCommand(argv, cwd) {
|
|
9
11
|
if (argv.help) {
|
|
10
12
|
console.log(getUpdateHelpText());
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
await runEntityAwareUpdate({
|
|
16
|
+
argv,
|
|
15
17
|
cwd,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
target: "all",
|
|
19
|
+
sourceIndex: 1,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export async function runScopedUpdateCommand(options) {
|
|
23
|
+
await runEntityAwareUpdate({
|
|
24
|
+
argv: options.argv,
|
|
25
|
+
cwd: options.cwd,
|
|
26
|
+
target: options.entity,
|
|
27
|
+
sourceIndex: options.sourceIndex,
|
|
19
28
|
});
|
|
29
|
+
}
|
|
30
|
+
async function runEntityAwareUpdate(options) {
|
|
31
|
+
const nonInteractive = getNonInteractiveMode(options.argv);
|
|
32
|
+
const paths = await resolvePathsForCommand(options.argv, options.cwd);
|
|
33
|
+
const explicitProviders = parseProvidersFlag(options.argv.providers);
|
|
34
|
+
let resolvedSkillProviders;
|
|
35
|
+
const resolveProvidersForSkills = async () => {
|
|
36
|
+
if (explicitProviders && explicitProviders.length > 0) {
|
|
37
|
+
return explicitProviders;
|
|
38
|
+
}
|
|
39
|
+
if (resolvedSkillProviders && resolvedSkillProviders.length > 0) {
|
|
40
|
+
return resolvedSkillProviders;
|
|
41
|
+
}
|
|
42
|
+
resolvedSkillProviders = await resolveProvidersForSync({
|
|
43
|
+
paths,
|
|
44
|
+
explicitProviders,
|
|
45
|
+
nonInteractive,
|
|
46
|
+
});
|
|
47
|
+
return resolvedSkillProviders;
|
|
48
|
+
};
|
|
20
49
|
const lockfile = readLockfile(paths);
|
|
21
50
|
if (lockfile.entries.length === 0) {
|
|
22
51
|
console.log(`No lock entries found in ${paths.lockPath}.`);
|
|
23
52
|
return;
|
|
24
53
|
}
|
|
54
|
+
const sourceFilter = resolveSourceFilter(options.argv, options.sourceIndex);
|
|
55
|
+
const entries = lockfile.entries.filter((entry) => matchesSourceFilter(entry, sourceFilter));
|
|
56
|
+
if (entries.length === 0) {
|
|
57
|
+
console.log("No lock entries matched the requested source filter.");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
25
60
|
let updated = 0;
|
|
26
61
|
let skipped = 0;
|
|
27
|
-
for (const entry of
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
if (!entryIncludesTarget(entry, options.target)) {
|
|
64
|
+
skipped += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
28
67
|
const probe = prepareSource({
|
|
29
68
|
source: entry.source,
|
|
30
69
|
ref: entry.requestedRef,
|
|
@@ -36,15 +75,58 @@ export async function runUpdateCommand(argv, cwd) {
|
|
|
36
75
|
skipped += 1;
|
|
37
76
|
continue;
|
|
38
77
|
}
|
|
78
|
+
const updatePlan = buildEntryUpdatePlan(entry, options.target);
|
|
79
|
+
if (!updatePlan.importAgents &&
|
|
80
|
+
!updatePlan.importCommands &&
|
|
81
|
+
!updatePlan.importMcp &&
|
|
82
|
+
!updatePlan.importSkills) {
|
|
83
|
+
skipped += 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
39
86
|
try {
|
|
40
|
-
|
|
87
|
+
const importOptions = {
|
|
41
88
|
source: entry.source,
|
|
42
89
|
ref: entry.requestedRef,
|
|
43
90
|
subdir: entry.subdir,
|
|
44
|
-
|
|
91
|
+
agents: updatePlan.requestedAgents,
|
|
92
|
+
promptForAgentSelection: false,
|
|
93
|
+
promptForCommands: false,
|
|
94
|
+
promptForMcp: false,
|
|
95
|
+
promptForSkills: false,
|
|
96
|
+
yes: Boolean(options.argv.yes),
|
|
45
97
|
nonInteractive,
|
|
46
98
|
paths,
|
|
47
|
-
|
|
99
|
+
importAgents: updatePlan.importAgents,
|
|
100
|
+
requireAgents: updatePlan.importAgents,
|
|
101
|
+
importCommands: updatePlan.importCommands,
|
|
102
|
+
importMcp: updatePlan.importMcp,
|
|
103
|
+
};
|
|
104
|
+
if (updatePlan.importSkills) {
|
|
105
|
+
importOptions.importSkills = true;
|
|
106
|
+
if (explicitProviders && explicitProviders.length > 0) {
|
|
107
|
+
importOptions.skillsProviders = explicitProviders;
|
|
108
|
+
}
|
|
109
|
+
else if (updatePlan.skillsProviders) {
|
|
110
|
+
importOptions.skillsProviders = updatePlan.skillsProviders;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
importOptions.resolveSkillsProviders = resolveProvidersForSkills;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (updatePlan.commandSelectors) {
|
|
117
|
+
importOptions.commandSelectors = updatePlan.commandSelectors;
|
|
118
|
+
importOptions.commandRenameMap = updatePlan.commandRenameMap;
|
|
119
|
+
}
|
|
120
|
+
if (updatePlan.mcpSelectors) {
|
|
121
|
+
importOptions.mcpSelectors = updatePlan.mcpSelectors;
|
|
122
|
+
}
|
|
123
|
+
if (updatePlan.skillSelectors) {
|
|
124
|
+
importOptions.skillSelectors = updatePlan.skillSelectors;
|
|
125
|
+
}
|
|
126
|
+
if (updatePlan.skillRenameMap) {
|
|
127
|
+
importOptions.skillRenameMap = updatePlan.skillRenameMap;
|
|
128
|
+
}
|
|
129
|
+
await importSource(importOptions);
|
|
48
130
|
updated += 1;
|
|
49
131
|
}
|
|
50
132
|
catch (err) {
|
|
@@ -57,15 +139,198 @@ export async function runUpdateCommand(argv, cwd) {
|
|
|
57
139
|
}
|
|
58
140
|
console.log(`Updated entries: ${updated}`);
|
|
59
141
|
console.log(`Unchanged entries: ${skipped}`);
|
|
60
|
-
if (updated > 0
|
|
61
|
-
|
|
142
|
+
if (updated > 0) {
|
|
143
|
+
await runPostMutationSync({
|
|
144
|
+
argv: options.argv,
|
|
62
145
|
paths,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
nonInteractive,
|
|
66
|
-
dryRun: Boolean(argv["dry-run"]),
|
|
146
|
+
target: options.target,
|
|
147
|
+
providers: explicitProviders ?? resolvedSkillProviders,
|
|
67
148
|
});
|
|
68
|
-
console.log("");
|
|
69
|
-
console.log(formatSyncSummary(syncSummary, paths.agentsRoot));
|
|
70
149
|
}
|
|
71
150
|
}
|
|
151
|
+
function buildEntryUpdatePlan(entry, target) {
|
|
152
|
+
const includeAgents = shouldUpdateEntity(entry, "agent", target);
|
|
153
|
+
const includeCommands = shouldUpdateEntity(entry, "command", target);
|
|
154
|
+
const includeMcp = shouldUpdateEntity(entry, "mcp", target);
|
|
155
|
+
const includeSkills = shouldUpdateEntity(entry, "skill", target);
|
|
156
|
+
const commandOptions = getUpdateCommandOptions(entry, includeCommands);
|
|
157
|
+
const mcpOptions = getUpdateMcpOptions(entry, includeMcp);
|
|
158
|
+
const skillOptions = getUpdateSkillOptions(entry, includeSkills);
|
|
159
|
+
return {
|
|
160
|
+
importAgents: includeAgents,
|
|
161
|
+
importCommands: commandOptions.importCommands,
|
|
162
|
+
importMcp: mcpOptions.importMcp,
|
|
163
|
+
importSkills: skillOptions.importSkills,
|
|
164
|
+
requestedAgents: includeAgents ? entry.requestedAgents : undefined,
|
|
165
|
+
commandSelectors: commandOptions.commandSelectors,
|
|
166
|
+
commandRenameMap: commandOptions.commandRenameMap,
|
|
167
|
+
mcpSelectors: mcpOptions.mcpSelectors,
|
|
168
|
+
skillSelectors: skillOptions.skillSelectors,
|
|
169
|
+
skillsProviders: skillOptions.skillsProviders,
|
|
170
|
+
skillRenameMap: skillOptions.skillRenameMap,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function resolveSourceFilter(argv, sourceIndex) {
|
|
174
|
+
const sourceFromFlag = typeof argv.source === "string" && argv.source.trim().length > 0
|
|
175
|
+
? argv.source.trim()
|
|
176
|
+
: undefined;
|
|
177
|
+
if (sourceFromFlag)
|
|
178
|
+
return sourceFromFlag;
|
|
179
|
+
const sourceFromArg = argv._[sourceIndex];
|
|
180
|
+
if (typeof sourceFromArg !== "string" || sourceFromArg.trim().length === 0) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
return sourceFromArg.trim();
|
|
184
|
+
}
|
|
185
|
+
function matchesSourceFilter(entry, filter) {
|
|
186
|
+
if (!filter)
|
|
187
|
+
return true;
|
|
188
|
+
if (entry.source === filter)
|
|
189
|
+
return true;
|
|
190
|
+
try {
|
|
191
|
+
const parsed = parseSourceSpec(filter);
|
|
192
|
+
return entry.source === parsed.source;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function entryIncludesTarget(entry, target) {
|
|
199
|
+
if (target === "all")
|
|
200
|
+
return true;
|
|
201
|
+
return tracksEntity(entry, target);
|
|
202
|
+
}
|
|
203
|
+
function shouldUpdateEntity(entry, entity, target) {
|
|
204
|
+
if (target !== "all" && target !== entity)
|
|
205
|
+
return false;
|
|
206
|
+
if (target === "all" && !entry.trackedEntities) {
|
|
207
|
+
if (entity === "skill") {
|
|
208
|
+
return tracksEntity(entry, entity);
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
return tracksEntity(entry, entity);
|
|
213
|
+
}
|
|
214
|
+
function tracksEntity(entry, entity) {
|
|
215
|
+
const importedAgents = Array.isArray(entry.importedAgents)
|
|
216
|
+
? entry.importedAgents
|
|
217
|
+
: [];
|
|
218
|
+
const importedCommands = Array.isArray(entry.importedCommands)
|
|
219
|
+
? entry.importedCommands
|
|
220
|
+
: [];
|
|
221
|
+
const importedMcpServers = Array.isArray(entry.importedMcpServers)
|
|
222
|
+
? entry.importedMcpServers
|
|
223
|
+
: [];
|
|
224
|
+
const importedSkills = Array.isArray(entry.importedSkills)
|
|
225
|
+
? entry.importedSkills
|
|
226
|
+
: [];
|
|
227
|
+
if (entry.trackedEntities?.includes(entity))
|
|
228
|
+
return true;
|
|
229
|
+
if (entity === "agent") {
|
|
230
|
+
return importedAgents.length > 0 || Boolean(entry.requestedAgents);
|
|
231
|
+
}
|
|
232
|
+
if (entity === "command") {
|
|
233
|
+
return (importedCommands.length > 0 ||
|
|
234
|
+
Boolean(entry.selectedSourceCommands) ||
|
|
235
|
+
Boolean(entry.commandRenameMap));
|
|
236
|
+
}
|
|
237
|
+
if (entity === "mcp") {
|
|
238
|
+
return (importedMcpServers.length > 0 || Boolean(entry.selectedSourceMcpServers));
|
|
239
|
+
}
|
|
240
|
+
return (importedSkills.length > 0 ||
|
|
241
|
+
Boolean(entry.selectedSourceSkills) ||
|
|
242
|
+
Boolean(entry.skillsProviders) ||
|
|
243
|
+
Boolean(entry.skillRenameMap));
|
|
244
|
+
}
|
|
245
|
+
function getUpdateCommandOptions(entry, includeCommands) {
|
|
246
|
+
if (!includeCommands) {
|
|
247
|
+
return { importCommands: false };
|
|
248
|
+
}
|
|
249
|
+
const commandSelectors = getUpdateCommandSelectors(entry);
|
|
250
|
+
if (commandSelectors && commandSelectors.length === 0) {
|
|
251
|
+
return { importCommands: false };
|
|
252
|
+
}
|
|
253
|
+
if (!commandSelectors) {
|
|
254
|
+
return { importCommands: true };
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
importCommands: true,
|
|
258
|
+
commandSelectors,
|
|
259
|
+
commandRenameMap: getUpdateCommandRenameMap(entry, commandSelectors),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function getUpdateMcpOptions(entry, includeMcp) {
|
|
263
|
+
if (!includeMcp) {
|
|
264
|
+
return { importMcp: false };
|
|
265
|
+
}
|
|
266
|
+
if (Array.isArray(entry.selectedSourceMcpServers) &&
|
|
267
|
+
entry.selectedSourceMcpServers.length === 0) {
|
|
268
|
+
return { importMcp: false };
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
importMcp: true,
|
|
272
|
+
mcpSelectors: entry.selectedSourceMcpServers,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function getUpdateSkillOptions(entry, includeSkills) {
|
|
276
|
+
if (!includeSkills) {
|
|
277
|
+
return { importSkills: false };
|
|
278
|
+
}
|
|
279
|
+
if (Array.isArray(entry.selectedSourceSkills) &&
|
|
280
|
+
entry.selectedSourceSkills.length === 0) {
|
|
281
|
+
return { importSkills: false };
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
importSkills: true,
|
|
285
|
+
skillSelectors: entry.selectedSourceSkills,
|
|
286
|
+
skillsProviders: entry.skillsProviders,
|
|
287
|
+
skillRenameMap: entry.skillRenameMap,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function getUpdateCommandSelectors(entry) {
|
|
291
|
+
if (entry.selectedSourceCommands !== undefined) {
|
|
292
|
+
return entry.selectedSourceCommands;
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
function getUpdateCommandRenameMap(entry, commandSelectors) {
|
|
297
|
+
const renameMapFromLock = filterRenameMapBySelectors(entry.commandRenameMap, commandSelectors);
|
|
298
|
+
if (renameMapFromLock) {
|
|
299
|
+
return renameMapFromLock;
|
|
300
|
+
}
|
|
301
|
+
const inferredRename = inferUpdateCommandRename(entry, commandSelectors);
|
|
302
|
+
if (!inferredRename)
|
|
303
|
+
return undefined;
|
|
304
|
+
return {
|
|
305
|
+
[commandSelectors[0]]: inferredRename,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function inferUpdateCommandRename(entry, commandSelectors) {
|
|
309
|
+
if (!commandSelectors || commandSelectors.length !== 1) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
if (entry.importedCommands.length !== 1) {
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
const sourceName = stripCommandFileExtension(commandSelectors[0]);
|
|
316
|
+
const importedName = stripCommandFileExtension(path.basename(entry.importedCommands[0]));
|
|
317
|
+
if (!sourceName || !importedName || sourceName === importedName) {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
return importedName;
|
|
321
|
+
}
|
|
322
|
+
function filterRenameMapBySelectors(renameMap, selectors) {
|
|
323
|
+
if (!renameMap)
|
|
324
|
+
return undefined;
|
|
325
|
+
const selectorSet = new Set(selectors.map(normalizeCommandSelector));
|
|
326
|
+
const filteredEntries = Object.entries(renameMap)
|
|
327
|
+
.filter(([sourceSelector]) => selectorSet.has(normalizeCommandSelector(sourceSelector)))
|
|
328
|
+
.map(([sourceSelector, importedFileName]) => [
|
|
329
|
+
sourceSelector,
|
|
330
|
+
path.basename(importedFileName),
|
|
331
|
+
]);
|
|
332
|
+
if (filteredEntries.length === 0) {
|
|
333
|
+
return undefined;
|
|
334
|
+
}
|
|
335
|
+
return Object.fromEntries(filteredEntries);
|
|
336
|
+
}
|
package/dist/core/argv.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ParsedArgs } from "minimist";
|
|
2
|
-
import type { Provider } from "../types.js";
|
|
2
|
+
import type { Provider, SelectionMode } from "../types.js";
|
|
3
3
|
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
4
4
|
export declare function parseProvidersFlag(input: unknown): Provider[] | undefined;
|
|
5
|
+
export declare function parseSelectionModeFlag(input: unknown): SelectionMode | undefined;
|
|
5
6
|
export declare function getStringArrayFlag(value: unknown, fallback?: string[]): string[];
|
package/dist/core/argv.js
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import minimist from "minimist";
|
|
2
2
|
export function parseArgs(argv) {
|
|
3
|
-
|
|
3
|
+
const parsed = minimist(argv, {
|
|
4
4
|
boolean: ["global", "local", "yes", "no-sync", "dry-run", "json", "help"],
|
|
5
|
-
string: [
|
|
5
|
+
string: [
|
|
6
|
+
"ref",
|
|
7
|
+
"subdir",
|
|
8
|
+
"providers",
|
|
9
|
+
"rename",
|
|
10
|
+
"agent",
|
|
11
|
+
"agents",
|
|
12
|
+
"command",
|
|
13
|
+
"commands",
|
|
14
|
+
"mcp",
|
|
15
|
+
"mcps",
|
|
16
|
+
"skill",
|
|
17
|
+
"skills",
|
|
18
|
+
"url",
|
|
19
|
+
"arg",
|
|
20
|
+
"env",
|
|
21
|
+
"source",
|
|
22
|
+
"name",
|
|
23
|
+
"entity",
|
|
24
|
+
"selection-mode",
|
|
25
|
+
],
|
|
6
26
|
alias: {
|
|
7
27
|
g: "global",
|
|
8
28
|
l: "local",
|
|
@@ -11,6 +31,14 @@ export function parseArgs(argv) {
|
|
|
11
31
|
},
|
|
12
32
|
"--": true,
|
|
13
33
|
});
|
|
34
|
+
const syncFlag = parsed.sync;
|
|
35
|
+
if (syncFlag === false ||
|
|
36
|
+
syncFlag === "false" ||
|
|
37
|
+
syncFlag === 0 ||
|
|
38
|
+
syncFlag === "0") {
|
|
39
|
+
parsed["no-sync"] = true;
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
14
42
|
}
|
|
15
43
|
export function parseProvidersFlag(input) {
|
|
16
44
|
if (typeof input !== "string" || input.trim() === "")
|
|
@@ -35,6 +63,18 @@ export function parseProvidersFlag(input) {
|
|
|
35
63
|
}
|
|
36
64
|
return [...new Set(validProviders)];
|
|
37
65
|
}
|
|
66
|
+
export function parseSelectionModeFlag(input) {
|
|
67
|
+
if (typeof input !== "string" || input.trim() === "")
|
|
68
|
+
return undefined;
|
|
69
|
+
const normalized = input.trim().toLowerCase();
|
|
70
|
+
if (normalized === "all" || normalized === "sync-all") {
|
|
71
|
+
return "all";
|
|
72
|
+
}
|
|
73
|
+
if (normalized === "custom") {
|
|
74
|
+
return "custom";
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`Unknown selection mode: ${normalized}. Expected one of: all, sync-all, custom.`);
|
|
77
|
+
}
|
|
38
78
|
export function getStringArrayFlag(value, fallback = []) {
|
|
39
79
|
if (Array.isArray(value)) {
|
|
40
80
|
return value
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CanonicalCommandFile {
|
|
2
|
+
fileName: string;
|
|
3
|
+
sourcePath: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function parseCommandsDir(commandsDir: string): CanonicalCommandFile[];
|
|
7
|
+
export declare function stripCommandFileExtension(fileName: string): string;
|
|
8
|
+
export declare function commandFileMatchesSelector(fileName: string, selector: string): boolean;
|
|
9
|
+
export declare function normalizeCommandSelector(selector: string): string;
|
|
10
|
+
export declare function resolveCommandSelections(commands: CanonicalCommandFile[], selectors: string[]): {
|
|
11
|
+
selected: CanonicalCommandFile[];
|
|
12
|
+
unmatched: string[];
|
|
13
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { listMarkdownFiles, slugify } from "./fs.js";
|
|
4
|
+
export function parseCommandsDir(commandsDir) {
|
|
5
|
+
if (!fs.existsSync(commandsDir))
|
|
6
|
+
return [];
|
|
7
|
+
return listMarkdownFiles(commandsDir)
|
|
8
|
+
.sort((a, b) => a.localeCompare(b))
|
|
9
|
+
.map((sourcePath) => ({
|
|
10
|
+
fileName: path.basename(sourcePath),
|
|
11
|
+
sourcePath,
|
|
12
|
+
content: fs.readFileSync(sourcePath, "utf8"),
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
export function stripCommandFileExtension(fileName) {
|
|
16
|
+
const lower = fileName.toLowerCase();
|
|
17
|
+
if (lower.endsWith(".prompt.md")) {
|
|
18
|
+
return fileName.slice(0, -".prompt.md".length);
|
|
19
|
+
}
|
|
20
|
+
const ext = path.extname(fileName);
|
|
21
|
+
if (!ext)
|
|
22
|
+
return fileName;
|
|
23
|
+
return fileName.slice(0, -ext.length);
|
|
24
|
+
}
|
|
25
|
+
export function commandFileMatchesSelector(fileName, selector) {
|
|
26
|
+
const raw = selector.trim().toLowerCase();
|
|
27
|
+
if (!raw)
|
|
28
|
+
return false;
|
|
29
|
+
const normalizedSelector = normalizeCommandSelector(raw);
|
|
30
|
+
const normalizedFileName = fileName.toLowerCase();
|
|
31
|
+
const withoutExt = stripCommandFileExtension(normalizedFileName);
|
|
32
|
+
if (normalizedFileName === raw || normalizedFileName === normalizedSelector) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (withoutExt === raw || withoutExt === normalizedSelector) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (slugify(withoutExt) === normalizedSelector ||
|
|
39
|
+
slugify(withoutExt) === slugify(normalizedSelector)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
export function normalizeCommandSelector(selector) {
|
|
45
|
+
const trimmed = selector.trim().replace(/^\/+/, "");
|
|
46
|
+
return stripCommandFileExtension(trimmed).toLowerCase();
|
|
47
|
+
}
|
|
48
|
+
export function resolveCommandSelections(commands, selectors) {
|
|
49
|
+
const uniqueSelected = new Map();
|
|
50
|
+
const unmatched = [];
|
|
51
|
+
for (const selector of selectors) {
|
|
52
|
+
const matches = commands.filter((command) => commandFileMatchesSelector(command.fileName, selector));
|
|
53
|
+
if (matches.length === 0) {
|
|
54
|
+
unmatched.push(selector);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const match of matches) {
|
|
58
|
+
uniqueSelected.set(match.fileName, match);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
selected: [...uniqueSelected.values()],
|
|
63
|
+
unmatched,
|
|
64
|
+
};
|
|
65
|
+
}
|
package/dist/core/copy.d.ts
CHANGED
|
@@ -4,10 +4,16 @@ type UsageErrorInput = {
|
|
|
4
4
|
example?: string;
|
|
5
5
|
};
|
|
6
6
|
export declare function getRootHelpText(): string;
|
|
7
|
+
export declare function getFindHelpText(): string;
|
|
7
8
|
export declare function getAddHelpText(): string;
|
|
8
9
|
export declare function getUpdateHelpText(): string;
|
|
9
10
|
export declare function getSyncHelpText(): string;
|
|
11
|
+
export declare function getCommandHelpText(): string;
|
|
12
|
+
export declare function getCommandAddHelpText(): string;
|
|
13
|
+
export declare function getCommandListHelpText(): string;
|
|
14
|
+
export declare function getCommandDeleteHelpText(): string;
|
|
10
15
|
export declare function getMcpHelpText(): string;
|
|
16
|
+
export declare function getMcpServerHelpText(): string;
|
|
11
17
|
export declare function getMcpAddHelpText(): string;
|
|
12
18
|
export declare function getMcpListHelpText(): string;
|
|
13
19
|
export declare function getMcpDeleteHelpText(): string;
|