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/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). 'tool' is accepted as alias for 'script'.",
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 registry packages from config" },
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 registry package by id or ref" },
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 registry packages" },
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
- // These flags are kept for backward compatibility (--view toc still works)
504
- // but the preferred syntax is positional: akm show ref toc
505
- view: { type: "string", description: "Knowledge view mode (full|toc|frontmatter|section|lines)" },
506
- heading: { type: "string", description: "Section heading (for section view)" },
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.view) {
514
- switch (args.view) {
539
+ if (args.akmView) {
540
+ switch (args.akmView) {
515
541
  case "section":
516
- view = { mode: "section", heading: args.heading ?? "" };
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.start ?? "1"),
522
- end: args.end ? parseInt(args.end, 10) : Number.MAX_SAFE_INTEGER,
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.view };
554
+ view = { mode: args.akmView };
529
555
  break;
530
556
  default:
531
- throw new UsageError(`Unknown view mode: ${args.view}. Expected one of: full|toc|frontmatter|section|lines`);
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
- if (args.get) {
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. @installed:pkg/tool:script.sh)", required: true },
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
- output("sources", { sources });
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(normalizeConfigArgv(process.argv));
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 registry entry matched target"))
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 the flag form that citty can parse.
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 --view toc
850
- * akm show knowledge:guide.md section Auth → akm show knowledge:guide.md --view section --heading Auth
851
- * akm show knowledge:guide.md lines 1 50 → akm show knowledge:guide.md --view lines --start 1 --end 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
- * If --view is already present the argv is returned unchanged (backward compat).
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
- // If --view is already present, pass through unchanged
861
- if (argv.includes("--view"))
862
- return argv;
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, "--view", viewMode];
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("--heading", heading);
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("--start", start);
945
+ result.push("--akmStart", start);
907
946
  if (end)
908
- result.push("--end", end);
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 ──────────────────────────────────────────────────────────────