akm-cli 0.0.16 → 0.0.18
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 +61 -108
- package/dist/asset-spec.js +9 -9
- package/dist/cli.js +321 -118
- package/dist/common.js +0 -7
- package/dist/config-cli.js +43 -0
- package/dist/config.js +46 -26
- package/dist/file-context.js +3 -28
- package/dist/indexer.js +0 -30
- package/dist/llm.js +1 -1
- package/dist/matchers.js +4 -15
- package/dist/metadata.js +3 -3
- package/dist/provider-registry.js +8 -0
- package/dist/providers/skills-sh.js +165 -0
- package/dist/providers/static-index.js +340 -0
- package/dist/registry-install.js +5 -5
- package/dist/registry-provider.js +1 -0
- package/dist/registry-search.js +65 -226
- package/dist/renderers.js +1 -1
- package/dist/stash-add.js +2 -2
- package/dist/stash-ref.js +7 -9
- package/dist/stash-registry.js +6 -6
- package/dist/stash-resolve.js +7 -44
- package/dist/stash-search.js +8 -12
- package/dist/stash-show.js +1 -2
- package/dist/stash-source.js +6 -7
- package/dist/walker.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { ConfigError, NotFoundError, UsageError } from "./errors";
|
|
|
9
9
|
import { agentikitIndex } from "./indexer";
|
|
10
10
|
import { agentikitInit } from "./init";
|
|
11
11
|
import { getCacheDir, getDbPath, getDefaultStashDir } from "./paths";
|
|
12
|
+
import { searchRegistry } from "./registry-search";
|
|
12
13
|
import { checkForUpdate, performUpgrade } from "./self-update";
|
|
13
14
|
import { agentikitAdd } from "./stash-add";
|
|
14
15
|
import { agentikitClone } from "./stash-clone";
|
|
@@ -101,6 +102,8 @@ function shapeForCommand(command, result, detail) {
|
|
|
101
102
|
switch (command) {
|
|
102
103
|
case "search":
|
|
103
104
|
return shapeSearchOutput(result, detail);
|
|
105
|
+
case "registry-search":
|
|
106
|
+
return shapeRegistrySearchOutput(result, detail);
|
|
104
107
|
case "show":
|
|
105
108
|
return shapeShowOutput(result, detail);
|
|
106
109
|
default:
|
|
@@ -127,6 +130,22 @@ function shapeSearchOutput(result, detail) {
|
|
|
127
130
|
...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
|
|
128
131
|
};
|
|
129
132
|
}
|
|
133
|
+
function shapeRegistrySearchOutput(result, detail) {
|
|
134
|
+
const hits = Array.isArray(result.hits) ? result.hits : [];
|
|
135
|
+
const assetHits = Array.isArray(result.assetHits) ? result.assetHits : [];
|
|
136
|
+
// Shape kit hits as registry type
|
|
137
|
+
const shapedKitHits = hits.map((hit) => shapeSearchHit({ ...hit, type: "registry" }, detail));
|
|
138
|
+
const shapedAssetHits = assetHits.map((hit) => shapeSearchHit(hit, detail));
|
|
139
|
+
const shaped = {
|
|
140
|
+
hits: shapedKitHits,
|
|
141
|
+
...(shapedAssetHits.length > 0 ? { assetHits: shapedAssetHits } : {}),
|
|
142
|
+
...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
|
|
143
|
+
};
|
|
144
|
+
if (detail === "full") {
|
|
145
|
+
shaped.query = result.query;
|
|
146
|
+
}
|
|
147
|
+
return shaped;
|
|
148
|
+
}
|
|
130
149
|
function shapeSearchHit(hit, detail) {
|
|
131
150
|
// Keep local and registry hit models separate internally so search and
|
|
132
151
|
// ranking logic can carry source-specific metadata. Normalize the external
|
|
@@ -139,6 +158,15 @@ function shapeSearchHit(hit, detail) {
|
|
|
139
158
|
return pickFields(hit, ["type", "name", "id", "description", "tags", "action", "curated"]);
|
|
140
159
|
return hit;
|
|
141
160
|
}
|
|
161
|
+
if (hit.type === "registry-asset") {
|
|
162
|
+
const brief = withTruncatedDescription(pickFields(hit, ["type", "assetType", "assetName", "description", "kit", "action"]));
|
|
163
|
+
if (detail === "brief")
|
|
164
|
+
return brief;
|
|
165
|
+
if (detail === "normal") {
|
|
166
|
+
return pickFields(hit, ["type", "assetType", "assetName", "description", "kit", "registryName", "action"]);
|
|
167
|
+
}
|
|
168
|
+
return hit;
|
|
169
|
+
}
|
|
142
170
|
const brief = withTruncatedDescription(pickFields(hit, ["type", "name", "description", "action"]));
|
|
143
171
|
if (detail === "brief")
|
|
144
172
|
return brief;
|
|
@@ -405,7 +433,7 @@ const searchCommand = defineCommand({
|
|
|
405
433
|
query: { type: "positional", description: "Search query (omit to list all assets)", required: false, default: "" },
|
|
406
434
|
type: {
|
|
407
435
|
type: "string",
|
|
408
|
-
description: "Asset type filter (skill|command|agent|knowledge|script|any).
|
|
436
|
+
description: "Asset type filter (skill|command|agent|knowledge|script|any).",
|
|
409
437
|
},
|
|
410
438
|
limit: { type: "string", description: "Maximum number of results" },
|
|
411
439
|
source: { type: "string", description: "Search source (local|registry|both)", default: "local" },
|
|
@@ -439,7 +467,7 @@ const addCommand = defineCommand({
|
|
|
439
467
|
},
|
|
440
468
|
});
|
|
441
469
|
const listCommand = defineCommand({
|
|
442
|
-
meta: { name: "list", description: "List installed
|
|
470
|
+
meta: { name: "list", description: "List installed kits" },
|
|
443
471
|
async run() {
|
|
444
472
|
await runWithJsonErrors(async () => {
|
|
445
473
|
const result = await agentikitList();
|
|
@@ -448,7 +476,7 @@ const listCommand = defineCommand({
|
|
|
448
476
|
},
|
|
449
477
|
});
|
|
450
478
|
const removeCommand = defineCommand({
|
|
451
|
-
meta: { name: "remove", description: "Remove an installed
|
|
479
|
+
meta: { name: "remove", description: "Remove an installed kit by id or ref" },
|
|
452
480
|
args: {
|
|
453
481
|
target: { type: "positional", description: "Installed target (id or ref)", required: true },
|
|
454
482
|
},
|
|
@@ -460,7 +488,7 @@ const removeCommand = defineCommand({
|
|
|
460
488
|
},
|
|
461
489
|
});
|
|
462
490
|
const updateCommand = defineCommand({
|
|
463
|
-
meta: { name: "update", description: "Update one or all installed
|
|
491
|
+
meta: { name: "update", description: "Update one or all installed kits" },
|
|
464
492
|
args: {
|
|
465
493
|
target: { type: "positional", description: "Installed target (id or ref)", required: false },
|
|
466
494
|
all: { type: "boolean", description: "Update all installed entries", default: false },
|
|
@@ -500,35 +528,33 @@ const showCommand = defineCommand({
|
|
|
500
528
|
ref: { type: "positional", description: "Asset ref (type:name)", required: true },
|
|
501
529
|
format: { type: "string", description: "Output format (json|text|yaml)" },
|
|
502
530
|
detail: { type: "string", description: "Detail level (brief|normal|full)" },
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
start: { type: "string", description: "Start line (for lines view)" },
|
|
508
|
-
end: { type: "string", description: "End line (for lines view)" },
|
|
531
|
+
akmView: { type: "string", description: "Internal positional knowledge view mode parser" },
|
|
532
|
+
akmHeading: { type: "string", description: "Internal positional section heading parser" },
|
|
533
|
+
akmStart: { type: "string", description: "Internal positional start-line parser" },
|
|
534
|
+
akmEnd: { type: "string", description: "Internal positional end-line parser" },
|
|
509
535
|
},
|
|
510
536
|
async run({ args }) {
|
|
511
537
|
await runWithJsonErrors(async () => {
|
|
512
538
|
let view;
|
|
513
|
-
if (args.
|
|
514
|
-
switch (args.
|
|
539
|
+
if (args.akmView) {
|
|
540
|
+
switch (args.akmView) {
|
|
515
541
|
case "section":
|
|
516
|
-
view = { mode: "section", heading: args.
|
|
542
|
+
view = { mode: "section", heading: args.akmHeading ?? "" };
|
|
517
543
|
break;
|
|
518
544
|
case "lines":
|
|
519
545
|
view = {
|
|
520
546
|
mode: "lines",
|
|
521
|
-
start: Number(args.
|
|
522
|
-
end: args.
|
|
547
|
+
start: Number(args.akmStart ?? "1"),
|
|
548
|
+
end: args.akmEnd ? parseInt(args.akmEnd, 10) : Number.MAX_SAFE_INTEGER,
|
|
523
549
|
};
|
|
524
550
|
break;
|
|
525
551
|
case "toc":
|
|
526
552
|
case "frontmatter":
|
|
527
553
|
case "full":
|
|
528
|
-
view = { mode: args.
|
|
554
|
+
view = { mode: args.akmView };
|
|
529
555
|
break;
|
|
530
556
|
default:
|
|
531
|
-
throw new UsageError(`Unknown view mode: ${args.
|
|
557
|
+
throw new UsageError(`Unknown view mode: ${args.akmView}. Expected one of: full|toc|frontmatter|section|lines`);
|
|
532
558
|
}
|
|
533
559
|
}
|
|
534
560
|
const result = await agentikitShow({ ref: args.ref, view });
|
|
@@ -540,9 +566,6 @@ const configCommand = defineCommand({
|
|
|
540
566
|
meta: { name: "config", description: "Show and manage configuration" },
|
|
541
567
|
args: {
|
|
542
568
|
list: { type: "boolean", description: "List current configuration", default: false },
|
|
543
|
-
get: { type: "string", description: "Get a configuration value by key" },
|
|
544
|
-
unset: { type: "string", description: "Unset an optional configuration key or whole embedding/llm section" },
|
|
545
|
-
set: { type: "string", description: "Back-compat alias for updating a key (key=value format)" },
|
|
546
569
|
},
|
|
547
570
|
subCommands: {
|
|
548
571
|
path: defineCommand({
|
|
@@ -631,30 +654,7 @@ const configCommand = defineCommand({
|
|
|
631
654
|
output("config", listConfig(loadConfig()));
|
|
632
655
|
return;
|
|
633
656
|
}
|
|
634
|
-
|
|
635
|
-
output("config", getConfigValue(loadConfig(), args.get));
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
if (args.unset) {
|
|
639
|
-
const updated = unsetConfigValue(loadConfig(), args.unset);
|
|
640
|
-
saveConfig(updated);
|
|
641
|
-
output("config", listConfig(updated));
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
if (args.set) {
|
|
645
|
-
const eqIndex = args.set.indexOf("=");
|
|
646
|
-
if (eqIndex === -1) {
|
|
647
|
-
throw new UsageError("--set expects key=value format");
|
|
648
|
-
}
|
|
649
|
-
const key = args.set.slice(0, eqIndex);
|
|
650
|
-
const value = args.set.slice(eqIndex + 1);
|
|
651
|
-
const config = setConfigValue(loadConfig(), key, value);
|
|
652
|
-
saveConfig(config);
|
|
653
|
-
output("config", listConfig(config));
|
|
654
|
-
}
|
|
655
|
-
else {
|
|
656
|
-
output("config", listConfig(loadConfig()));
|
|
657
|
-
}
|
|
657
|
+
output("config", listConfig(loadConfig()));
|
|
658
658
|
});
|
|
659
659
|
},
|
|
660
660
|
});
|
|
@@ -664,7 +664,7 @@ const cloneCommand = defineCommand({
|
|
|
664
664
|
description: "Clone an asset from any stash source into the working stash or a custom destination",
|
|
665
665
|
},
|
|
666
666
|
args: {
|
|
667
|
-
ref: { type: "positional", description: "Asset ref (e.g.
|
|
667
|
+
ref: { type: "positional", description: "Asset ref (e.g. npm:@scope/pkg//script:deploy.sh)", required: true },
|
|
668
668
|
name: { type: "string", description: "New name for the cloned asset" },
|
|
669
669
|
force: { type: "boolean", description: "Overwrite if asset already exists in working stash", default: false },
|
|
670
670
|
dest: { type: "string", description: "Destination directory (default: working stash)" },
|
|
@@ -681,15 +681,110 @@ const cloneCommand = defineCommand({
|
|
|
681
681
|
});
|
|
682
682
|
},
|
|
683
683
|
});
|
|
684
|
+
const registryCommand = defineCommand({
|
|
685
|
+
meta: { name: "registry", description: "Manage kit registries" },
|
|
686
|
+
subCommands: {
|
|
687
|
+
list: defineCommand({
|
|
688
|
+
meta: { name: "list", description: "List configured registries" },
|
|
689
|
+
run() {
|
|
690
|
+
return runWithJsonErrors(() => {
|
|
691
|
+
const config = loadConfig();
|
|
692
|
+
const registries = config.registries ?? [];
|
|
693
|
+
output("registry-list", { registries });
|
|
694
|
+
});
|
|
695
|
+
},
|
|
696
|
+
}),
|
|
697
|
+
add: defineCommand({
|
|
698
|
+
meta: { name: "add", description: "Add a registry by URL" },
|
|
699
|
+
args: {
|
|
700
|
+
url: { type: "positional", description: "Registry index URL", required: true },
|
|
701
|
+
name: { type: "string", description: "Human-friendly name for the registry" },
|
|
702
|
+
provider: { type: "string", description: "Provider type (e.g. static-index, skills-sh)" },
|
|
703
|
+
},
|
|
704
|
+
run({ args }) {
|
|
705
|
+
return runWithJsonErrors(() => {
|
|
706
|
+
if (!args.url.startsWith("http")) {
|
|
707
|
+
throw new UsageError("Registry URL must start with http:// or https://");
|
|
708
|
+
}
|
|
709
|
+
const config = loadConfig();
|
|
710
|
+
const registries = [...(config.registries ?? [])];
|
|
711
|
+
// Deduplicate by URL
|
|
712
|
+
if (registries.some((r) => r.url === args.url)) {
|
|
713
|
+
output("registry-add", { registries, added: false, message: "Registry URL already configured" });
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const entry = { url: args.url };
|
|
717
|
+
if (args.name)
|
|
718
|
+
entry.name = args.name;
|
|
719
|
+
if (args.provider)
|
|
720
|
+
entry.provider = args.provider;
|
|
721
|
+
registries.push(entry);
|
|
722
|
+
saveConfig({ ...config, registries });
|
|
723
|
+
output("registry-add", { registries, added: true });
|
|
724
|
+
});
|
|
725
|
+
},
|
|
726
|
+
}),
|
|
727
|
+
remove: defineCommand({
|
|
728
|
+
meta: { name: "remove", description: "Remove a registry by URL or name" },
|
|
729
|
+
args: {
|
|
730
|
+
target: { type: "positional", description: "Registry URL or name to remove", required: true },
|
|
731
|
+
},
|
|
732
|
+
run({ args }) {
|
|
733
|
+
return runWithJsonErrors(() => {
|
|
734
|
+
const config = loadConfig();
|
|
735
|
+
const registries = [...(config.registries ?? [])];
|
|
736
|
+
const idx = registries.findIndex((r) => r.url === args.target || r.name === args.target);
|
|
737
|
+
if (idx === -1) {
|
|
738
|
+
output("registry-remove", { registries, removed: false, message: "No matching registry found" });
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const removed = registries.splice(idx, 1)[0];
|
|
742
|
+
saveConfig({ ...config, registries });
|
|
743
|
+
output("registry-remove", { registries, removed: true, entry: removed });
|
|
744
|
+
});
|
|
745
|
+
},
|
|
746
|
+
}),
|
|
747
|
+
search: defineCommand({
|
|
748
|
+
meta: { name: "search", description: "Search enabled registries for kits" },
|
|
749
|
+
args: {
|
|
750
|
+
query: { type: "positional", description: "Search query", required: true },
|
|
751
|
+
limit: { type: "string", description: "Maximum number of results" },
|
|
752
|
+
assets: { type: "boolean", description: "Include asset-level search results", default: false },
|
|
753
|
+
},
|
|
754
|
+
async run({ args }) {
|
|
755
|
+
await runWithJsonErrors(async () => {
|
|
756
|
+
const limit = args.limit ? parseInt(args.limit, 10) : undefined;
|
|
757
|
+
const result = await searchRegistry(args.query, { limit, includeAssets: args.assets });
|
|
758
|
+
output("registry-search", result);
|
|
759
|
+
});
|
|
760
|
+
},
|
|
761
|
+
}),
|
|
762
|
+
},
|
|
763
|
+
});
|
|
684
764
|
const sourcesCommand = defineCommand({
|
|
685
765
|
meta: { name: "sources", description: "List all stash search paths and their status" },
|
|
686
766
|
run() {
|
|
687
767
|
return runWithJsonErrors(() => {
|
|
768
|
+
const config = loadConfig();
|
|
688
769
|
const sources = resolveStashSources();
|
|
689
|
-
|
|
770
|
+
const registries = config.registries ?? [];
|
|
771
|
+
output("sources", { sources, registries });
|
|
690
772
|
});
|
|
691
773
|
},
|
|
692
774
|
});
|
|
775
|
+
const hintsCommand = defineCommand({
|
|
776
|
+
meta: {
|
|
777
|
+
name: "hints",
|
|
778
|
+
description: "Print agent instructions on how to use akm, use --detail full for a complete guide",
|
|
779
|
+
},
|
|
780
|
+
args: {
|
|
781
|
+
detail: { type: "string", description: "Detail level (normal|full)", default: "normal" },
|
|
782
|
+
},
|
|
783
|
+
run({ args }) {
|
|
784
|
+
const detail = args.detail === "full" ? "full" : "normal";
|
|
785
|
+
process.stdout.write(loadHints(detail));
|
|
786
|
+
},
|
|
787
|
+
});
|
|
693
788
|
const main = defineCommand({
|
|
694
789
|
meta: {
|
|
695
790
|
name: "akm",
|
|
@@ -713,7 +808,9 @@ const main = defineCommand({
|
|
|
713
808
|
show: showCommand,
|
|
714
809
|
clone: cloneCommand,
|
|
715
810
|
sources: sourcesCommand,
|
|
811
|
+
registry: registryCommand,
|
|
716
812
|
config: configCommand,
|
|
813
|
+
hints: hintsCommand,
|
|
717
814
|
},
|
|
718
815
|
});
|
|
719
816
|
const SEARCH_SOURCES = ["local", "registry", "both"];
|
|
@@ -721,7 +818,7 @@ const CONFIG_SUBCOMMAND_SET = new Set(["path", "list", "get", "set", "unset"]);
|
|
|
721
818
|
const SHOW_VIEW_MODES = new Set(["toc", "frontmatter", "full", "section", "lines"]);
|
|
722
819
|
// citty reads process.argv directly and does not accept a custom argv array,
|
|
723
820
|
// so we must replace process.argv with the normalized version before runMain.
|
|
724
|
-
process.argv = normalizeShowArgv(
|
|
821
|
+
process.argv = normalizeShowArgv(process.argv);
|
|
725
822
|
runMain(main);
|
|
726
823
|
function parseSearchSource(value) {
|
|
727
824
|
if (SEARCH_SOURCES.includes(value))
|
|
@@ -764,7 +861,7 @@ function buildHint(message) {
|
|
|
764
861
|
return "Use `akm update --all` or pass a target like `akm update npm:@scope/pkg`.";
|
|
765
862
|
if (message.includes("Specify either <target> or --all"))
|
|
766
863
|
return "Use only one: a positional target or `--all`.";
|
|
767
|
-
if (message.includes("No installed
|
|
864
|
+
if (message.includes("No installed kit matched target"))
|
|
768
865
|
return "Run `akm list` to view installed ids/refs, then retry with one of those values.";
|
|
769
866
|
if (message.includes("remote package fetched but asset not found"))
|
|
770
867
|
return "The remote package was fetched but doesn't contain the requested asset. Check the asset name and type.";
|
|
@@ -783,83 +880,25 @@ function hasConfigSubcommand(args) {
|
|
|
783
880
|
const command = Array.isArray(args._) ? args._[0] : undefined;
|
|
784
881
|
return typeof command === "string" && CONFIG_SUBCOMMAND_SET.has(command);
|
|
785
882
|
}
|
|
786
|
-
/**
|
|
787
|
-
* Normalize argv before citty parses it so git-style config forms like
|
|
788
|
-
* `akm config llm.maxTokens 512` and `akm config --get llm.maxTokens`
|
|
789
|
-
* are normalized into the existing config subcommands.
|
|
790
|
-
*
|
|
791
|
-
* Returns a new array; the input is never modified.
|
|
792
|
-
*/
|
|
793
|
-
function normalizeConfigArgv(argv) {
|
|
794
|
-
// Global flags should not be treated as config subcommand arguments.
|
|
795
|
-
// We strip them from the analysis portion, normalize, then re-append them.
|
|
796
|
-
const globalFlags = [];
|
|
797
|
-
const configArgs = [];
|
|
798
|
-
for (let i = 3; i < argv.length; i++) {
|
|
799
|
-
const arg = argv[i];
|
|
800
|
-
if (arg === "--quiet" || arg === "-q") {
|
|
801
|
-
globalFlags.push(arg);
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
if (arg.startsWith("--format=") || arg.startsWith("--detail=")) {
|
|
805
|
-
globalFlags.push(arg);
|
|
806
|
-
continue;
|
|
807
|
-
}
|
|
808
|
-
if (arg === "--format" || arg === "--detail") {
|
|
809
|
-
globalFlags.push(arg);
|
|
810
|
-
if (argv[i + 1] !== undefined) {
|
|
811
|
-
globalFlags.push(argv[i + 1]);
|
|
812
|
-
i++;
|
|
813
|
-
}
|
|
814
|
-
continue;
|
|
815
|
-
}
|
|
816
|
-
configArgs.push(arg);
|
|
817
|
-
}
|
|
818
|
-
const [command, argAfterCommand, argAfterKey, ...rest] = [argv[2], ...configArgs];
|
|
819
|
-
if (command !== "config")
|
|
820
|
-
return argv;
|
|
821
|
-
if (!argAfterCommand)
|
|
822
|
-
return argv;
|
|
823
|
-
const prefix = argv.slice(0, 3);
|
|
824
|
-
const buildResult = (...newArgs) => [...prefix, ...newArgs, ...globalFlags];
|
|
825
|
-
if (argAfterCommand === "--list") {
|
|
826
|
-
return buildResult("list");
|
|
827
|
-
}
|
|
828
|
-
if (argAfterCommand === "--get" && argAfterKey) {
|
|
829
|
-
return buildResult("get", argAfterKey, ...rest);
|
|
830
|
-
}
|
|
831
|
-
if (argAfterCommand === "--unset" && argAfterKey) {
|
|
832
|
-
return buildResult("unset", argAfterKey, ...rest);
|
|
833
|
-
}
|
|
834
|
-
if (argAfterCommand.startsWith("-"))
|
|
835
|
-
return argv;
|
|
836
|
-
if (CONFIG_SUBCOMMAND_SET.has(argAfterCommand))
|
|
837
|
-
return argv;
|
|
838
|
-
// A single arg after `config` behaves like `git config <key>` and reads the value.
|
|
839
|
-
if (argAfterKey === undefined) {
|
|
840
|
-
return buildResult("get", argAfterCommand);
|
|
841
|
-
}
|
|
842
|
-
return buildResult("set", argAfterCommand, argAfterKey, ...rest);
|
|
843
|
-
}
|
|
844
883
|
/**
|
|
845
884
|
* Normalize argv so positional view-mode arguments after the asset ref
|
|
846
|
-
* are rewritten into
|
|
885
|
+
* are rewritten into internal flags that citty can parse.
|
|
847
886
|
*
|
|
848
887
|
* Converts:
|
|
849
|
-
* akm show knowledge:guide.md toc → akm show knowledge:guide.md --
|
|
850
|
-
* akm show knowledge:guide.md section Auth
|
|
851
|
-
* akm show knowledge:guide.md lines 1 50
|
|
888
|
+
* akm show knowledge:guide.md toc → akm show knowledge:guide.md --akmView toc
|
|
889
|
+
* akm show knowledge:guide.md section Auth → akm show knowledge:guide.md --akmView section --akmHeading Auth
|
|
890
|
+
* akm show knowledge:guide.md lines 1 50 → akm show knowledge:guide.md --akmView lines --akmStart 1 --akmEnd 50
|
|
852
891
|
*
|
|
853
|
-
*
|
|
892
|
+
* Legacy `--view` is intentionally unsupported.
|
|
854
893
|
* Returns a new array; the input is never modified.
|
|
855
894
|
*/
|
|
856
895
|
function normalizeShowArgv(argv) {
|
|
857
896
|
// argv[0]=bun argv[1]=script argv[2]=subcommand argv[3]=ref argv[4..]=rest
|
|
858
897
|
if (argv[2] !== "show")
|
|
859
898
|
return argv;
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
899
|
+
if (argv.includes("--view") || argv.includes("--heading") || argv.includes("--start") || argv.includes("--end")) {
|
|
900
|
+
throw new UsageError('Legacy show flags are no longer supported. Use positional syntax like `akm show knowledge:guide toc` or `akm show knowledge:guide section "Auth"`.');
|
|
901
|
+
}
|
|
863
902
|
// Separate global flags from positional/show-specific args
|
|
864
903
|
const prefix = argv.slice(0, 3); // [bun, script, show]
|
|
865
904
|
const rest = argv.slice(3);
|
|
@@ -891,22 +930,186 @@ function normalizeShowArgv(argv) {
|
|
|
891
930
|
if (!ref || !viewMode || !SHOW_VIEW_MODES.has(viewMode)) {
|
|
892
931
|
return argv;
|
|
893
932
|
}
|
|
894
|
-
const result = [...prefix, ref, "--
|
|
933
|
+
const result = [...prefix, ref, "--akmView", viewMode];
|
|
895
934
|
if (viewMode === "section") {
|
|
896
935
|
// Next arg is the heading name; pass empty string when missing so the
|
|
897
936
|
// show handler can produce a clear "section not found" error.
|
|
898
937
|
const heading = showArgs[2] ?? "";
|
|
899
|
-
result.push("--
|
|
938
|
+
result.push("--akmHeading", heading);
|
|
900
939
|
}
|
|
901
940
|
else if (viewMode === "lines") {
|
|
902
941
|
// Next two args are start and end
|
|
903
942
|
const start = showArgs[2];
|
|
904
943
|
const end = showArgs[3];
|
|
905
944
|
if (start)
|
|
906
|
-
result.push("--
|
|
945
|
+
result.push("--akmStart", start);
|
|
907
946
|
if (end)
|
|
908
|
-
result.push("--
|
|
947
|
+
result.push("--akmEnd", end);
|
|
909
948
|
}
|
|
910
949
|
result.push(...globalFlags);
|
|
911
950
|
return result;
|
|
912
951
|
}
|
|
952
|
+
// ── Hints (embedded AGENTS.md) ──────────────────────────────────────────────
|
|
953
|
+
function loadHints(detail = "normal") {
|
|
954
|
+
const filename = detail === "full" ? "AGENTS.full.md" : "AGENTS.md";
|
|
955
|
+
const fallback = detail === "full" ? EMBEDDED_HINTS_FULL : EMBEDDED_HINTS;
|
|
956
|
+
// Try reading from the docs/ directory (works in dev and when installed via npm)
|
|
957
|
+
try {
|
|
958
|
+
const docsPath = path.resolve(import.meta.dir ?? __dirname, `../docs/${filename}`);
|
|
959
|
+
if (fs.existsSync(docsPath)) {
|
|
960
|
+
return fs.readFileSync(docsPath, "utf8");
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
catch {
|
|
964
|
+
// fall through
|
|
965
|
+
}
|
|
966
|
+
// Fallback for compiled binary — inline content
|
|
967
|
+
return fallback;
|
|
968
|
+
}
|
|
969
|
+
const EMBEDDED_HINTS = `# akm CLI
|
|
970
|
+
|
|
971
|
+
You have access to a searchable library of scripts, skills, commands, agents, and knowledge documents via \`akm\`. Search the stash first before writing something from scratch.
|
|
972
|
+
|
|
973
|
+
## Quick Reference
|
|
974
|
+
|
|
975
|
+
\`\`\`sh
|
|
976
|
+
akm search "<query>" # Search for assets
|
|
977
|
+
akm search "<query>" --type skill # Filter by type
|
|
978
|
+
akm search "<query>" --source both # Search registries and local stashes for assets
|
|
979
|
+
akm show <ref> # View asset details
|
|
980
|
+
akm add <ref> # Install a kit (npm, GitHub, git, local)
|
|
981
|
+
akm clone <ref> # Copy an asset to the working stash (optional --dest arg to clone to specific location)
|
|
982
|
+
akm registry search "<query>" # Search all registries
|
|
983
|
+
\`\`\`
|
|
984
|
+
|
|
985
|
+
## Primary Asset Types
|
|
986
|
+
|
|
987
|
+
| Type | What \`akm show\` returns |
|
|
988
|
+
| --- | --- |
|
|
989
|
+
| script | A \`run\` command you can execute directly |
|
|
990
|
+
| skill | Instructions to follow (read the full content) |
|
|
991
|
+
| command | A prompt template with placeholders to fill in |
|
|
992
|
+
| agent | A system prompt with model and tool hints |
|
|
993
|
+
| knowledge | A reference doc (use \`toc\` or \`section "..."\` to navigate) |
|
|
994
|
+
|
|
995
|
+
Run \`akm -h\` for the full command reference.
|
|
996
|
+
`;
|
|
997
|
+
const EMBEDDED_HINTS_FULL = `# akm CLI — Full Reference
|
|
998
|
+
|
|
999
|
+
You have access to a searchable library of scripts, skills, commands, agents, and knowledge documents via \`akm\`. Search the stash first before writing something from scratch.
|
|
1000
|
+
|
|
1001
|
+
## Search
|
|
1002
|
+
|
|
1003
|
+
\`\`\`sh
|
|
1004
|
+
akm search "<query>" # Search local stash
|
|
1005
|
+
akm search "<query>" --type skill # Filter by asset type
|
|
1006
|
+
akm search "<query>" --source both # Search local stash and registries
|
|
1007
|
+
akm search "<query>" --source registry # Search registries only
|
|
1008
|
+
akm search "<query>" --limit 10 # Limit results
|
|
1009
|
+
akm search "<query>" --detail full # Include scores, paths, timing
|
|
1010
|
+
\`\`\`
|
|
1011
|
+
|
|
1012
|
+
| Flag | Values | Default |
|
|
1013
|
+
| --- | --- | --- |
|
|
1014
|
+
| \`--type\` | \`skill\`, \`command\`, \`agent\`, \`knowledge\`, \`script\`, \`any\` | \`any\` |
|
|
1015
|
+
| \`--source\` | \`local\`, \`registry\`, \`both\` | \`local\` |
|
|
1016
|
+
| \`--limit\` | number | \`20\` |
|
|
1017
|
+
| \`--format\` | \`json\`, \`text\`, \`yaml\` | \`json\` |
|
|
1018
|
+
| \`--detail\` | \`brief\`, \`normal\`, \`full\` | \`brief\` |
|
|
1019
|
+
|
|
1020
|
+
## Show
|
|
1021
|
+
|
|
1022
|
+
Display an asset by ref. Knowledge assets support view modes as positional arguments.
|
|
1023
|
+
|
|
1024
|
+
\`\`\`sh
|
|
1025
|
+
akm show script:deploy.sh # Show script (returns run command)
|
|
1026
|
+
akm show skill:code-review # Show skill (returns full content)
|
|
1027
|
+
akm show command:release # Show command (returns template)
|
|
1028
|
+
akm show agent:architect # Show agent (returns system prompt)
|
|
1029
|
+
akm show knowledge:guide toc # Table of contents
|
|
1030
|
+
akm show knowledge:guide section "Auth" # Specific section
|
|
1031
|
+
akm show knowledge:guide lines 10 30 # Line range
|
|
1032
|
+
\`\`\`
|
|
1033
|
+
|
|
1034
|
+
| Type | Key fields returned |
|
|
1035
|
+
| --- | --- |
|
|
1036
|
+
| script | \`run\`, \`setup\`, \`cwd\` |
|
|
1037
|
+
| skill | \`content\` (full SKILL.md) |
|
|
1038
|
+
| command | \`template\`, \`description\`, \`parameters\` |
|
|
1039
|
+
| agent | \`prompt\`, \`description\`, \`modelHint\`, \`toolPolicy\` |
|
|
1040
|
+
| knowledge | \`content\` (with view modes: \`full\`, \`toc\`, \`frontmatter\`, \`section\`, \`lines\`) |
|
|
1041
|
+
|
|
1042
|
+
## Install & Manage Kits
|
|
1043
|
+
|
|
1044
|
+
\`\`\`sh
|
|
1045
|
+
akm add <ref> # Install a kit
|
|
1046
|
+
akm add @scope/kit # From npm
|
|
1047
|
+
akm add owner/repo # From GitHub
|
|
1048
|
+
akm add ./path/to/local/kit # From local directory
|
|
1049
|
+
akm list # List installed kits
|
|
1050
|
+
akm remove <target> # Remove by id or ref
|
|
1051
|
+
akm update --all # Update all installed kits
|
|
1052
|
+
akm update <target> --force # Force re-download
|
|
1053
|
+
\`\`\`
|
|
1054
|
+
|
|
1055
|
+
## Clone
|
|
1056
|
+
|
|
1057
|
+
Copy an asset to the working stash or a custom destination for editing.
|
|
1058
|
+
|
|
1059
|
+
\`\`\`sh
|
|
1060
|
+
akm clone <ref> # Clone to working stash
|
|
1061
|
+
akm clone <ref> --name new-name # Rename on clone
|
|
1062
|
+
akm clone <ref> --dest ./project/.claude # Clone to custom location
|
|
1063
|
+
akm clone <ref> --force # Overwrite existing
|
|
1064
|
+
akm clone "npm:@scope/pkg//script:deploy.sh" # Clone from remote package
|
|
1065
|
+
\`\`\`
|
|
1066
|
+
|
|
1067
|
+
When \`--dest\` is provided, \`akm init\` is not required first.
|
|
1068
|
+
|
|
1069
|
+
## Registries
|
|
1070
|
+
|
|
1071
|
+
\`\`\`sh
|
|
1072
|
+
akm registry list # List configured registries
|
|
1073
|
+
akm registry add <url> # Add a registry
|
|
1074
|
+
akm registry add <url> --name my-team # Add with label
|
|
1075
|
+
akm registry add <url> --provider skills-sh # Specify provider type
|
|
1076
|
+
akm registry remove <url-or-name> # Remove a registry
|
|
1077
|
+
akm registry search "<query>" # Search all registries
|
|
1078
|
+
akm registry search "<query>" --assets # Include asset-level results
|
|
1079
|
+
\`\`\`
|
|
1080
|
+
|
|
1081
|
+
## Configuration
|
|
1082
|
+
|
|
1083
|
+
\`\`\`sh
|
|
1084
|
+
akm config list # Show current config
|
|
1085
|
+
akm config get <key> # Read a value
|
|
1086
|
+
akm config set <key> <value> # Set a value
|
|
1087
|
+
akm config unset <key> # Remove a key
|
|
1088
|
+
akm config path --all # Show all config paths
|
|
1089
|
+
\`\`\`
|
|
1090
|
+
|
|
1091
|
+
## Other Commands
|
|
1092
|
+
|
|
1093
|
+
\`\`\`sh
|
|
1094
|
+
akm init # Initialize stash directory
|
|
1095
|
+
akm index # Rebuild search index
|
|
1096
|
+
akm index --full # Full reindex
|
|
1097
|
+
akm sources # List stash search paths
|
|
1098
|
+
akm upgrade # Upgrade akm binary
|
|
1099
|
+
akm upgrade --check # Check for updates
|
|
1100
|
+
akm hints # Print this reference
|
|
1101
|
+
\`\`\`
|
|
1102
|
+
|
|
1103
|
+
## Output Control
|
|
1104
|
+
|
|
1105
|
+
All commands accept \`--format\` and \`--detail\` flags:
|
|
1106
|
+
|
|
1107
|
+
- \`--format json\` (default) — structured JSON
|
|
1108
|
+
- \`--format text\` — human-readable plain text
|
|
1109
|
+
- \`--format yaml\` — YAML output
|
|
1110
|
+
- \`--detail brief\` (default) — compact output
|
|
1111
|
+
- \`--detail normal\` — adds tags, refs, origins
|
|
1112
|
+
- \`--detail full\` — includes scores, paths, timing, debug info
|
|
1113
|
+
|
|
1114
|
+
Run \`akm -h\` or \`akm <command> -h\` for per-command help.
|
|
1115
|
+
`;
|
package/dist/common.js
CHANGED
|
@@ -3,13 +3,6 @@ import path from "node:path";
|
|
|
3
3
|
import { TYPE_DIRS } from "./asset-spec";
|
|
4
4
|
import { ConfigError } from "./errors";
|
|
5
5
|
import { getConfigPath, getDefaultStashDir } from "./paths";
|
|
6
|
-
/**
|
|
7
|
-
* Normalize an asset type for output purposes.
|
|
8
|
-
* "tool" is a transparent alias for "script" -- all output should use "script".
|
|
9
|
-
*/
|
|
10
|
-
export function normalizeAssetType(type) {
|
|
11
|
-
return type === "tool" ? "script" : type;
|
|
12
|
-
}
|
|
13
6
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
14
7
|
export const IS_WINDOWS = process.platform === "win32";
|
|
15
8
|
// ── Validators ──────────────────────────────────────────────────────────────
|