cyber-agentkit 1.0.0 → 1.1.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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cli.js +680 -65
- package/dist/commands.d.ts +7 -1
- package/dist/commands.js +469 -48
- package/dist/index.d.ts +28 -15
- package/dist/index.js +31 -18
- package/dist/{reference-where-BhymfNgA.js → reference-where-C84J6MsR.js} +3839 -3649
- package/dist/{resolve-reference-Cis-Ye6T.d.ts → resolve-reference-D62VJZc0.d.ts} +17 -3
- package/package.json +1 -1
- package/plugin.json +3 -2
- package/skills/asset/README.md +14 -0
- package/skills/asset/SKILL.md +52 -0
- package/skills/asset/scripts/asset.mjs +199 -0
- package/skills/reference/README.md +1 -1
- package/skills/reference/SKILL.md +3 -3
- package/skills/reference/scripts/reference.mjs +56 -56
package/dist/commands.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { dirname, join, resolve, sep } from "node:path";
|
|
1
|
+
import { A as skillName, C as repositoryRoot, M as require_dist, R as pluginManifestName, S as referenceLayers, _ as parseDocument, a as interfaceLookup, c as readExtends, d as parseReferenceName, f as fitsName, g as isMergeOperation, h as hasBody, i as checkResolved, m as frontmatterPattern, n as referenceImplementations, o as listReferences, p as dataExtensions, r as checkReferences, s as searchReferences, t as whereReference, u as resolveReference, v as parseSections, w as userReferencesDir, x as projectReferencesDir, y as canonical } from "./reference-where-C84J6MsR.js";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, extname, join, resolve, sep } from "node:path";
|
|
5
5
|
import { command, exitCodes, t } from "clibuilder";
|
|
6
6
|
import { CliError, document, encode, isCliError, printAnswer, result } from "clibuilder/axi";
|
|
7
7
|
//#region src/command-output/collapse-home.ts
|
|
@@ -286,12 +286,20 @@ function selectContribution(layers, args, options = {}) {
|
|
|
286
286
|
after: resolveReference(name, layers, options)
|
|
287
287
|
};
|
|
288
288
|
}
|
|
289
|
+
/** The data files that can answer a name in a folder. */
|
|
290
|
+
function dataFiles(dir, name) {
|
|
291
|
+
return dataExtensions.map(({ extension }) => join(dir, `${name}${extension}`));
|
|
292
|
+
}
|
|
289
293
|
function deleteContribution(layers, args, options = {}) {
|
|
290
294
|
const name = bareName(args.name);
|
|
291
295
|
const target = writeTarget(name, args);
|
|
292
296
|
const shown = options.display ?? ((path) => path);
|
|
293
297
|
const before = resolveReference(name, layers, options);
|
|
294
|
-
const path = (target.scope === "project" || target.scope === "user" ? [
|
|
298
|
+
const path = (target.scope === "project" || target.scope === "user" ? [
|
|
299
|
+
target.path,
|
|
300
|
+
join(target.dir, name.name, "README.md"),
|
|
301
|
+
...dataFiles(target.dir, name.name)
|
|
302
|
+
] : [target.path]).find((candidate) => candidate !== options.without && existsSync(candidate));
|
|
295
303
|
if (!path) throw new ReferenceWriteError("no-file", `${shown(target.path)} does not exist, so there is no ${target.scope} contribution of "${name.name}" to delete. ${describeAnswer(before, options.display)} An installed plugin's, a managed, or an installed skill's contribution is never deleted.`);
|
|
296
304
|
const steps = readExtends(parseDocument(tryRead(path) ?? "", () => {}).metadata["extends"], () => {});
|
|
297
305
|
const dryRun = Boolean(args.dryRun);
|
|
@@ -316,7 +324,7 @@ function deleteContribution(layers, args, options = {}) {
|
|
|
316
324
|
}
|
|
317
325
|
//#endregion
|
|
318
326
|
//#region src/references/reference.command.ts
|
|
319
|
-
const rootOption = {
|
|
327
|
+
const rootOption$1 = {
|
|
320
328
|
description: "Directory the project tier is read from, and each folder above it up to the repository root; a project write goes to its `.agents/references/`. Defaults to the current directory.",
|
|
321
329
|
type: t.string().optional()
|
|
322
330
|
};
|
|
@@ -328,14 +336,15 @@ const defaultOption = {
|
|
|
328
336
|
description: "The calling skill's folder: its `references/<name>.default.md` joins as the `default` tier.",
|
|
329
337
|
type: t.string().optional()
|
|
330
338
|
};
|
|
331
|
-
function layerSource(plugin) {
|
|
339
|
+
function layerSource(plugin, folder = "references") {
|
|
332
340
|
return (args, home) => referenceLayers({
|
|
333
341
|
root: args.root ?? process.cwd(),
|
|
334
342
|
home,
|
|
335
343
|
platform: process.platform,
|
|
336
344
|
env: process.env,
|
|
337
345
|
plugin,
|
|
338
|
-
defaultSkill: args.default
|
|
346
|
+
defaultSkill: args.default,
|
|
347
|
+
folder
|
|
339
348
|
});
|
|
340
349
|
}
|
|
341
350
|
/** A field with nothing to say is left out: `undefined`, an empty string, or an empty list. */
|
|
@@ -343,7 +352,7 @@ function compact(value) {
|
|
|
343
352
|
return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== void 0 && field !== "" && !(Array.isArray(field) && !field.length)));
|
|
344
353
|
}
|
|
345
354
|
/** stderr, not stdout: an agent parses stdout. Rethrows what the cli already reports. */
|
|
346
|
-
function fail(error, fallback) {
|
|
355
|
+
function fail$1(error, fallback) {
|
|
347
356
|
if (isCliError(error)) throw error;
|
|
348
357
|
if (error instanceof ReferenceWriteError) {
|
|
349
358
|
process.stderr.write(`error: ${error.code}: ${error.message}\n`);
|
|
@@ -352,7 +361,7 @@ function fail(error, fallback) {
|
|
|
352
361
|
process.stderr.write(`error: ${error instanceof Error ? error.message : fallback}\n`);
|
|
353
362
|
throw CliError.reported(exitCodes.error);
|
|
354
363
|
}
|
|
355
|
-
function usage(message) {
|
|
364
|
+
function usage$1(message) {
|
|
356
365
|
process.stderr.write(`error: usage: ${message}\n`);
|
|
357
366
|
throw CliError.reported(exitCodes.usage);
|
|
358
367
|
}
|
|
@@ -408,11 +417,12 @@ function errorText(entry) {
|
|
|
408
417
|
return `${entry.name}: ${entry.message}${options}`;
|
|
409
418
|
}
|
|
410
419
|
function showEntry(resolved, home, { metadata, trace }) {
|
|
411
|
-
if (resolved.status === "found" && !resolved.warnings.length && !metadata && !trace) return resolved.content;
|
|
420
|
+
if (resolved.status === "found" && !resolved.warnings.length && !metadata && !trace && resolved.format === "markdown") return resolved.content;
|
|
412
421
|
return compact({
|
|
413
422
|
name: resolved.name,
|
|
414
423
|
status: resolved.status,
|
|
415
424
|
content: resolved.content,
|
|
425
|
+
format: resolved.format === "markdown" ? void 0 : resolved.format,
|
|
416
426
|
code: resolved.code,
|
|
417
427
|
options: resolved.options,
|
|
418
428
|
metadata: metadata ? resolved.metadata : void 0,
|
|
@@ -433,9 +443,9 @@ function showText(resolved) {
|
|
|
433
443
|
const blocks = resolved.map((entry) => entry.content === void 0 ? `<reference name="${entry.name}" status="${entry.status}" />` : `<reference name="${entry.name}">\n${entry.content}</reference>`);
|
|
434
444
|
return document(blocks.join("\n\n"));
|
|
435
445
|
}
|
|
436
|
-
function showCommand(layersFor) {
|
|
446
|
+
function showCommand$1(layersFor, name = "show") {
|
|
437
447
|
return command({
|
|
438
|
-
name
|
|
448
|
+
name,
|
|
439
449
|
description: "Print one or more references, each composed from its contributions as their extends and merge declare.",
|
|
440
450
|
arguments: [{
|
|
441
451
|
name: "names",
|
|
@@ -443,7 +453,7 @@ function showCommand(layersFor) {
|
|
|
443
453
|
type: t.array(t.string())
|
|
444
454
|
}],
|
|
445
455
|
options: {
|
|
446
|
-
root: rootOption,
|
|
456
|
+
root: rootOption$1,
|
|
447
457
|
default: defaultOption,
|
|
448
458
|
metadata: {
|
|
449
459
|
description: "Make every entry a record with its status and composed frontmatter.",
|
|
@@ -453,7 +463,7 @@ function showCommand(layersFor) {
|
|
|
453
463
|
},
|
|
454
464
|
async run(args) {
|
|
455
465
|
const format = this.format;
|
|
456
|
-
if (!args.names.length) usage("name at least one reference.");
|
|
466
|
+
if (!args.names.length) usage$1("name at least one reference.");
|
|
457
467
|
try {
|
|
458
468
|
const home = homedir();
|
|
459
469
|
const layers = await layersFor(args, home);
|
|
@@ -488,14 +498,14 @@ function showCommand(layersFor) {
|
|
|
488
498
|
const answer = result(resolved.map((entry) => showEntry(entry, home, flags)), { render: bareArray });
|
|
489
499
|
return ok ? answer : answerThenFail(answer, format);
|
|
490
500
|
} catch (error) {
|
|
491
|
-
return fail(error, "Reference lookup failed.");
|
|
501
|
+
return fail$1(error, "Reference lookup failed.");
|
|
492
502
|
}
|
|
493
503
|
}
|
|
494
504
|
});
|
|
495
505
|
}
|
|
496
|
-
function listCommand(layersFor) {
|
|
506
|
+
function listCommand$1(layersFor, name = "list") {
|
|
497
507
|
return command({
|
|
498
|
-
name
|
|
508
|
+
name,
|
|
499
509
|
description: "List every reference name, one row each, with its description, and its status when not found. A pattern keeps only the names it matches exactly.",
|
|
500
510
|
arguments: [{
|
|
501
511
|
name: "pattern",
|
|
@@ -503,7 +513,7 @@ function listCommand(layersFor) {
|
|
|
503
513
|
type: t.string().optional()
|
|
504
514
|
}],
|
|
505
515
|
options: {
|
|
506
|
-
root: rootOption,
|
|
516
|
+
root: rootOption$1,
|
|
507
517
|
trace: {
|
|
508
518
|
...traceOption,
|
|
509
519
|
description: "Add one row per name per layer holding it, with its outcome."
|
|
@@ -521,6 +531,7 @@ function listCommand(layersFor) {
|
|
|
521
531
|
references: listing.references.length ? listing.references.map((row) => compact({
|
|
522
532
|
name: row.name,
|
|
523
533
|
description: row.description,
|
|
534
|
+
format: row.format,
|
|
524
535
|
status: row.status === "found" ? void 0 : row.status,
|
|
525
536
|
options: row.options
|
|
526
537
|
})) : args.pattern ? `0 references match "${args.pattern}"` : "0 references — no layer holds one",
|
|
@@ -533,7 +544,7 @@ function listCommand(layersFor) {
|
|
|
533
544
|
if (listing.warnings.length) report.warnings = listing.warnings;
|
|
534
545
|
return result(report);
|
|
535
546
|
} catch (error) {
|
|
536
|
-
return fail(error, "Reference listing failed.");
|
|
547
|
+
return fail$1(error, "Reference listing failed.");
|
|
537
548
|
}
|
|
538
549
|
}
|
|
539
550
|
});
|
|
@@ -548,7 +559,7 @@ function searchCommand(layersFor) {
|
|
|
548
559
|
type: t.string()
|
|
549
560
|
}],
|
|
550
561
|
options: {
|
|
551
|
-
root: rootOption,
|
|
562
|
+
root: rootOption$1,
|
|
552
563
|
trace: {
|
|
553
564
|
...traceOption,
|
|
554
565
|
description: "Add the tier and plugin or skill of each match."
|
|
@@ -556,7 +567,7 @@ function searchCommand(layersFor) {
|
|
|
556
567
|
},
|
|
557
568
|
async run(args) {
|
|
558
569
|
const query = args.query.trim();
|
|
559
|
-
if (!query) usage("search needs a query.");
|
|
570
|
+
if (!query) usage$1("search needs a query.");
|
|
560
571
|
try {
|
|
561
572
|
const home = homedir();
|
|
562
573
|
const { matches, defaults } = searchReferences(query, await layersFor(args, home), { display: (path) => collapseHome(home, path) });
|
|
@@ -579,14 +590,14 @@ function searchCommand(layersFor) {
|
|
|
579
590
|
});
|
|
580
591
|
return result(report);
|
|
581
592
|
} catch (error) {
|
|
582
|
-
return fail(error, "Reference search failed.");
|
|
593
|
+
return fail$1(error, "Reference search failed.");
|
|
583
594
|
}
|
|
584
595
|
}
|
|
585
596
|
});
|
|
586
597
|
}
|
|
587
|
-
function whereCommand(layersFor) {
|
|
598
|
+
function whereCommand(layersFor, assets = false, name = "where") {
|
|
588
599
|
return command({
|
|
589
|
-
name
|
|
600
|
+
name,
|
|
590
601
|
description: "Give the project and user files a customization or a selection of a reference is written to, who each reaches, and the heading paths of the document below each.",
|
|
591
602
|
arguments: [{
|
|
592
603
|
name: "name",
|
|
@@ -594,7 +605,7 @@ function whereCommand(layersFor) {
|
|
|
594
605
|
type: t.string()
|
|
595
606
|
}],
|
|
596
607
|
options: {
|
|
597
|
-
root: rootOption,
|
|
608
|
+
root: rootOption$1,
|
|
598
609
|
default: defaultOption,
|
|
599
610
|
trace: {
|
|
600
611
|
...traceOption,
|
|
@@ -608,7 +619,8 @@ function whereCommand(layersFor) {
|
|
|
608
619
|
const display = (path) => collapseHome(home, path);
|
|
609
620
|
const report = whereReference(args.name, await layersFor(args, home), {
|
|
610
621
|
root: resolve(args.root ?? process.cwd()),
|
|
611
|
-
display
|
|
622
|
+
display,
|
|
623
|
+
assets
|
|
612
624
|
});
|
|
613
625
|
const output = compact({
|
|
614
626
|
name: report.name,
|
|
@@ -627,7 +639,7 @@ function whereCommand(layersFor) {
|
|
|
627
639
|
process.stderr.write(`error: reference-invalid: ${parseReferenceName(args.name).invalid}\n`);
|
|
628
640
|
return answerThenFail(answer, format);
|
|
629
641
|
} catch (error) {
|
|
630
|
-
return fail(error, "Reference placement lookup failed.");
|
|
642
|
+
return fail$1(error, "Reference placement lookup failed.");
|
|
631
643
|
}
|
|
632
644
|
}
|
|
633
645
|
});
|
|
@@ -635,7 +647,7 @@ function whereCommand(layersFor) {
|
|
|
635
647
|
function parseAccept(value) {
|
|
636
648
|
if (value === void 0) return void 0;
|
|
637
649
|
const versions = value.split(",").map((part) => part.trim());
|
|
638
|
-
if (!versions.length || versions.some((part) => !/^[1-9]\d*$/.test(part))) usage(`--accept is a comma-separated list of versions, such as 1,2; got "${value}".`);
|
|
650
|
+
if (!versions.length || versions.some((part) => !/^[1-9]\d*$/.test(part))) usage$1(`--accept is a comma-separated list of versions, such as 1,2; got "${value}".`);
|
|
639
651
|
return versions.map(Number);
|
|
640
652
|
}
|
|
641
653
|
function implementationsCommand(layersFor) {
|
|
@@ -648,7 +660,7 @@ function implementationsCommand(layersFor) {
|
|
|
648
660
|
type: t.string()
|
|
649
661
|
}],
|
|
650
662
|
options: {
|
|
651
|
-
root: rootOption,
|
|
663
|
+
root: rootOption$1,
|
|
652
664
|
accept: {
|
|
653
665
|
description: "Versions the consumer knows, comma-separated, such as 1,2. Defaults to the interface's `versions`.",
|
|
654
666
|
type: t.string().optional()
|
|
@@ -688,7 +700,7 @@ function implementationsCommand(layersFor) {
|
|
|
688
700
|
}));
|
|
689
701
|
return result(report);
|
|
690
702
|
} catch (error) {
|
|
691
|
-
return fail(error, "Implementation lookup failed.");
|
|
703
|
+
return fail$1(error, "Implementation lookup failed.");
|
|
692
704
|
}
|
|
693
705
|
}
|
|
694
706
|
});
|
|
@@ -703,7 +715,7 @@ function checkCommand(layersFor) {
|
|
|
703
715
|
type: t.array(t.string()).optional()
|
|
704
716
|
}],
|
|
705
717
|
options: {
|
|
706
|
-
root: rootOption,
|
|
718
|
+
root: rootOption$1,
|
|
707
719
|
trace: {
|
|
708
720
|
...traceOption,
|
|
709
721
|
description: "Add every entry checked, with its kind and unsupported sections."
|
|
@@ -743,7 +755,7 @@ function checkCommand(layersFor) {
|
|
|
743
755
|
if (format === "text") process.stderr.write(`error: interface-check: ${failing.length} of ${entries.length} references fail their check.\n`);
|
|
744
756
|
return answerThenFail(answer, format);
|
|
745
757
|
} catch (error) {
|
|
746
|
-
return fail(error, "Reference check failed.");
|
|
758
|
+
return fail$1(error, "Reference check failed.");
|
|
747
759
|
}
|
|
748
760
|
}
|
|
749
761
|
});
|
|
@@ -756,7 +768,7 @@ const pluginOption = {
|
|
|
756
768
|
description: "A plugin's source folder in this repository: acts on its `references/<name>.md`.",
|
|
757
769
|
type: t.string().optional()
|
|
758
770
|
};
|
|
759
|
-
const skillOption = {
|
|
771
|
+
const skillOption$1 = {
|
|
760
772
|
description: "A skill's source folder in this repository: acts on its `references/<name>.default.md`.",
|
|
761
773
|
type: t.string().optional()
|
|
762
774
|
};
|
|
@@ -770,10 +782,10 @@ function createCommand(layersFor) {
|
|
|
770
782
|
type: t.string()
|
|
771
783
|
}],
|
|
772
784
|
options: {
|
|
773
|
-
root: rootOption,
|
|
785
|
+
root: rootOption$1,
|
|
774
786
|
scope: scopeOption,
|
|
775
787
|
plugin: pluginOption,
|
|
776
|
-
default: skillOption,
|
|
788
|
+
default: skillOption$1,
|
|
777
789
|
merge: {
|
|
778
790
|
description: "How it applies over what is below: replace, patch (default), combine, or remove. remove writes no body.",
|
|
779
791
|
type: t.string().optional()
|
|
@@ -828,12 +840,12 @@ function createCommand(layersFor) {
|
|
|
828
840
|
if (args.trace && created.after) process.stderr.write(traceText(created.after, home));
|
|
829
841
|
return document(created.dryRun ? `${report.path}\n\n${created.content}` : `${report.path}\n\n${report.hint}\n`);
|
|
830
842
|
} catch (error) {
|
|
831
|
-
return fail(error, "Reference creation failed.");
|
|
843
|
+
return fail$1(error, "Reference creation failed.");
|
|
832
844
|
}
|
|
833
845
|
}
|
|
834
846
|
});
|
|
835
847
|
}
|
|
836
|
-
function selectCommand(layersFor) {
|
|
848
|
+
function selectCommand$1(layersFor) {
|
|
837
849
|
return command({
|
|
838
850
|
name: "select",
|
|
839
851
|
description: "Choose what a name builds on: write an `extends` listing the options, bottom first, in the project or user file. Its body and other keys are kept.",
|
|
@@ -847,7 +859,7 @@ function selectCommand(layersFor) {
|
|
|
847
859
|
type: t.array(t.string()).optional()
|
|
848
860
|
}],
|
|
849
861
|
options: {
|
|
850
|
-
root: rootOption,
|
|
862
|
+
root: rootOption$1,
|
|
851
863
|
scope: scopeOption,
|
|
852
864
|
clear: {
|
|
853
865
|
description: "Remove the selection; a file left with nothing in it is deleted.",
|
|
@@ -881,7 +893,7 @@ function selectCommand(layersFor) {
|
|
|
881
893
|
const what = args.clear ? selected.deleted ? "selection cleared; the file was left empty and deleted" : "selection cleared" : `extends: [${selected.extends.join(", ")}]`;
|
|
882
894
|
return document(`${report.path}\n\n${what}. ${report.answer}\n`);
|
|
883
895
|
} catch (error) {
|
|
884
|
-
return fail(error, "Reference selection failed.");
|
|
896
|
+
return fail$1(error, "Reference selection failed.");
|
|
885
897
|
}
|
|
886
898
|
}
|
|
887
899
|
});
|
|
@@ -898,7 +910,7 @@ function deleteReport(deleted, home) {
|
|
|
898
910
|
options: deleted.after.options
|
|
899
911
|
});
|
|
900
912
|
}
|
|
901
|
-
function deleteCommand(layersFor) {
|
|
913
|
+
function deleteCommand$1(layersFor) {
|
|
902
914
|
return command({
|
|
903
915
|
name: "delete",
|
|
904
916
|
description: "Delete a project or user contribution, or one in a plugin's or a skill's source folder, and report what answers the name afterwards. Never deletes an installed or managed one.",
|
|
@@ -908,13 +920,13 @@ function deleteCommand(layersFor) {
|
|
|
908
920
|
type: t.string()
|
|
909
921
|
}],
|
|
910
922
|
options: {
|
|
911
|
-
root: rootOption,
|
|
923
|
+
root: rootOption$1,
|
|
912
924
|
scope: {
|
|
913
925
|
...scopeOption,
|
|
914
926
|
description: "Tier to delete from: project (default) or user."
|
|
915
927
|
},
|
|
916
928
|
plugin: pluginOption,
|
|
917
|
-
default: skillOption,
|
|
929
|
+
default: skillOption$1,
|
|
918
930
|
"dry-run": {
|
|
919
931
|
description: "Print the file that would be deleted and what would answer the name then, and delete nothing.",
|
|
920
932
|
type: t.boolean().optional()
|
|
@@ -942,7 +954,7 @@ function deleteCommand(layersFor) {
|
|
|
942
954
|
const selection = report.selection ? ` Also, ${report.selection}.` : "";
|
|
943
955
|
return document(`${report.path}\n\n${deleted.dryRun ? "would delete" : "deleted"}. ${report.answer}${selection}\n`);
|
|
944
956
|
} catch (error) {
|
|
945
|
-
return fail(error, "Reference deletion failed.");
|
|
957
|
+
return fail$1(error, "Reference deletion failed.");
|
|
946
958
|
}
|
|
947
959
|
}
|
|
948
960
|
});
|
|
@@ -951,13 +963,13 @@ function deleteCommand(layersFor) {
|
|
|
951
963
|
function createReferenceCommands({ plugin } = {}) {
|
|
952
964
|
const layersFor = layerSource(plugin);
|
|
953
965
|
return {
|
|
954
|
-
show: showCommand(layersFor),
|
|
955
|
-
list: listCommand(layersFor),
|
|
966
|
+
show: showCommand$1(layersFor),
|
|
967
|
+
list: listCommand$1(layersFor),
|
|
956
968
|
search: searchCommand(layersFor),
|
|
957
969
|
where: whereCommand(layersFor),
|
|
958
970
|
create: createCommand(layersFor),
|
|
959
|
-
select: selectCommand(layersFor),
|
|
960
|
-
delete: deleteCommand(layersFor),
|
|
971
|
+
select: selectCommand$1(layersFor),
|
|
972
|
+
delete: deleteCommand$1(layersFor),
|
|
961
973
|
check: checkCommand(layersFor),
|
|
962
974
|
implementations: implementationsCommand(layersFor)
|
|
963
975
|
};
|
|
@@ -980,5 +992,414 @@ function createReferenceCommand(options = {}) {
|
|
|
980
992
|
]
|
|
981
993
|
});
|
|
982
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* The tiered, by-name commands over `assets/` folders: the reference engine reading `assets/` where it
|
|
997
|
+
* reads `references/`. `load` is `show`, `names` is `list`. `asset`'s own commands act on a path.
|
|
998
|
+
*/
|
|
999
|
+
function createAssetResolveCommands({ plugin } = {}) {
|
|
1000
|
+
const layersFor = layerSource(plugin, "assets");
|
|
1001
|
+
return {
|
|
1002
|
+
load: showCommand$1(layersFor, "load"),
|
|
1003
|
+
names: listCommand$1(layersFor, "names"),
|
|
1004
|
+
where: whereCommand(layersFor, true)
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
//#endregion
|
|
1008
|
+
//#region src/assets/skill-assets.ts
|
|
1009
|
+
/** A refusal. `usage` marks a wrong invocation (exit 2) rather than a refusal (exit 1). */
|
|
1010
|
+
var AssetError = class extends Error {
|
|
1011
|
+
code;
|
|
1012
|
+
usage;
|
|
1013
|
+
constructor(code, message, usage = false) {
|
|
1014
|
+
super(message);
|
|
1015
|
+
this.code = code;
|
|
1016
|
+
this.usage = usage;
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
/** The skill's `assets/` folder, for a skill folder that holds a `SKILL.md`. */
|
|
1020
|
+
function assetsDir(skill, root, write) {
|
|
1021
|
+
const folder = resolve(skill);
|
|
1022
|
+
if (skillName(folder) === void 0) throw new AssetError("folder-invalid", `${folder} holds no SKILL.md, so it is not a skill folder.`);
|
|
1023
|
+
if (write && !insideRepository(folder, root)) throw new AssetError("folder-invalid", `${folder} is outside the repository, such as an installed copy; write to the skill's source instead.`);
|
|
1024
|
+
return join(folder, "assets");
|
|
1025
|
+
}
|
|
1026
|
+
/** An asset path: relative, `/`-separated, with no `..` or empty part. */
|
|
1027
|
+
function assetFile(dir, path) {
|
|
1028
|
+
const parts = path.split("/");
|
|
1029
|
+
if (!path || path.includes("\\") || path.startsWith("/") || parts.some((part) => part === "" || part === "." || part === "..")) throw new AssetError("path-invalid", `"${path}" is not an asset path. Use a relative path inside assets/, with "/" separators and no "..".`, true);
|
|
1030
|
+
return join(dir, ...parts);
|
|
1031
|
+
}
|
|
1032
|
+
/** True when the real location of an existing file or its nearest existing parent stays inside the folder. */
|
|
1033
|
+
function contained(dir, file) {
|
|
1034
|
+
if (!existsSync(dir)) return true;
|
|
1035
|
+
const base = realpathSync(dir);
|
|
1036
|
+
let probe = file;
|
|
1037
|
+
while (!existsSync(probe)) probe = dirname(probe);
|
|
1038
|
+
const real = realpathSync(probe);
|
|
1039
|
+
return real === base || real.startsWith(base + sep);
|
|
1040
|
+
}
|
|
1041
|
+
function guard(dir, file, path) {
|
|
1042
|
+
if (!contained(dir, file)) throw new AssetError("path-invalid", `"${path}" leaves the assets/ folder through a link.`, true);
|
|
1043
|
+
}
|
|
1044
|
+
function listAssets(skill, root) {
|
|
1045
|
+
const dir = assetsDir(skill, root, false);
|
|
1046
|
+
const entries = [];
|
|
1047
|
+
const walk = (folder, prefix) => {
|
|
1048
|
+
let items;
|
|
1049
|
+
try {
|
|
1050
|
+
items = readdirSync(folder, { withFileTypes: true });
|
|
1051
|
+
} catch {
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
for (const item of items) {
|
|
1055
|
+
const full = join(folder, item.name);
|
|
1056
|
+
const stat = lstatSync(full);
|
|
1057
|
+
if (stat.isSymbolicLink()) continue;
|
|
1058
|
+
if (stat.isDirectory()) walk(full, `${prefix}${item.name}/`);
|
|
1059
|
+
else if (stat.isFile()) entries.push({
|
|
1060
|
+
path: `${prefix}${item.name}`,
|
|
1061
|
+
bytes: stat.size
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
walk(dir, "");
|
|
1066
|
+
return entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
1067
|
+
}
|
|
1068
|
+
function showAsset(skill, root, path) {
|
|
1069
|
+
const dir = assetsDir(skill, root, false);
|
|
1070
|
+
const file = assetFile(dir, path);
|
|
1071
|
+
guard(dir, file, path);
|
|
1072
|
+
if (!existsSync(file) || !lstatSync(file).isFile()) throw new AssetError("no-file", `${path} does not exist in assets/.`);
|
|
1073
|
+
const bytes = readFileSync(file);
|
|
1074
|
+
if (bytes.includes(0)) throw new AssetError("binary", `${path} is binary (${bytes.length} bytes); point to it by path instead of showing it.`);
|
|
1075
|
+
return bytes.toString("utf8");
|
|
1076
|
+
}
|
|
1077
|
+
function writeAsset(mode, skill, root, path, content) {
|
|
1078
|
+
const dir = assetsDir(skill, root, true);
|
|
1079
|
+
const file = assetFile(dir, path);
|
|
1080
|
+
guard(dir, file, path);
|
|
1081
|
+
const exists = existsSync(file);
|
|
1082
|
+
if (mode === "create" && exists) throw new AssetError("exists", `${path} already exists in assets/; use update to replace it.`);
|
|
1083
|
+
if (mode === "update" && !exists) throw new AssetError("no-file", `${path} does not exist in assets/; use create to add it.`);
|
|
1084
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
1085
|
+
writeFileSync(file, content);
|
|
1086
|
+
return file;
|
|
1087
|
+
}
|
|
1088
|
+
function deleteAsset(skill, root, path) {
|
|
1089
|
+
const dir = assetsDir(skill, root, true);
|
|
1090
|
+
const file = assetFile(dir, path);
|
|
1091
|
+
guard(dir, file, path);
|
|
1092
|
+
if (!existsSync(file) || !lstatSync(file).isFile()) throw new AssetError("no-file", `${path} does not exist in assets/.`);
|
|
1093
|
+
rmSync(file);
|
|
1094
|
+
for (let folder = dirname(file); folder !== dir && folder.startsWith(dir + sep); folder = dirname(folder)) try {
|
|
1095
|
+
rmdirSync(folder);
|
|
1096
|
+
} catch {
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
return file;
|
|
1100
|
+
}
|
|
1101
|
+
//#endregion
|
|
1102
|
+
//#region src/assets/copy-asset.ts
|
|
1103
|
+
/**
|
|
1104
|
+
* Creates `<name>.<ext>` in the project or user `assets/` folder as a copy of the file another tier or
|
|
1105
|
+
* plugin holds, so it can be edited as an override. The managed tier is never a source: it is policy an
|
|
1106
|
+
* administrator keeps out of repositories and home folders, and a copy would show stale text as if it
|
|
1107
|
+
* were in effect (the managed file would still win).
|
|
1108
|
+
*/
|
|
1109
|
+
function copyAsset(layers, args) {
|
|
1110
|
+
const name = parseReferenceName(args.name);
|
|
1111
|
+
if (name.invalid || name.plugin !== void 0) throw new AssetError("name-invalid", name.invalid ?? "create takes a bare name.", true);
|
|
1112
|
+
if (args.scope !== "project" && args.scope !== "user") throw new AssetError("options-invalid", "--scope is project or user.", true);
|
|
1113
|
+
if (args.copy === "managed") throw new AssetError("managed-copy-refused", "the managed tier is policy and is never copied into a project or user folder. Ask the administrator, or read it with \"asset load\".");
|
|
1114
|
+
const found = resolveReference(name.name, layers).trace.layers.filter(({ file }) => file);
|
|
1115
|
+
const source = found.find((layer) => args.copy === "default" || args.copy === "project" || args.copy === "user" ? layer.tier === args.copy : layer.tier === "plugin" && layer.plugin === args.copy);
|
|
1116
|
+
if (!source) {
|
|
1117
|
+
const held = found.map((layer) => layer.tier === "plugin" ? layer.plugin : layer.tier);
|
|
1118
|
+
throw new AssetError("no-source", `"${args.copy}" holds no asset "${name.name}". Held by: ${held.filter((tier) => tier !== "managed").join(", ") || "nothing"}.`);
|
|
1119
|
+
}
|
|
1120
|
+
const extension = extname(source.path);
|
|
1121
|
+
if (source.file && ![...dataExtensions.map((item) => item.extension), ".md"].includes(extension)) throw new AssetError("no-source", `${basename(source.path)} is not a file an asset name resolves to.`);
|
|
1122
|
+
const base = args.scope === "user" ? userReferencesDir(args.home) : projectReferencesDir(resolve(args.root));
|
|
1123
|
+
const dir = join(dirname(base), "assets");
|
|
1124
|
+
const taken = [".md", ...dataExtensions.map((item) => item.extension)].map((item) => join(dir, `${name.name}${item}`)).find((path) => existsSync(path));
|
|
1125
|
+
if (taken) throw new AssetError("exists", `${taken} already exists; edit it, or delete it first.`);
|
|
1126
|
+
const path = join(dir, `${name.name}${extension}`);
|
|
1127
|
+
mkdirSync(dir, { recursive: true });
|
|
1128
|
+
copyFileSync(source.path, path);
|
|
1129
|
+
return {
|
|
1130
|
+
path,
|
|
1131
|
+
source: source.path,
|
|
1132
|
+
from: args.copy
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
//#endregion
|
|
1136
|
+
//#region src/assets/select-asset.ts
|
|
1137
|
+
/** The options a name can be selected between: each plugin holding it, and `default` when the skill's file exists. */
|
|
1138
|
+
function options(layers, name) {
|
|
1139
|
+
const found = resolveReference(name, layers).trace.layers;
|
|
1140
|
+
return [...found.filter(({ tier, file }) => tier === "plugin" && file).map(({ plugin }) => plugin), ...found.some(({ tier, file }) => tier === "default" && file) ? ["default"] : []];
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Writes `<name>.select` in the project or user `assets/` folder: one line, the plugin or `default` that
|
|
1144
|
+
* answers the name. Nothing else is in the file, and nothing extends or merges.
|
|
1145
|
+
*/
|
|
1146
|
+
function selectAsset(layers, args) {
|
|
1147
|
+
const name = parseReferenceName(args.name);
|
|
1148
|
+
if (name.invalid || name.plugin !== void 0) throw new AssetError("name-invalid", name.invalid ?? "select takes a bare name.", true);
|
|
1149
|
+
if (args.scope !== void 0 && args.scope !== "project" && args.scope !== "user") throw new AssetError("options-invalid", "--scope is project or user.", true);
|
|
1150
|
+
const base = args.scope === "user" ? userReferencesDir(args.home) : projectReferencesDir(resolve(args.root));
|
|
1151
|
+
const path = join(dirname(base), "assets", `${name.name}.select`);
|
|
1152
|
+
if (args.clear) {
|
|
1153
|
+
if (!existsSync(path)) throw new AssetError("no-file", `${path} does not exist, so there is no selection to clear.`);
|
|
1154
|
+
rmSync(path);
|
|
1155
|
+
} else {
|
|
1156
|
+
const held = options(layers, name.name);
|
|
1157
|
+
if (!args.option || !held.includes(args.option)) throw new AssetError("option-invalid", `"${args.option ?? ""}" cannot be selected for "${name.name}". Options: ${held.join(", ") || "none, no plugin or default holds it"}.`, !args.option);
|
|
1158
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
1159
|
+
writeFileSync(path, `${args.option}\n`);
|
|
1160
|
+
}
|
|
1161
|
+
const result = {
|
|
1162
|
+
path,
|
|
1163
|
+
cleared: Boolean(args.clear),
|
|
1164
|
+
after: resolveReference(name.name, layers, { without: args.clear ? path : void 0 })
|
|
1165
|
+
};
|
|
1166
|
+
return args.clear ? result : {
|
|
1167
|
+
...result,
|
|
1168
|
+
selected: args.option
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
//#endregion
|
|
1172
|
+
//#region src/assets/asset.command.ts
|
|
1173
|
+
const skillOption = {
|
|
1174
|
+
description: "A skill's source folder in this repository: its `assets/` folder is acted on.",
|
|
1175
|
+
type: t.string()
|
|
1176
|
+
};
|
|
1177
|
+
const rootOption = {
|
|
1178
|
+
description: "The directory the repository is found from. Defaults to the current directory.",
|
|
1179
|
+
type: t.string().optional()
|
|
1180
|
+
};
|
|
1181
|
+
function fail(error, fallback) {
|
|
1182
|
+
if (isCliError(error)) throw error;
|
|
1183
|
+
if (error instanceof AssetError) {
|
|
1184
|
+
process.stderr.write(`error: ${error.code}: ${error.message}\n`);
|
|
1185
|
+
throw CliError.reported(error.usage ? exitCodes.usage : exitCodes.error);
|
|
1186
|
+
}
|
|
1187
|
+
process.stderr.write(`error: ${error instanceof Error ? error.message : fallback}\n`);
|
|
1188
|
+
throw CliError.reported(exitCodes.error);
|
|
1189
|
+
}
|
|
1190
|
+
function usage(message) {
|
|
1191
|
+
process.stderr.write(`error: usage: ${message}\n`);
|
|
1192
|
+
throw CliError.reported(exitCodes.usage);
|
|
1193
|
+
}
|
|
1194
|
+
const pathDescription = "Asset path inside `assets/`, such as `data/rules.json`.";
|
|
1195
|
+
function rootOf(args) {
|
|
1196
|
+
return resolve(args.root ?? process.cwd());
|
|
1197
|
+
}
|
|
1198
|
+
function listCommand() {
|
|
1199
|
+
return command({
|
|
1200
|
+
name: "list",
|
|
1201
|
+
description: "List every file in a skill's assets/ folder with its size.",
|
|
1202
|
+
options: {
|
|
1203
|
+
skill: skillOption,
|
|
1204
|
+
root: rootOption
|
|
1205
|
+
},
|
|
1206
|
+
async run(args) {
|
|
1207
|
+
try {
|
|
1208
|
+
const entries = listAssets(args.skill, rootOf(args));
|
|
1209
|
+
return result({ assets: entries.length ? entries : "0 assets — the skill holds none" });
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
return fail(error, "Asset listing failed.");
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
function showCommand() {
|
|
1217
|
+
return command({
|
|
1218
|
+
name: "show",
|
|
1219
|
+
description: "Print a text asset as written.",
|
|
1220
|
+
arguments: [{
|
|
1221
|
+
name: "path",
|
|
1222
|
+
description: pathDescription,
|
|
1223
|
+
type: t.string()
|
|
1224
|
+
}],
|
|
1225
|
+
options: {
|
|
1226
|
+
skill: skillOption,
|
|
1227
|
+
root: rootOption
|
|
1228
|
+
},
|
|
1229
|
+
async run(args) {
|
|
1230
|
+
try {
|
|
1231
|
+
return document(showAsset(args.skill, rootOf(args), args.path));
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
return fail(error, "Asset read failed.");
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
function writeCommand(mode, host) {
|
|
1239
|
+
const create = mode === "create";
|
|
1240
|
+
return command({
|
|
1241
|
+
name: mode,
|
|
1242
|
+
description: create ? "Add a new asset: by path in a skill from --content or --from, or, with --copy, by name in the project or user assets folder as a copy of what a plugin, the default, or another tier holds (never the managed tier). Never overwrites a file." : "Replace an existing asset from --content or --from.",
|
|
1243
|
+
arguments: [{
|
|
1244
|
+
name: "path",
|
|
1245
|
+
description: `${pathDescription} With --copy, the asset name.`,
|
|
1246
|
+
type: t.string()
|
|
1247
|
+
}],
|
|
1248
|
+
options: {
|
|
1249
|
+
skill: {
|
|
1250
|
+
...skillOption,
|
|
1251
|
+
type: t.string().optional()
|
|
1252
|
+
},
|
|
1253
|
+
root: rootOption,
|
|
1254
|
+
content: {
|
|
1255
|
+
description: "The text to write.",
|
|
1256
|
+
type: t.string().optional()
|
|
1257
|
+
},
|
|
1258
|
+
from: {
|
|
1259
|
+
description: "A local file whose bytes to write.",
|
|
1260
|
+
type: t.string().optional()
|
|
1261
|
+
},
|
|
1262
|
+
...create ? {
|
|
1263
|
+
default: {
|
|
1264
|
+
description: "With --copy, the calling skill's folder: its `assets/<name>.<ext>` is the `default` source.",
|
|
1265
|
+
type: t.string().optional()
|
|
1266
|
+
},
|
|
1267
|
+
copy: {
|
|
1268
|
+
description: "Copy the asset of this source: a plugin's name, `default` (the skill's own file), `project`, or `user`. `managed` is refused.",
|
|
1269
|
+
type: t.string().optional()
|
|
1270
|
+
},
|
|
1271
|
+
scope: {
|
|
1272
|
+
description: "With --copy, where the copy goes: project (default), `.agents/assets/`, or user, `~/.agents/assets/`.",
|
|
1273
|
+
type: t.string().optional()
|
|
1274
|
+
}
|
|
1275
|
+
} : {}
|
|
1276
|
+
},
|
|
1277
|
+
async run(args) {
|
|
1278
|
+
try {
|
|
1279
|
+
if (args.copy !== void 0) {
|
|
1280
|
+
if (args.content !== void 0 || args.from !== void 0) usage("--copy takes neither --content nor --from.");
|
|
1281
|
+
const home = homedir();
|
|
1282
|
+
const root = rootOf(args);
|
|
1283
|
+
const done = copyAsset(await referenceLayers({
|
|
1284
|
+
root,
|
|
1285
|
+
home,
|
|
1286
|
+
platform: process.platform,
|
|
1287
|
+
env: process.env,
|
|
1288
|
+
plugin: host.plugin,
|
|
1289
|
+
defaultSkill: args.default ?? args.skill,
|
|
1290
|
+
folder: "assets"
|
|
1291
|
+
}), {
|
|
1292
|
+
root,
|
|
1293
|
+
home,
|
|
1294
|
+
name: args.path,
|
|
1295
|
+
scope: args.scope ?? "project",
|
|
1296
|
+
copy: args.copy
|
|
1297
|
+
});
|
|
1298
|
+
return document(`${done.path}\n\ncopied from ${done.from}. Edit it; it now answers over the plugin tier.\n`);
|
|
1299
|
+
}
|
|
1300
|
+
if (!args.skill) usage("pass --skill, or --copy to create an override by name.");
|
|
1301
|
+
if (args.content === void 0 === (args.from === void 0)) usage("pass exactly one of --content and --from.");
|
|
1302
|
+
const content = args.content ?? readFileSync(resolve(args.from), "utf8");
|
|
1303
|
+
const file = writeAsset(mode, args.skill, rootOf(args), args.path, content);
|
|
1304
|
+
return document(`${file}\n\n${create ? "created" : "updated"}.\n`);
|
|
1305
|
+
} catch (error) {
|
|
1306
|
+
return fail(error, `Asset ${mode} failed.`);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
function deleteCommand() {
|
|
1312
|
+
return command({
|
|
1313
|
+
name: "delete",
|
|
1314
|
+
description: "Delete an asset from a skill's source folder, and any folder it leaves empty.",
|
|
1315
|
+
arguments: [{
|
|
1316
|
+
name: "path",
|
|
1317
|
+
description: pathDescription,
|
|
1318
|
+
type: t.string()
|
|
1319
|
+
}],
|
|
1320
|
+
options: {
|
|
1321
|
+
skill: skillOption,
|
|
1322
|
+
root: rootOption
|
|
1323
|
+
},
|
|
1324
|
+
async run(args) {
|
|
1325
|
+
try {
|
|
1326
|
+
return document(`${deleteAsset(args.skill, rootOf(args), args.path)}\n\ndeleted.\n`);
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
return fail(error, "Asset deletion failed.");
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
function selectCommand(options) {
|
|
1334
|
+
return command({
|
|
1335
|
+
name: "select",
|
|
1336
|
+
description: "Choose which plugin, or the skill itself, answers an asset name that several hold, by writing `<name>.select` in the project or user assets folder.",
|
|
1337
|
+
arguments: [{
|
|
1338
|
+
name: "name",
|
|
1339
|
+
description: "Asset name, without its extension.",
|
|
1340
|
+
type: t.string()
|
|
1341
|
+
}, {
|
|
1342
|
+
name: "option",
|
|
1343
|
+
description: "A plugin name, or `default` for the skill's own file. Not used with --clear.",
|
|
1344
|
+
type: t.string().optional()
|
|
1345
|
+
}],
|
|
1346
|
+
options: {
|
|
1347
|
+
root: rootOption,
|
|
1348
|
+
default: {
|
|
1349
|
+
description: "The calling skill's folder: its `assets/<name>.<ext>` is the `default` option.",
|
|
1350
|
+
type: t.string().optional()
|
|
1351
|
+
},
|
|
1352
|
+
scope: {
|
|
1353
|
+
description: "Where to write: project (default), `.agents/assets/`, or user, `~/.agents/assets/`.",
|
|
1354
|
+
type: t.string().optional()
|
|
1355
|
+
},
|
|
1356
|
+
clear: {
|
|
1357
|
+
description: "Remove the selection.",
|
|
1358
|
+
type: t.boolean().optional()
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
async run(args) {
|
|
1362
|
+
try {
|
|
1363
|
+
const home = homedir();
|
|
1364
|
+
const root = resolve(args.root ?? process.cwd());
|
|
1365
|
+
const done = selectAsset(await referenceLayers({
|
|
1366
|
+
root,
|
|
1367
|
+
home,
|
|
1368
|
+
platform: process.platform,
|
|
1369
|
+
env: process.env,
|
|
1370
|
+
plugin: options.plugin,
|
|
1371
|
+
defaultSkill: args.default,
|
|
1372
|
+
folder: "assets"
|
|
1373
|
+
}), {
|
|
1374
|
+
...args,
|
|
1375
|
+
root,
|
|
1376
|
+
home
|
|
1377
|
+
});
|
|
1378
|
+
const answer = done.after.status === "found" ? `${args.name} now answers from ${done.after.trace.stack.join(", ") || "a tier"}.` : `${args.name} is ${done.after.status}: ${done.after.message ?? ""}`;
|
|
1379
|
+
return document(`${done.path}\n\n${done.cleared ? "selection cleared" : `selected ${done.selected}`}. ${answer}\n`);
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
return fail(error, "Asset selection failed.");
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
function createAssetCommand(options = {}) {
|
|
1387
|
+
const { load, names, where } = createAssetResolveCommands(options);
|
|
1388
|
+
return command({
|
|
1389
|
+
name: "asset",
|
|
1390
|
+
description: "Manage a skill's assets/ files by path (list, show, create, update, delete), and load one by name through the tiers (load, names, where, select).",
|
|
1391
|
+
commands: [
|
|
1392
|
+
listCommand(),
|
|
1393
|
+
showCommand(),
|
|
1394
|
+
writeCommand("create", options),
|
|
1395
|
+
writeCommand("update", options),
|
|
1396
|
+
deleteCommand(),
|
|
1397
|
+
load,
|
|
1398
|
+
names,
|
|
1399
|
+
where,
|
|
1400
|
+
selectCommand(options)
|
|
1401
|
+
]
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
983
1404
|
//#endregion
|
|
984
|
-
export { createReferenceCommand, createReferenceCommands };
|
|
1405
|
+
export { createAssetCommand, createReferenceCommand, createReferenceCommands };
|