akm-cli 0.0.22 → 0.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agent Kit Manager
2
2
 
3
- > Agent-i-Kit
3
+ > **akm** — Agent Kit Manager
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/akm-cli)](https://www.npmjs.com/package/akm-cli)
6
6
  [![CI](https://github.com/itlackey/agentikit/actions/workflows/ci.yml/badge.svg)](https://github.com/itlackey/agentikit/actions/workflows/ci.yml)
@@ -25,7 +25,7 @@ Upgrade in place with `akm upgrade`.
25
25
  ## Quick Start
26
26
 
27
27
  ```sh
28
- akm init # Initialize your stash
28
+ akm init # Initialize your working stash
29
29
  akm add github:owner/repo # Add a kit from GitHub
30
30
  akm search "deploy" # Find assets
31
31
  akm show script:deploy.sh # View details and run command
@@ -89,7 +89,7 @@ Registries are indexes of available kits. The official
89
89
  ```sh
90
90
  akm registry search "code review" # Search registries
91
91
  akm registry add https://example.com/registry/index.json --name team # Add a registry
92
- akm sources add http://host:1933 --provider openviking \
92
+ akm stash add http://host:1933 --provider openviking \
93
93
  --options '{"apiKey":"key"}' # Add an OpenViking stash source
94
94
  akm registry list # List configured registries
95
95
  akm show viking://resources/my-doc # Fetch remote content from OpenViking
@@ -130,7 +130,7 @@ See the [Kit Maker's Guide](docs/kit-makers.md) for a full walkthrough.
130
130
  | [Getting Started](docs/getting-started.md) | Quick setup guide |
131
131
  | [CLI Reference](docs/cli.md) | All commands and flags |
132
132
  | [Configuration](docs/configuration.md) | Settings, providers, and Ollama setup |
133
- | [Concepts](docs/concepts.md) | Asset types, classification, stash model |
133
+ | [Concepts](docs/concepts.md) | Stashes, kits, registries, asset types |
134
134
  | [Kit Maker's Guide](docs/kit-makers.md) | Build and share kits |
135
135
  | [Registry](docs/registry.md) | Registries, search, and the v2 index format |
136
136
 
@@ -79,7 +79,7 @@ export function _setAssetTypeHooks(rendererHook, actionBuilderHook) {
79
79
  _registerActionBuilder = actionBuilderHook;
80
80
  }
81
81
  /**
82
- * Register a custom asset type with the Agentikit asset system.
82
+ * Register a custom asset type with the akm asset system.
83
83
  *
84
84
  * ## Full extension registration API
85
85
  *
package/dist/cli.js CHANGED
@@ -6,18 +6,18 @@ import { resolveStashDir } from "./common";
6
6
  import { DEFAULT_CONFIG, getConfigPath, loadConfig, saveConfig } from "./config";
7
7
  import { getConfigValue, listConfig, setConfigValue, unsetConfigValue } from "./config-cli";
8
8
  import { ConfigError, NotFoundError, UsageError } from "./errors";
9
- import { agentikitIndex } from "./indexer";
10
- import { agentikitInit } from "./init";
11
- import { agentikitList, agentikitRemove, agentikitUpdate } from "./installed-kits";
9
+ import { akmIndex } from "./indexer";
10
+ import { akmInit } from "./init";
11
+ import { akmList, akmRemove, akmUpdate } from "./installed-kits";
12
12
  import { getCacheDir, getDbPath, getDefaultStashDir } from "./paths";
13
13
  import { buildRegistryIndex, writeRegistryIndex } from "./registry-build-index";
14
14
  import { searchRegistry } from "./registry-search";
15
15
  import { checkForUpdate, performUpgrade } from "./self-update";
16
- import { agentikitAdd } from "./stash-add";
17
- import { agentikitClone } from "./stash-clone";
18
- import { agentikitSearch, parseSearchSource } from "./stash-search";
19
- import { agentikitShowUnified } from "./stash-show";
20
- import { resolveStashSources } from "./stash-source";
16
+ import { akmAdd, akmKitAdd } from "./stash-add";
17
+ import { akmClone } from "./stash-clone";
18
+ import { akmSearch, parseSearchSource } from "./stash-search";
19
+ import { akmShowUnified } from "./stash-show";
20
+ import { addStash, listStashes, removeStash } from "./stash-source-manage";
21
21
  import { setQuiet, warn } from "./warn";
22
22
  // Version: prefer compile-time define, then package.json, then fallback
23
23
  const pkgVersion = (() => {
@@ -405,14 +405,14 @@ function formatSearchPlain(r, detail) {
405
405
  const initCommand = defineCommand({
406
406
  meta: {
407
407
  name: "init",
408
- description: "Initialize Agent-i-Kit's working stash directory and persist stashDir in config",
408
+ description: "Initialize akm's working stash directory and persist stashDir in config",
409
409
  },
410
410
  args: {
411
411
  dir: { type: "string", description: "Custom stash directory path (default: ~/akm)" },
412
412
  },
413
413
  async run({ args }) {
414
414
  await runWithJsonErrors(async () => {
415
- const result = await agentikitInit({ dir: args.dir });
415
+ const result = await akmInit({ dir: args.dir });
416
416
  output("init", result);
417
417
  });
418
418
  },
@@ -424,7 +424,7 @@ const indexCommand = defineCommand({
424
424
  },
425
425
  async run({ args }) {
426
426
  await runWithJsonErrors(async () => {
427
- const result = await agentikitIndex({ full: args.full });
427
+ const result = await akmIndex({ full: args.full });
428
428
  output("index", result);
429
429
  });
430
430
  },
@@ -451,7 +451,7 @@ const searchCommand = defineCommand({
451
451
  }
452
452
  const limit = limitRaw;
453
453
  const source = parseSearchSource(args.source);
454
- const result = await agentikitSearch({ query: args.query, type, limit, source });
454
+ const result = await akmSearch({ query: args.query, type, limit, source });
455
455
  output("search", result);
456
456
  });
457
457
  },
@@ -467,7 +467,7 @@ const addCommand = defineCommand({
467
467
  },
468
468
  async run({ args }) {
469
469
  await runWithJsonErrors(async () => {
470
- const result = await agentikitAdd({ ref: args.ref });
470
+ const result = await akmAdd({ ref: args.ref });
471
471
  output("add", result);
472
472
  });
473
473
  },
@@ -476,7 +476,7 @@ const listCommand = defineCommand({
476
476
  meta: { name: "list", description: "List installed kits" },
477
477
  async run() {
478
478
  await runWithJsonErrors(async () => {
479
- const result = await agentikitList();
479
+ const result = await akmList();
480
480
  output("list", result);
481
481
  });
482
482
  },
@@ -488,7 +488,7 @@ const removeCommand = defineCommand({
488
488
  },
489
489
  async run({ args }) {
490
490
  await runWithJsonErrors(async () => {
491
- const result = await agentikitRemove({ target: args.target });
491
+ const result = await akmRemove({ target: args.target });
492
492
  output("remove", result);
493
493
  });
494
494
  },
@@ -502,11 +502,36 @@ const updateCommand = defineCommand({
502
502
  },
503
503
  async run({ args }) {
504
504
  await runWithJsonErrors(async () => {
505
- const result = await agentikitUpdate({ target: args.target, all: args.all, force: args.force });
505
+ const result = await akmUpdate({ target: args.target, all: args.all, force: args.force });
506
506
  output("update", result);
507
507
  });
508
508
  },
509
509
  });
510
+ const kitAddCommand = defineCommand({
511
+ meta: { name: "add", description: "Install a kit from npm, GitHub, or any git host" },
512
+ args: {
513
+ ref: {
514
+ type: "positional",
515
+ description: "Registry ref (npm package, owner/repo, or git URL)",
516
+ required: true,
517
+ },
518
+ },
519
+ async run({ args }) {
520
+ await runWithJsonErrors(async () => {
521
+ const result = await akmKitAdd({ ref: args.ref });
522
+ output("add", result);
523
+ });
524
+ },
525
+ });
526
+ const kitCommand = defineCommand({
527
+ meta: { name: "kit", description: "Manage installed kits" },
528
+ subCommands: {
529
+ add: kitAddCommand,
530
+ list: listCommand,
531
+ remove: removeCommand,
532
+ update: updateCommand,
533
+ },
534
+ });
510
535
  const upgradeCommand = defineCommand({
511
536
  meta: { name: "upgrade", description: "Upgrade akm to the latest release" },
512
537
  args: {
@@ -568,7 +593,7 @@ const showCommand = defineCommand({
568
593
  throw new UsageError(`Unknown view mode: ${args.akmView}. Expected one of: full|toc|frontmatter|section|lines`);
569
594
  }
570
595
  }
571
- const result = await agentikitShowUnified({ ref: args.ref, view });
596
+ const result = await akmShowUnified({ ref: args.ref, view });
572
597
  output("show", result);
573
598
  });
574
599
  },
@@ -672,7 +697,7 @@ const configCommand = defineCommand({
672
697
  const cloneCommand = defineCommand({
673
698
  meta: {
674
699
  name: "clone",
675
- description: "Clone an asset from any stash source into the working stash or a custom destination",
700
+ description: "Clone an asset from any source into the working stash or a custom destination",
676
701
  },
677
702
  args: {
678
703
  ref: { type: "positional", description: "Asset ref (e.g. npm:@scope/pkg//script:deploy.sh)", required: true },
@@ -682,7 +707,7 @@ const cloneCommand = defineCommand({
682
707
  },
683
708
  async run({ args }) {
684
709
  await runWithJsonErrors(async () => {
685
- const result = await agentikitClone({
710
+ const result = await akmClone({
686
711
  sourceRef: args.ref,
687
712
  newName: args.name,
688
713
  force: args.force,
@@ -814,28 +839,21 @@ const registryCommand = defineCommand({
814
839
  }),
815
840
  },
816
841
  });
817
- const sourcesCommand = defineCommand({
818
- meta: { name: "sources", description: "Manage stash sources (local paths and remote providers)" },
819
- subCommands: {
842
+ /**
843
+ * Subcommand definitions for managing additional stashes.
844
+ */
845
+ function buildSourceSubCommands(outputPrefix) {
846
+ return {
820
847
  list: defineCommand({
821
- meta: { name: "list", description: "List all stash sources" },
848
+ meta: { name: "list", description: "List all stashes in search order" },
822
849
  run() {
823
850
  return runWithJsonErrors(() => {
824
- const config = loadConfig();
825
- const localSources = resolveStashSources();
826
- const stashes = config.stashes ?? [];
827
- // Legacy fallback: show remoteStashSources if no stashes config
828
- const legacyRemote = !config.stashes ? (config.remoteStashSources ?? []) : [];
829
- output("sources", {
830
- localSources,
831
- stashes,
832
- ...(legacyRemote.length > 0 ? { remoteSources: legacyRemote } : {}),
833
- });
851
+ output(`${outputPrefix}`, listStashes());
834
852
  });
835
853
  },
836
854
  }),
837
855
  add: defineCommand({
838
- meta: { name: "add", description: "Add a stash source (filesystem path or remote URL)" },
856
+ meta: { name: "add", description: "Register an additional stash (filesystem path or remote URL)" },
839
857
  args: {
840
858
  target: { type: "positional", description: "Path or URL to add", required: true },
841
859
  name: { type: "string", description: "Human-friendly name for the source" },
@@ -844,75 +862,51 @@ const sourcesCommand = defineCommand({
844
862
  },
845
863
  run({ args }) {
846
864
  return runWithJsonErrors(() => {
847
- const config = loadConfig();
848
- const stashes = [...(config.stashes ?? [])];
849
- const isUrl = args.target.startsWith("http://") || args.target.startsWith("https://");
850
- if (isUrl) {
851
- if (args.target.startsWith("http://")) {
852
- warn("Warning: source URL uses plain HTTP (not HTTPS). For security, prefer https:// to protect against eavesdropping and tampering.");
853
- }
854
- const providerType = args.provider;
855
- if (!providerType) {
856
- throw new UsageError("--provider is required for URL sources (e.g. --provider openviking)");
857
- }
858
- if (stashes.some((s) => s.url === args.target)) {
859
- output("sources-add", { stashes, added: false, message: "Source URL already configured" });
860
- return;
861
- }
862
- const entry = { type: providerType, url: args.target };
863
- if (args.name)
864
- entry.name = args.name;
865
- if (args.options) {
866
- try {
867
- entry.options = JSON.parse(args.options);
868
- }
869
- catch {
870
- throw new UsageError("--options must be valid JSON");
865
+ if (args.target.startsWith("http://")) {
866
+ warn("Warning: source URL uses plain HTTP (not HTTPS). For security, prefer https:// to protect against eavesdropping and tampering.");
867
+ }
868
+ let parsedOptions;
869
+ if (args.options) {
870
+ try {
871
+ const parsed = JSON.parse(args.options);
872
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
873
+ throw new UsageError("--options must be a JSON object");
871
874
  }
875
+ parsedOptions = parsed;
872
876
  }
873
- stashes.push(entry);
874
- }
875
- else {
876
- // Filesystem path
877
- const resolvedPath = path.resolve(args.target);
878
- if (stashes.some((s) => s.path === resolvedPath)) {
879
- output("sources-add", { stashes, added: false, message: "Source path already configured" });
880
- return;
877
+ catch (err) {
878
+ if (err instanceof UsageError)
879
+ throw err;
880
+ throw new UsageError("--options must be valid JSON");
881
881
  }
882
- const entry = { type: "filesystem", path: resolvedPath };
883
- if (args.name)
884
- entry.name = args.name;
885
- stashes.push(entry);
886
882
  }
887
- // Migrate: remove remoteStashSources when moving to stashes
888
- const { remoteStashSources, ...rest } = config;
889
- saveConfig({ ...rest, stashes });
890
- output("sources-add", { stashes, added: true });
883
+ const result = addStash({
884
+ target: args.target,
885
+ name: args.name,
886
+ providerType: args.provider,
887
+ options: parsedOptions,
888
+ });
889
+ output(`${outputPrefix}-add`, result);
891
890
  });
892
891
  },
893
892
  }),
894
893
  remove: defineCommand({
895
- meta: { name: "remove", description: "Remove a stash source by URL, path, or name" },
894
+ meta: { name: "remove", description: "Remove an additional stash by URL, path, or name" },
896
895
  args: {
897
896
  target: { type: "positional", description: "Source URL, path, or name to remove", required: true },
898
897
  },
899
898
  run({ args }) {
900
899
  return runWithJsonErrors(() => {
901
- const config = loadConfig();
902
- const stashes = [...(config.stashes ?? [])];
903
- const resolvedTarget = args.target.startsWith("http") ? args.target : path.resolve(args.target);
904
- const idx = stashes.findIndex((s) => s.url === resolvedTarget || s.path === resolvedTarget || s.name === resolvedTarget);
905
- if (idx === -1) {
906
- output("sources-remove", { stashes, removed: false, message: "No matching source found" });
907
- return;
908
- }
909
- const removed = stashes.splice(idx, 1)[0];
910
- saveConfig({ ...config, stashes });
911
- output("sources-remove", { stashes, removed: true, entry: removed });
900
+ const result = removeStash(args.target);
901
+ output(`${outputPrefix}-remove`, result);
912
902
  });
913
903
  },
914
904
  }),
915
- },
905
+ };
906
+ }
907
+ const stashCommand = defineCommand({
908
+ meta: { name: "stash", description: "Manage additional stashes (local directories and remote providers)" },
909
+ subCommands: buildSourceSubCommands("stash"),
916
910
  });
917
911
  const hintsCommand = defineCommand({
918
912
  meta: {
@@ -931,7 +925,7 @@ const main = defineCommand({
931
925
  meta: {
932
926
  name: "akm",
933
927
  version: pkgVersion,
934
- description: "CLI tool to search, open, and manage assets from Agent-i-Kit stash.",
928
+ description: "Agent Kit Manager search, show, and manage assets from your stash.",
935
929
  },
936
930
  args: {
937
931
  format: { type: "string", description: "Output format (json|text|yaml)" },
@@ -945,11 +939,12 @@ const main = defineCommand({
945
939
  list: listCommand,
946
940
  remove: removeCommand,
947
941
  update: updateCommand,
942
+ kit: kitCommand,
948
943
  upgrade: upgradeCommand,
949
944
  search: searchCommand,
950
945
  show: showCommand,
951
946
  clone: cloneCommand,
952
- sources: sourcesCommand,
947
+ stash: stashCommand,
953
948
  registry: registryCommand,
954
949
  config: configCommand,
955
950
  hints: hintsCommand,
@@ -1104,14 +1099,14 @@ function loadHints(detail = "normal") {
1104
1099
  }
1105
1100
  const EMBEDDED_HINTS = `# akm CLI
1106
1101
 
1107
- 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.
1102
+ You have access to a searchable library of scripts, skills, commands, agents, and knowledge documents via \`akm\`. Search your stashes first before writing something from scratch.
1108
1103
 
1109
1104
  ## Quick Reference
1110
1105
 
1111
1106
  \`\`\`sh
1112
- akm search "<query>" # Search for assets
1107
+ akm search "<query>" # Search your stashes and installed kits
1113
1108
  akm search "<query>" --type skill # Filter by type
1114
- akm search "<query>" --source both # Search stash providers and registries for assets
1109
+ akm search "<query>" --source both # Also search registries for installable kits
1115
1110
  akm show <ref> # View asset details
1116
1111
  akm add <ref> # Install a kit (npm, GitHub, git, local)
1117
1112
  akm clone <ref> # Copy an asset to the working stash (optional --dest arg to clone to specific location)
@@ -1132,14 +1127,14 @@ Run \`akm -h\` for the full command reference.
1132
1127
  `;
1133
1128
  const EMBEDDED_HINTS_FULL = `# akm CLI — Full Reference
1134
1129
 
1135
- 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.
1130
+ You have access to a searchable library of scripts, skills, commands, agents, and knowledge documents via \`akm\`. Search your stashes first before writing something from scratch.
1136
1131
 
1137
1132
  ## Search
1138
1133
 
1139
1134
  \`\`\`sh
1140
- akm search "<query>" # Search local stash
1135
+ akm search "<query>" # Search your stashes and installed kits
1141
1136
  akm search "<query>" --type skill # Filter by asset type
1142
- akm search "<query>" --source both # Search all stash providers and registries
1137
+ akm search "<query>" --source both # Also search registries for installable kits
1143
1138
  akm search "<query>" --source registry # Search registries only
1144
1139
  akm search "<query>" --limit 10 # Limit results
1145
1140
  akm search "<query>" --detail full # Include scores, paths, timing
@@ -1180,10 +1175,14 @@ akm show viking://resources/my-doc # Show remote OpenViking content
1180
1175
  ## Install & Manage Kits
1181
1176
 
1182
1177
  \`\`\`sh
1183
- akm add <ref> # Install a kit
1178
+ akm add <ref> # Install a kit (smart router: local dirs become stash adds)
1184
1179
  akm add @scope/kit # From npm
1185
1180
  akm add owner/repo # From GitHub
1186
- akm add ./path/to/local/kit # From local directory
1181
+ akm add ./path/to/local/kit # From local directory (adds as stash)
1182
+ akm kit add <ref> # Install a kit (explicit)
1183
+ akm kit list # List installed kits
1184
+ akm kit remove <target> # Remove a kit
1185
+ akm kit update --all # Update all kits
1187
1186
  akm list # List installed kits
1188
1187
  akm remove <target> # Remove by id or ref
1189
1188
  akm update --all # Update all installed kits
@@ -1231,10 +1230,11 @@ akm config path --all # Show all config paths
1231
1230
  ## Other Commands
1232
1231
 
1233
1232
  \`\`\`sh
1234
- akm init # Initialize stash directory
1233
+ akm init # Initialize working stash
1235
1234
  akm index # Rebuild search index
1236
1235
  akm index --full # Full reindex
1237
- akm sources # List stash search paths
1236
+ akm stash # List all stashes
1237
+ akm kit # Kit management (add, list, remove, update)
1238
1238
  akm upgrade # Upgrade akm binary
1239
1239
  akm upgrade --check # Check for updates
1240
1240
  akm hints # Print this reference
@@ -9,24 +9,12 @@ export function parseConfigValue(key, value) {
9
9
  throw new UsageError(`Invalid value for semanticSearch: expected "true" or "false"`);
10
10
  }
11
11
  return { semanticSearch: value === "true" };
12
- case "searchPaths":
13
- try {
14
- const parsed = JSON.parse(value);
15
- if (!Array.isArray(parsed))
16
- throw new UsageError("expected JSON array");
17
- return { searchPaths: parsed.filter((d) => typeof d === "string") };
18
- }
19
- catch {
20
- throw new UsageError(`Invalid value for searchPaths: expected JSON array (e.g. '["/path/a","/path/b"]')`);
21
- }
22
12
  case "embedding":
23
13
  return { embedding: parseEmbeddingConnectionValue(value) };
24
14
  case "llm":
25
15
  return { llm: parseLlmConnectionValue(value) };
26
16
  case "registries":
27
17
  return { registries: parseRegistriesValue(value) };
28
- case "remoteStashSources":
29
- return { remoteStashSources: parseStashesValue(value) };
30
18
  case "stashes":
31
19
  return { stashes: parseStashesValue(value) };
32
20
  case "output.format":
@@ -43,16 +31,12 @@ export function getConfigValue(config, key) {
43
31
  return config.stashDir ?? null;
44
32
  case "semanticSearch":
45
33
  return config.semanticSearch;
46
- case "searchPaths":
47
- return [...config.searchPaths];
48
34
  case "embedding":
49
35
  return config.embedding ?? null;
50
36
  case "llm":
51
37
  return config.llm ?? null;
52
38
  case "registries":
53
39
  return config.registries ?? DEFAULT_CONFIG.registries ?? [];
54
- case "remoteStashSources":
55
- return config.remoteStashSources ?? [];
56
40
  case "stashes":
57
41
  return config.stashes ?? [];
58
42
  case "output.format":
@@ -67,11 +51,9 @@ export function setConfigValue(config, key, rawValue) {
67
51
  switch (key) {
68
52
  case "stashDir":
69
53
  case "semanticSearch":
70
- case "searchPaths":
71
54
  case "embedding":
72
55
  case "llm":
73
56
  case "registries":
74
- case "remoteStashSources":
75
57
  case "stashes":
76
58
  case "output.format":
77
59
  case "output.detail":
@@ -90,8 +72,6 @@ export function unsetConfigValue(config, key) {
90
72
  return { ...config, llm: undefined };
91
73
  case "registries":
92
74
  return { ...config, registries: undefined };
93
- case "remoteStashSources":
94
- return { ...config, remoteStashSources: undefined };
95
75
  case "stashes":
96
76
  return { ...config, stashes: undefined };
97
77
  case "output.format":
@@ -115,11 +95,6 @@ export function listConfig(config) {
115
95
  result.embedding = config.embedding;
116
96
  if (config.llm)
117
97
  result.llm = config.llm;
118
- // Show legacy keys only if they still have content
119
- if (config.searchPaths?.length)
120
- result.searchPaths = config.searchPaths;
121
- if (config.remoteStashSources?.length)
122
- result.remoteStashSources = config.remoteStashSources;
123
98
  return result;
124
99
  }
125
100
  function mergeConfigValue(config, partial) {