agentikit 0.0.3 → 0.0.8

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.
Files changed (80) hide show
  1. package/README.md +113 -77
  2. package/dist/index.d.ts +15 -3
  3. package/dist/index.js +8 -2
  4. package/dist/src/asset-spec.d.ts +14 -0
  5. package/dist/src/asset-spec.js +46 -0
  6. package/dist/src/cli.js +154 -52
  7. package/dist/src/common.d.ts +8 -0
  8. package/dist/src/common.js +46 -0
  9. package/dist/src/config.d.ts +31 -0
  10. package/dist/src/config.js +74 -0
  11. package/dist/src/embedder.d.ts +10 -0
  12. package/dist/src/embedder.js +87 -0
  13. package/dist/src/frontmatter.d.ts +30 -0
  14. package/dist/src/frontmatter.js +86 -0
  15. package/dist/src/indexer.d.ts +20 -2
  16. package/dist/src/indexer.js +212 -80
  17. package/dist/src/init.d.ts +19 -0
  18. package/dist/src/init.js +87 -0
  19. package/dist/src/llm.d.ts +15 -0
  20. package/dist/src/llm.js +91 -0
  21. package/dist/src/markdown.d.ts +18 -0
  22. package/dist/src/markdown.js +77 -0
  23. package/dist/src/metadata.d.ts +10 -2
  24. package/dist/src/metadata.js +146 -30
  25. package/dist/src/ripgrep-install.d.ts +12 -0
  26. package/dist/src/ripgrep-install.js +169 -0
  27. package/dist/src/ripgrep-resolve.d.ts +13 -0
  28. package/dist/src/ripgrep-resolve.js +68 -0
  29. package/dist/src/ripgrep.d.ts +3 -0
  30. package/dist/src/ripgrep.js +2 -0
  31. package/dist/src/similarity.d.ts +1 -2
  32. package/dist/src/similarity.js +35 -9
  33. package/dist/src/stash-ref.d.ts +7 -0
  34. package/dist/src/stash-ref.js +33 -0
  35. package/dist/src/stash-resolve.d.ts +2 -0
  36. package/dist/src/stash-resolve.js +45 -0
  37. package/dist/src/stash-search.d.ts +6 -0
  38. package/dist/src/stash-search.js +269 -0
  39. package/dist/src/stash-show.d.ts +5 -0
  40. package/dist/src/stash-show.js +107 -0
  41. package/dist/src/stash-types.d.ts +53 -0
  42. package/dist/src/stash-types.js +1 -0
  43. package/dist/src/stash.d.ts +8 -58
  44. package/dist/src/stash.js +4 -580
  45. package/dist/src/tool-runner.d.ts +35 -0
  46. package/dist/src/tool-runner.js +100 -0
  47. package/dist/src/walker.d.ts +19 -0
  48. package/dist/src/walker.js +47 -0
  49. package/package.json +8 -14
  50. package/src/asset-spec.ts +69 -0
  51. package/src/cli.ts +164 -48
  52. package/src/common.ts +58 -0
  53. package/src/config.ts +124 -0
  54. package/src/embedder.ts +117 -0
  55. package/src/frontmatter.ts +95 -0
  56. package/src/indexer.ts +244 -84
  57. package/src/init.ts +106 -0
  58. package/src/llm.ts +124 -0
  59. package/src/markdown.ts +106 -0
  60. package/src/metadata.ts +157 -29
  61. package/src/ripgrep-install.ts +200 -0
  62. package/src/ripgrep-resolve.ts +72 -0
  63. package/src/ripgrep.ts +3 -0
  64. package/src/similarity.ts +33 -9
  65. package/src/stash-ref.ts +41 -0
  66. package/src/stash-resolve.ts +47 -0
  67. package/src/stash-search.ts +343 -0
  68. package/src/stash-show.ts +104 -0
  69. package/src/stash-types.ts +46 -0
  70. package/src/stash.ts +16 -695
  71. package/src/tool-runner.ts +129 -0
  72. package/src/walker.ts +53 -0
  73. package/.claude-plugin/plugin.json +0 -21
  74. package/commands/open.md +0 -11
  75. package/commands/run.md +0 -11
  76. package/commands/search.md +0 -11
  77. package/dist/src/plugin.d.ts +0 -2
  78. package/dist/src/plugin.js +0 -55
  79. package/skills/stash/SKILL.md +0 -68
  80. package/src/plugin.ts +0 -56
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # agentikit
2
2
 
3
- Agentikit is a stash toolkit for AI coding assistants. It exposes three tools so agents can **search**, **open**, and **run** extension assets directly from a stash directory. Works as both an **OpenCode plugin** and a **Claude Code plugin**.
3
+ Agentikit is a CLI tool and library for managing a stash of extension assets for AI coding assistants. It lets you **search** and **show** tools, skills, commands, and agents from a stash directory.
4
+
5
+ The CLI is called **akm** (Agentikit Manager).
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ### npm / bun
8
10
 
9
11
  ```sh
10
- npm install @itlackey/agentikit
12
+ npm install -g agentikit
11
13
  # or
12
- bun add @itlackey/agentikit
14
+ bun add -g agentikit
13
15
  ```
14
16
 
15
17
  ### Standalone binary
@@ -17,131 +19,165 @@ bun add @itlackey/agentikit
17
19
  Use the install scripts for a copy/paste install:
18
20
 
19
21
  ```sh
20
- # macOS / Linux (recommended: pin a release tag)
22
+ # macOS / Linux
23
+ curl -fsSL https://raw.githubusercontent.com/itlackey/agentikit/main/install.sh | bash
24
+ # pin a release tag)
21
25
  curl -fsSL https://raw.githubusercontent.com/itlackey/agentikit/main/install.sh | bash -s -- v1.2.3
22
- ```
23
26
 
24
- ```sh
25
27
  # PowerShell (Windows)
26
- irm https://raw.githubusercontent.com/itlackey/agentikit/main/install.ps1 -OutFile install.ps1; ./install.ps1 v1.2.3
28
+ irm https://raw.githubusercontent.com/itlackey/agentikit/main/install.ps1 -OutFile install.ps1; ./install.ps1
27
29
  ```
28
30
 
29
31
  The shell installer verifies the downloaded binary against release `checksums.txt` before installing it.
30
32
 
31
- ### OpenCode plugin
33
+ ## Stash model
32
34
 
33
- Add agentikit to the `plugin` array in your OpenCode config (`opencode.json`):
35
+ Set a stash path via `AGENTIKIT_STASH_DIR`, or run `akm init` to create one automatically.
34
36
 
35
- ```json
36
- {
37
- "plugin": ["@itlackey/agentikit"]
38
- }
37
+ ```sh
38
+ export AGENTIKIT_STASH_DIR=/abs/path/to/your-stash
39
39
  ```
40
40
 
41
- ### Claude Code plugin
41
+ Expected stash layout:
42
+
43
+ ```
44
+ $AGENTIKIT_STASH_DIR/
45
+ ├── tools/ # recursive files (.sh, .ts, .js, .ps1, .cmd, .bat)
46
+ ├── skills/ # skill directories containing SKILL.md
47
+ ├── commands/ # markdown files
48
+ ├── agents/ # markdown files
49
+ └── knowledge/ # markdown files
50
+ ```
42
51
 
43
- Install agentikit as a Claude Code plugin by pointing to the repo directory:
52
+ ## CLI usage
44
53
 
45
54
  ```sh
46
- claude --plugin-dir /path/to/agentikit
55
+ akm init # Initialize stash directory and set AGENTIKIT_STASH_DIR
56
+ akm index [--full] # Build search index (incremental by default)
57
+ akm search [query] # Search the stash
58
+ akm show <type:name> # Read a stash asset by ref
47
59
  ```
48
60
 
49
- Or add it to a plugin marketplace for team distribution. See the [Claude Code plugins documentation](https://code.claude.com/docs/en/plugins) for details.
61
+ ### search
50
62
 
51
- Once installed, the plugin provides:
63
+ Search the stash for extension assets.
52
64
 
53
- - **Skill** (`agentikit:stash`) — Claude automatically uses this when you ask about stash assets
54
- - **Commands** `/agentikit:search`, `/agentikit:open`, `/agentikit:run` slash commands
65
+ ```sh
66
+ akm search "deploy" --type tool --limit 10
67
+ ```
55
68
 
56
- ## Stash model
69
+ - `query`: case-insensitive substring over stable names (relative paths)
70
+ - `--type`: `tool | skill | command | agent | knowledge | any` (default: `any`)
71
+ - `--limit`: defaults to `20`
72
+
73
+ Returns typed hits with `openRef`, score/explainability details (`score`, `whyMatched`), and, for tools, execution-ready `runCmd`.
57
74
 
58
- Set a stash path via `AGENTIKIT_STASH_DIR`.
75
+ ### show
76
+
77
+ Show a hit using `openRef` from search results.
59
78
 
60
79
  ```sh
61
- export AGENTIKIT_STASH_DIR=/abs/path/to/your-stash
80
+ akm show skill:code-review
81
+ akm show knowledge:guide.md --view toc
82
+ akm show knowledge:guide.md --view section --heading "Getting Started"
83
+ akm show knowledge:guide.md --view lines --start 10 --end 30
62
84
  ```
63
85
 
64
- Expected stash layout:
86
+ Returns full payload by type:
65
87
 
66
- ```
67
- $AGENTIKIT_STASH_DIR/
68
- ├── tools/ # recursive files (.sh, .ts, .js, .ps1, .cmd, .bat)
69
- ├── skills/ # skill directories containing SKILL.md
70
- ├── commands/ # markdown files
71
- └── agents/ # markdown files
88
+ - `skill` — full `SKILL.md` content
89
+ - `command` — full markdown body as `template` (+ best-effort `description`)
90
+ - `agent` full markdown body as `prompt` (+ best-effort `description`, `toolPolicy`, `modelHint`)
91
+ - `tool` `runCmd`/`kind` (the agent uses the host's shell to execute `runCmd`)
92
+ - `knowledge` content with optional view modes (`full`, `toc`, `frontmatter`, `section`, `lines`)
93
+
94
+ ## Library API
95
+
96
+ Agentikit also exports its core functions for use as a library:
97
+
98
+ ```ts
99
+ import { agentikitSearch, agentikitShow, agentikitInit, agentikitIndex } from "agentikit"
72
100
  ```
73
101
 
74
- ## Tools
102
+ - `agentikitSearch({ query, type?, limit? })` — search the stash
103
+ - `agentikitShow({ ref, view? })` — show a stash asset
104
+ - `agentikitInit()` — initialize stash directory
105
+ - `agentikitIndex()` — build/rebuild search index
75
106
 
76
- When loaded as a plugin (OpenCode or Claude Code), Agentikit provides three tools:
107
+ ## Configuration
77
108
 
78
- - `agentikit_search({ query, type?, limit? })`
79
- - `agentikit_open({ ref })`
80
- - `agentikit_run({ ref })`
109
+ Agentikit stores configuration in `config.json` inside the stash directory.
81
110
 
82
- ### `agentikit_search`
111
+ ```sh
112
+ akm config # Show current config
113
+ akm config --set key=value # Update a config key
114
+ ```
83
115
 
84
- Search the stash for extension assets.
116
+ ### Embedding connection
85
117
 
86
- - `query`: case-insensitive substring over stable names (relative paths)
87
- - `type`: `tool | skill | command | agent | any` (default: `any`)
88
- - `limit`: defaults to `20`
118
+ By default, agentikit uses the local `@xenova/transformers` library for embeddings. You can configure an OpenAI-compatible embedding endpoint instead:
89
119
 
90
- Returns typed hits with `openRef` and, for tools, execution-ready `runCmd`.
120
+ ```sh
121
+ akm config --set 'embedding={"endpoint":"http://localhost:11434/v1/embeddings","model":"nomic-embed-text"}'
122
+ ```
91
123
 
92
- Tool command generation:
124
+ To clear the custom embedding config and revert to local embeddings:
93
125
 
94
- - `.sh` → `bash "<absolute-file>"`
95
- - `.ps1` `powershell -ExecutionPolicy Bypass -File "<absolute-file>"`
96
- - `.cmd`/`.bat` → `cmd /c "<absolute-file>"`
97
- - `.ts`/`.js`:
98
- - find nearest `package.json` from script dir upward to stash `tools/` root
99
- - if found: `cd "<pkgDir>" && bun "<absolute-file>"`
100
- - else: `bun "<absolute-file>"`
101
- - optional: set `AGENTIKIT_BUN_INSTALL=true` to include `bun install` before running
126
+ ```sh
127
+ akm config --set 'embedding=null'
128
+ ```
102
129
 
103
- ### `agentikit_open`
130
+ ### LLM connection
104
131
 
105
- Open a hit using `openRef` from search results.
132
+ When configured, agentikit uses an OpenAI-compatible LLM to generate richer metadata (descriptions, intents, tags) during indexing:
106
133
 
107
- Returns full payload by type:
134
+ ```sh
135
+ akm config --set 'llm={"endpoint":"http://localhost:11434/v1/chat/completions","model":"llama3.2"}'
136
+ ```
108
137
 
109
- - `skill` → full `SKILL.md` content
110
- - `command` → full markdown body as `template` (+ best-effort `description`)
111
- - `agent` → full markdown body as `prompt` (+ best-effort `description`, `toolPolicy`, `modelHint`)
112
- - `tool` → `runCmd`/`kind`
138
+ To clear:
113
139
 
114
- ### `agentikit_run`
140
+ ```sh
141
+ akm config --set 'llm=null'
142
+ ```
115
143
 
116
- Execute a tool from the stash by its `openRef`. Only `tool:` refs are supported.
144
+ ### Using a local Ollama instance
117
145
 
118
- - `ref`: open reference of a tool returned by `agentikit_search`
146
+ [Ollama](https://ollama.com) provides local models with an OpenAI-compatible API. After installing Ollama and pulling your models:
119
147
 
120
- Returns `{ type, name, path, output, exitCode }`.
148
+ ```sh
149
+ # Pull models
150
+ ollama pull nomic-embed-text
151
+ ollama pull llama3.2
121
152
 
122
- ## Usage example
153
+ # Configure agentikit to use Ollama for both embeddings and metadata generation
154
+ akm config --set 'embedding={"endpoint":"http://localhost:11434/v1/embeddings","model":"nomic-embed-text"}'
155
+ akm config --set 'llm={"endpoint":"http://localhost:11434/v1/chat/completions","model":"llama3.2"}'
123
156
 
124
- 1. `agentikit_search({ query: "deploy", type: "tool" })`
125
- 2. `agentikit_run({ ref: "<openRef from search>" })`
157
+ # Rebuild the index — embeddings use Ollama, metadata is LLM-enhanced
158
+ akm index --full
159
+ ```
126
160
 
127
- Or:
161
+ Both `embedding` and `llm` accept an optional `apiKey` field for authenticated endpoints:
128
162
 
129
- 1. `agentikit_search({ query: "release", type: "command" })`
130
- 2. `agentikit_open({ ref: "<openRef from search>" })`
131
- 3. Apply returned template in-session
163
+ ```json
164
+ {
165
+ "endpoint": "https://api.openai.com/v1/embeddings",
166
+ "model": "text-embedding-3-small",
167
+ "apiKey": "sk-..."
168
+ }
169
+ ```
132
170
 
133
- ## Package exports
171
+ ### Config reference
134
172
 
135
- - `plugin` OpenCode plugin exposing `agentikit_search`, `agentikit_open`, and `agentikit_run`
136
- - `agentikitSearch` / `agentikitOpen` / `agentikitRun` — direct library APIs
173
+ | Key | Type | Default | Description |
174
+ |-----|------|---------|-------------|
175
+ | `semanticSearch` | `boolean` | `true` | Enable semantic search ranking |
176
+ | `additionalStashDirs` | `string[]` | `[]` | Extra stash directories to search |
177
+ | `embedding` | `object` | not set | OpenAI-compatible embedding endpoint (`endpoint`, `model`, `apiKey?`) |
178
+ | `llm` | `object` | not set | OpenAI-compatible LLM endpoint (`endpoint`, `model`, `apiKey?`) |
137
179
 
138
180
  ## Notes
139
181
 
140
- - Agentikit does not write to `.opencode/` or `.claude/`.
141
182
  - Agentikit does not install or copy kit files.
142
183
  - Missing or unreadable stash paths return friendly errors.
143
-
144
- ## Docs
145
-
146
- - **OpenCode**: [Plugins](https://opencode.ai/docs/plugins/) · [Commands](https://opencode.ai/docs/commands/) · [Agents](https://opencode.ai/docs/agents/) · [Agent Skills](https://opencode.ai/docs/skills/) · [Custom tools](https://opencode.ai/docs/custom-tools/) · [Config](https://opencode.ai/docs/config/)
147
- - **Claude Code**: [Plugins](https://code.claude.com/docs/en/plugins) · [Skills](https://code.claude.com/docs/en/skills) · [Plugins reference](https://code.claude.com/docs/en/plugins-reference)
package/dist/index.d.ts CHANGED
@@ -1,6 +1,18 @@
1
- export { plugin } from "./src/plugin";
2
- export { agentikitSearch, agentikitOpen, agentikitRun, agentikitInit } from "./src/stash";
3
- export type { AgentikitAssetType, AgentikitSearchType, SearchHit, SearchResponse, OpenResponse, RunResponse, InitResponse, } from "./src/stash";
1
+ export { agentikitSearch, agentikitShow } from "./src/stash";
2
+ export { agentikitInit } from "./src/init";
3
+ export type { InitResponse } from "./src/init";
4
+ export type { AgentikitAssetType, AgentikitSearchType, SearchHit, SearchResponse, ShowResponse, KnowledgeView, } from "./src/stash";
5
+ export type { ToolKind } from "./src/tool-runner";
4
6
  export { agentikitIndex } from "./src/indexer";
5
7
  export type { IndexResponse } from "./src/indexer";
6
8
  export type { StashEntry, StashFile, StashIntent } from "./src/metadata";
9
+ export { resolveRg, isRgAvailable, ensureRg } from "./src/ripgrep";
10
+ export type { EnsureRgResult } from "./src/ripgrep";
11
+ export { parseMarkdownToc, extractSection, extractLineRange, extractFrontmatterOnly, formatToc } from "./src/markdown";
12
+ export type { TocHeading, KnowledgeToc } from "./src/markdown";
13
+ export { parseFrontmatter } from "./src/frontmatter";
14
+ export { loadConfig, saveConfig, updateConfig } from "./src/config";
15
+ export type { AgentikitConfig, EmbeddingConnectionConfig, LlmConnectionConfig } from "./src/config";
16
+ export { enhanceMetadata, isLlmAvailable } from "./src/llm";
17
+ export { embed, cosineSimilarity, isEmbeddingAvailable } from "./src/embedder";
18
+ export type { EmbeddingVector } from "./src/embedder";
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
- export { plugin } from "./src/plugin";
2
- export { agentikitSearch, agentikitOpen, agentikitRun, agentikitInit } from "./src/stash";
1
+ export { agentikitSearch, agentikitShow } from "./src/stash";
2
+ export { agentikitInit } from "./src/init";
3
3
  export { agentikitIndex } from "./src/indexer";
4
+ export { resolveRg, isRgAvailable, ensureRg } from "./src/ripgrep";
5
+ export { parseMarkdownToc, extractSection, extractLineRange, extractFrontmatterOnly, formatToc } from "./src/markdown";
6
+ export { parseFrontmatter } from "./src/frontmatter";
7
+ export { loadConfig, saveConfig, updateConfig } from "./src/config";
8
+ export { enhanceMetadata, isLlmAvailable } from "./src/llm";
9
+ export { embed, cosineSimilarity, isEmbeddingAvailable } from "./src/embedder";
@@ -0,0 +1,14 @@
1
+ import type { AgentikitAssetType } from "./common";
2
+ export declare const SCRIPT_EXTENSIONS: Set<string>;
3
+ export interface AssetSpec {
4
+ stashDir: string;
5
+ isRelevantFile: (fileName: string) => boolean;
6
+ toCanonicalName: (typeRoot: string, filePath: string) => string | undefined;
7
+ toAssetPath: (typeRoot: string, name: string) => string;
8
+ }
9
+ export declare const ASSET_SPECS: Record<AgentikitAssetType, AssetSpec>;
10
+ export declare const ASSET_TYPES: AgentikitAssetType[];
11
+ export declare const TYPE_DIRS: Record<AgentikitAssetType, string>;
12
+ export declare function isRelevantAssetFile(assetType: AgentikitAssetType, fileName: string): boolean;
13
+ export declare function deriveCanonicalAssetName(assetType: AgentikitAssetType, typeRoot: string, filePath: string): string | undefined;
14
+ export declare function resolveAssetPathFromName(assetType: AgentikitAssetType, typeRoot: string, name: string): string;
@@ -0,0 +1,46 @@
1
+ import path from "node:path";
2
+ export const SCRIPT_EXTENSIONS = new Set([".sh", ".ts", ".js", ".ps1", ".cmd", ".bat"]);
3
+ const markdownSpec = {
4
+ isRelevantFile: (fileName) => path.extname(fileName).toLowerCase() === ".md",
5
+ toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
6
+ toAssetPath: (typeRoot, name) => path.join(typeRoot, name),
7
+ };
8
+ export const ASSET_SPECS = {
9
+ tool: {
10
+ stashDir: "tools",
11
+ isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path.extname(fileName).toLowerCase()),
12
+ toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
13
+ toAssetPath: (typeRoot, name) => path.join(typeRoot, name),
14
+ },
15
+ skill: {
16
+ stashDir: "skills",
17
+ isRelevantFile: (fileName) => fileName === "SKILL.md",
18
+ toCanonicalName: (typeRoot, filePath) => {
19
+ const relDir = toPosix(path.dirname(path.relative(typeRoot, filePath)));
20
+ if (!relDir || relDir === ".")
21
+ return undefined;
22
+ return relDir;
23
+ },
24
+ toAssetPath: (typeRoot, name) => path.join(typeRoot, name, "SKILL.md"),
25
+ },
26
+ command: { stashDir: "commands", ...markdownSpec },
27
+ agent: { stashDir: "agents", ...markdownSpec },
28
+ knowledge: { stashDir: "knowledge", ...markdownSpec },
29
+ };
30
+ export const ASSET_TYPES = Object.keys(ASSET_SPECS);
31
+ export const TYPE_DIRS = ASSET_TYPES.reduce((acc, type) => {
32
+ acc[type] = ASSET_SPECS[type].stashDir;
33
+ return acc;
34
+ }, {});
35
+ export function isRelevantAssetFile(assetType, fileName) {
36
+ return ASSET_SPECS[assetType].isRelevantFile(fileName);
37
+ }
38
+ export function deriveCanonicalAssetName(assetType, typeRoot, filePath) {
39
+ return ASSET_SPECS[assetType].toCanonicalName(typeRoot, filePath);
40
+ }
41
+ export function resolveAssetPathFromName(assetType, typeRoot, name) {
42
+ return ASSET_SPECS[assetType].toAssetPath(typeRoot, name);
43
+ }
44
+ function toPosix(input) {
45
+ return input.replace(/\\/g, "/");
46
+ }
package/dist/src/cli.js CHANGED
@@ -1,62 +1,164 @@
1
1
  #!/usr/bin/env node
2
- import { agentikitSearch, agentikitOpen, agentikitRun, agentikitInit } from "./stash";
2
+ import { defineCommand, runMain } from "citty";
3
+ import { agentikitSearch, agentikitShow } from "./stash";
4
+ import { agentikitInit } from "./init";
3
5
  import { agentikitIndex } from "./indexer";
4
- const args = process.argv.slice(2);
5
- const command = args[0];
6
- function flag(name) {
7
- const idx = args.indexOf(name);
8
- return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : undefined;
9
- }
10
- function usage() {
11
- console.error("Usage: agentikit <init|search|open|run> [options]");
12
- console.error("");
13
- console.error("Commands:");
14
- console.error(" init Initialize agentikit stash directory and set AGENTIKIT_STASH_DIR");
15
- console.error(" index Build search index with metadata generation");
16
- console.error(" search [query] Search the stash (--type tool|skill|command|agent|any) (--limit N)");
17
- console.error(" open <type:name> Open a stash asset by ref");
18
- console.error(" run <type:name> Run a tool by ref");
19
- process.exit(1);
20
- }
21
- switch (command) {
22
- case "init": {
6
+ import { loadConfig, updateConfig } from "./config";
7
+ import { resolveStashDir } from "./common";
8
+ const initCommand = defineCommand({
9
+ meta: { name: "init", description: "Initialize agentikit stash directory and set AGENTIKIT_STASH_DIR" },
10
+ run() {
23
11
  const result = agentikitInit();
24
12
  console.log(JSON.stringify(result, null, 2));
25
- break;
26
- }
27
- case "index": {
28
- const result = agentikitIndex();
13
+ },
14
+ });
15
+ const indexCommand = defineCommand({
16
+ meta: { name: "index", description: "Build search index (incremental by default; --full forces full reindex)" },
17
+ args: {
18
+ full: { type: "boolean", description: "Force full reindex", default: false },
19
+ },
20
+ async run({ args }) {
21
+ const result = await agentikitIndex({ full: args.full });
29
22
  console.log(JSON.stringify(result, null, 2));
30
- break;
23
+ },
24
+ });
25
+ const searchCommand = defineCommand({
26
+ meta: { name: "search", description: "Search the stash" },
27
+ args: {
28
+ query: { type: "positional", description: "Search query", required: false, default: "" },
29
+ type: { type: "string", description: "Asset type filter (tool|skill|command|agent|knowledge|any)" },
30
+ limit: { type: "string", description: "Maximum number of results" },
31
+ },
32
+ async run({ args }) {
33
+ const type = args.type;
34
+ const limit = args.limit ? parseInt(args.limit, 10) : undefined;
35
+ console.log(JSON.stringify(await agentikitSearch({ query: args.query, type, limit }), null, 2));
36
+ },
37
+ });
38
+ const showCommand = defineCommand({
39
+ meta: { name: "show", description: "Show a stash asset by ref (e.g. agent:bunjs-typescript-coder.md)" },
40
+ args: {
41
+ ref: { type: "positional", description: "Asset ref (type:name)", required: true },
42
+ view: { type: "string", description: "Knowledge view mode (full|toc|frontmatter|section|lines)" },
43
+ heading: { type: "string", description: "Section heading (for --view section)" },
44
+ start: { type: "string", description: "Start line (for --view lines)" },
45
+ end: { type: "string", description: "End line (for --view lines)" },
46
+ },
47
+ run({ args }) {
48
+ let view;
49
+ if (args.view) {
50
+ switch (args.view) {
51
+ case "section":
52
+ view = { mode: "section", heading: args.heading ?? "" };
53
+ break;
54
+ case "lines":
55
+ view = {
56
+ mode: "lines",
57
+ start: Number(args.start ?? "1"),
58
+ end: args.end ? parseInt(args.end, 10) : Number.MAX_SAFE_INTEGER,
59
+ };
60
+ break;
61
+ case "toc":
62
+ case "frontmatter":
63
+ case "full":
64
+ view = { mode: args.view };
65
+ break;
66
+ default:
67
+ console.error(`Unknown view mode: ${args.view}`);
68
+ process.exit(1);
69
+ }
70
+ }
71
+ console.log(JSON.stringify(agentikitShow({ ref: args.ref, view }), null, 2));
72
+ },
73
+ });
74
+ const configCommand = defineCommand({
75
+ meta: { name: "config", description: "Show or update configuration" },
76
+ args: {
77
+ set: { type: "string", description: "Update a config key (key=value format)" },
78
+ },
79
+ run({ args }) {
80
+ const stashDir = resolveStashDir();
81
+ if (args.set) {
82
+ const eqIndex = args.set.indexOf("=");
83
+ if (eqIndex === -1) {
84
+ console.error("Error: --set expects key=value format");
85
+ process.exit(1);
86
+ }
87
+ const key = args.set.slice(0, eqIndex);
88
+ const value = args.set.slice(eqIndex + 1);
89
+ const partial = parseConfigValue(key, value);
90
+ const config = updateConfig(partial, stashDir);
91
+ console.log(JSON.stringify(config, null, 2));
92
+ }
93
+ else {
94
+ const config = loadConfig(stashDir);
95
+ console.log(JSON.stringify(config, null, 2));
96
+ }
97
+ },
98
+ });
99
+ const main = defineCommand({
100
+ meta: {
101
+ name: "akm",
102
+ description: "CLI tool to search, open, and run extension assets from an agentikit stash directory.",
103
+ },
104
+ subCommands: {
105
+ init: initCommand,
106
+ index: indexCommand,
107
+ search: searchCommand,
108
+ show: showCommand,
109
+ config: configCommand,
110
+ },
111
+ });
112
+ runMain(main);
113
+ function parseConnectionValue(key, value, exampleEndpoint, exampleModel) {
114
+ if (value === "null" || value === "")
115
+ return undefined;
116
+ let parsed;
117
+ try {
118
+ parsed = JSON.parse(value);
31
119
  }
32
- case "search": {
33
- const query = args.find((a, i) => i > 0 && !a.startsWith("--") && args[i - 1] !== "--type" && args[i - 1] !== "--limit") ?? "";
34
- const type = flag("--type");
35
- const limitStr = flag("--limit");
36
- const limit = limitStr ? parseInt(limitStr, 10) : undefined;
37
- console.log(JSON.stringify(agentikitSearch({ query, type, limit }), null, 2));
38
- break;
120
+ catch {
121
+ throw new Error(`Invalid value for ${key}: expected JSON object with endpoint and model`
122
+ + ` (e.g. '{"endpoint":"${exampleEndpoint}","model":"${exampleModel}"}')`);
39
123
  }
40
- case "open": {
41
- const ref = args[1];
42
- if (!ref) {
43
- console.error("Error: missing ref argument\n");
44
- usage();
45
- }
46
- console.log(JSON.stringify(agentikitOpen({ ref }), null, 2));
47
- break;
124
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
125
+ throw new Error(`Invalid value for ${key}: expected a JSON object`);
48
126
  }
49
- case "run": {
50
- const ref = args[1];
51
- if (!ref) {
52
- console.error("Error: missing ref argument\n");
53
- usage();
54
- }
55
- const result = agentikitRun({ ref });
56
- console.log(JSON.stringify(result, null, 2));
57
- process.exit(result.exitCode);
58
- break;
127
+ const obj = parsed;
128
+ if (typeof obj.endpoint !== "string" || !obj.endpoint || typeof obj.model !== "string" || !obj.model) {
129
+ throw new Error(`Invalid value for ${key}: "endpoint" and "model" are required string fields`);
130
+ }
131
+ const result = {
132
+ endpoint: obj.endpoint,
133
+ model: obj.model,
134
+ };
135
+ if (typeof obj.apiKey === "string" && obj.apiKey) {
136
+ result.apiKey = obj.apiKey;
137
+ }
138
+ return result;
139
+ }
140
+ function parseConfigValue(key, value) {
141
+ switch (key) {
142
+ case "semanticSearch":
143
+ if (value !== "true" && value !== "false") {
144
+ throw new Error(`Invalid value for semanticSearch: expected "true" or "false"`);
145
+ }
146
+ return { semanticSearch: value === "true" };
147
+ case "additionalStashDirs":
148
+ try {
149
+ const parsed = JSON.parse(value);
150
+ if (!Array.isArray(parsed))
151
+ throw new Error("expected JSON array");
152
+ return { additionalStashDirs: parsed.filter((d) => typeof d === "string") };
153
+ }
154
+ catch {
155
+ throw new Error(`Invalid value for additionalStashDirs: expected JSON array (e.g. '["/path/a","/path/b"]')`);
156
+ }
157
+ case "embedding":
158
+ return { embedding: parseConnectionValue("embedding", value, "http://localhost:11434/v1/embeddings", "nomic-embed-text") };
159
+ case "llm":
160
+ return { llm: parseConnectionValue("llm", value, "http://localhost:11434/v1/chat/completions", "llama3.2") };
161
+ default:
162
+ throw new Error(`Unknown config key: ${key}`);
59
163
  }
60
- default:
61
- usage();
62
164
  }
@@ -0,0 +1,8 @@
1
+ export type AgentikitAssetType = "tool" | "skill" | "command" | "agent" | "knowledge";
2
+ export declare const IS_WINDOWS: boolean;
3
+ export { SCRIPT_EXTENSIONS, TYPE_DIRS } from "./asset-spec";
4
+ export declare function isAssetType(type: string): type is AgentikitAssetType;
5
+ export declare function resolveStashDir(): string;
6
+ export declare function toPosix(input: string): string;
7
+ export declare function hasErrnoCode(error: unknown, code: string): boolean;
8
+ export declare function isWithin(candidate: string, root: string): boolean;
@@ -0,0 +1,46 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { TYPE_DIRS } from "./asset-spec";
4
+ // ── Constants ───────────────────────────────────────────────────────────────
5
+ export const IS_WINDOWS = process.platform === "win32";
6
+ export { SCRIPT_EXTENSIONS, TYPE_DIRS } from "./asset-spec";
7
+ // ── Validators ──────────────────────────────────────────────────────────────
8
+ export function isAssetType(type) {
9
+ return type in TYPE_DIRS;
10
+ }
11
+ // ── Utilities ───────────────────────────────────────────────────────────────
12
+ export function resolveStashDir() {
13
+ const raw = process.env.AGENTIKIT_STASH_DIR?.trim();
14
+ if (!raw) {
15
+ throw new Error("AGENTIKIT_STASH_DIR is not set. Set it to your Agentikit stash path.");
16
+ }
17
+ const stashDir = path.resolve(raw);
18
+ let stat;
19
+ try {
20
+ stat = fs.statSync(stashDir);
21
+ }
22
+ catch {
23
+ throw new Error(`Unable to read AGENTIKIT_STASH_DIR at "${stashDir}".`);
24
+ }
25
+ if (!stat.isDirectory()) {
26
+ throw new Error(`AGENTIKIT_STASH_DIR must point to a directory: "${stashDir}".`);
27
+ }
28
+ return stashDir;
29
+ }
30
+ export function toPosix(input) {
31
+ return input.replace(/\\/g, "/");
32
+ }
33
+ export function hasErrnoCode(error, code) {
34
+ if (typeof error !== "object" || error === null || !("code" in error))
35
+ return false;
36
+ return error.code === code;
37
+ }
38
+ export function isWithin(candidate, root) {
39
+ const normalizedRoot = normalizeFsPathForComparison(path.resolve(root));
40
+ const normalizedCandidate = normalizeFsPathForComparison(path.resolve(candidate));
41
+ const rel = path.relative(normalizedRoot, normalizedCandidate);
42
+ return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
43
+ }
44
+ function normalizeFsPathForComparison(value) {
45
+ return process.platform === "win32" ? value.toLowerCase() : value;
46
+ }