agentikit 0.0.7 → 0.0.9
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 +215 -76
- package/dist/index.d.ts +17 -3
- package/dist/index.js +10 -2
- package/dist/src/asset-spec.d.ts +14 -0
- package/dist/src/asset-spec.js +46 -0
- package/dist/src/cli.js +268 -57
- package/dist/src/common.d.ts +8 -0
- package/dist/src/common.js +46 -0
- package/dist/src/config.d.ts +37 -0
- package/dist/src/config.js +124 -0
- package/dist/src/embedder.d.ts +10 -0
- package/dist/src/embedder.js +87 -0
- package/dist/src/frontmatter.d.ts +30 -0
- package/dist/src/frontmatter.js +86 -0
- package/dist/src/indexer.d.ts +20 -2
- package/dist/src/indexer.js +212 -80
- package/dist/src/init.d.ts +19 -0
- package/dist/src/init.js +87 -0
- package/dist/src/llm.d.ts +15 -0
- package/dist/src/llm.js +91 -0
- package/dist/src/markdown.d.ts +18 -0
- package/dist/src/markdown.js +77 -0
- package/dist/src/metadata.d.ts +11 -2
- package/dist/src/metadata.js +161 -29
- package/dist/src/registry-install.d.ts +11 -0
- package/dist/src/registry-install.js +208 -0
- package/dist/src/registry-resolve.d.ts +3 -0
- package/dist/src/registry-resolve.js +231 -0
- package/dist/src/registry-search.d.ts +5 -0
- package/dist/src/registry-search.js +129 -0
- package/dist/src/registry-types.d.ts +55 -0
- package/dist/src/registry-types.js +1 -0
- package/dist/src/ripgrep-install.d.ts +12 -0
- package/dist/src/ripgrep-install.js +169 -0
- package/dist/src/ripgrep-resolve.d.ts +13 -0
- package/dist/src/ripgrep-resolve.js +68 -0
- package/dist/src/ripgrep.d.ts +3 -36
- package/dist/src/ripgrep.js +2 -262
- package/dist/src/similarity.d.ts +1 -2
- package/dist/src/similarity.js +11 -0
- package/dist/src/stash-add.d.ts +4 -0
- package/dist/src/stash-add.js +59 -0
- package/dist/src/stash-ref.d.ts +7 -0
- package/dist/src/stash-ref.js +33 -0
- package/dist/src/stash-registry.d.ts +18 -0
- package/dist/src/stash-registry.js +221 -0
- package/dist/src/stash-resolve.d.ts +2 -0
- package/dist/src/stash-resolve.js +45 -0
- package/dist/src/stash-search.d.ts +8 -0
- package/dist/src/stash-search.js +484 -0
- package/dist/src/stash-show.d.ts +5 -0
- package/dist/src/stash-show.js +114 -0
- package/dist/src/stash-types.d.ts +217 -0
- package/dist/src/stash-types.js +1 -0
- package/dist/src/stash.d.ts +10 -63
- package/dist/src/stash.js +6 -633
- package/dist/src/tool-runner.d.ts +35 -0
- package/dist/src/tool-runner.js +100 -0
- package/dist/src/walker.d.ts +19 -0
- package/dist/src/walker.js +47 -0
- package/package.json +8 -14
- package/src/asset-spec.ts +69 -0
- package/src/cli.ts +282 -46
- package/src/common.ts +58 -0
- package/src/config.ts +183 -0
- package/src/embedder.ts +117 -0
- package/src/frontmatter.ts +95 -0
- package/src/indexer.ts +244 -84
- package/src/init.ts +106 -0
- package/src/llm.ts +124 -0
- package/src/markdown.ts +106 -0
- package/src/metadata.ts +171 -27
- package/src/registry-install.ts +245 -0
- package/src/registry-resolve.ts +272 -0
- package/src/registry-search.ts +145 -0
- package/src/registry-types.ts +64 -0
- package/src/ripgrep-install.ts +200 -0
- package/src/ripgrep-resolve.ts +72 -0
- package/src/ripgrep.ts +3 -315
- package/src/similarity.ts +13 -1
- package/src/stash-add.ts +66 -0
- package/src/stash-ref.ts +41 -0
- package/src/stash-registry.ts +259 -0
- package/src/stash-resolve.ts +47 -0
- package/src/stash-search.ts +595 -0
- package/src/stash-show.ts +112 -0
- package/src/stash-types.ts +221 -0
- package/src/stash.ts +31 -760
- package/src/tool-runner.ts +129 -0
- package/src/walker.ts +53 -0
- package/.claude-plugin/plugin.json +0 -21
- package/commands/open.md +0 -11
- package/commands/run.md +0 -11
- package/commands/search.md +0 -11
- package/dist/src/plugin.d.ts +0 -2
- package/dist/src/plugin.js +0 -55
- package/skills/stash/SKILL.md +0 -73
- package/src/plugin.ts +0 -56
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool execution utilities.
|
|
3
|
+
*
|
|
4
|
+
* Handles building run commands and executing tool scripts for all supported
|
|
5
|
+
* kinds (bash, bun, powershell, cmd).
|
|
6
|
+
*/
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { IS_WINDOWS, isWithin } from "./common";
|
|
10
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Build execution metadata for a tool file based on its extension.
|
|
13
|
+
*
|
|
14
|
+
* For `.ts` / `.js` files, looks up the nearest `package.json` so that
|
|
15
|
+
* `bun install` can be run in the correct working directory when the
|
|
16
|
+
* `AGENTIKIT_BUN_INSTALL` env flag is set.
|
|
17
|
+
*/
|
|
18
|
+
export function buildToolInfo(stashDir, filePath) {
|
|
19
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
20
|
+
if (ext === ".sh") {
|
|
21
|
+
return {
|
|
22
|
+
runCmd: `bash ${shellQuote(filePath)}`,
|
|
23
|
+
kind: "bash",
|
|
24
|
+
execute: { command: "bash", args: [filePath] },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (ext === ".ps1") {
|
|
28
|
+
return {
|
|
29
|
+
runCmd: `powershell -ExecutionPolicy Bypass -File ${shellQuote(filePath)}`,
|
|
30
|
+
kind: "powershell",
|
|
31
|
+
execute: { command: "powershell", args: ["-ExecutionPolicy", "Bypass", "-File", filePath] },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (ext === ".cmd" || ext === ".bat") {
|
|
35
|
+
return {
|
|
36
|
+
runCmd: `cmd /c ${shellQuote(filePath)}`,
|
|
37
|
+
kind: "cmd",
|
|
38
|
+
execute: { command: "cmd", args: ["/c", filePath] },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (ext !== ".ts" && ext !== ".js") {
|
|
42
|
+
throw new Error(`Unsupported tool extension: ${ext}`);
|
|
43
|
+
}
|
|
44
|
+
const toolsRoot = path.resolve(path.join(stashDir, "tools"));
|
|
45
|
+
const pkgDir = findNearestPackageDir(path.dirname(filePath), toolsRoot);
|
|
46
|
+
if (!pkgDir) {
|
|
47
|
+
return {
|
|
48
|
+
runCmd: `bun ${shellQuote(filePath)}`,
|
|
49
|
+
kind: "bun",
|
|
50
|
+
execute: { command: "bun", args: [filePath] },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const installFlag = process.env.AGENTIKIT_BUN_INSTALL;
|
|
54
|
+
const shouldInstall = installFlag === "1" || installFlag === "true" || installFlag === "yes";
|
|
55
|
+
const quotedPkgDir = shellQuote(pkgDir);
|
|
56
|
+
const quotedFilePath = shellQuote(filePath);
|
|
57
|
+
const cdCmd = IS_WINDOWS ? `cd /d ${quotedPkgDir}` : `cd ${quotedPkgDir}`;
|
|
58
|
+
const chain = IS_WINDOWS ? " & " : " && ";
|
|
59
|
+
return {
|
|
60
|
+
runCmd: shouldInstall
|
|
61
|
+
? `${cdCmd}${chain}bun install${chain}bun ${quotedFilePath}`
|
|
62
|
+
: `${cdCmd}${chain}bun ${quotedFilePath}`,
|
|
63
|
+
kind: "bun",
|
|
64
|
+
install: shouldInstall ? { command: "bun", args: ["install"], cwd: pkgDir } : undefined,
|
|
65
|
+
execute: { command: "bun", args: [filePath], cwd: pkgDir },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Shell-quote a path for inclusion in a human-readable `runCmd` string.
|
|
70
|
+
*/
|
|
71
|
+
export function shellQuote(input) {
|
|
72
|
+
if (/[\r\n\t\0]/.test(input)) {
|
|
73
|
+
throw new Error("Unsupported control characters in stash path.");
|
|
74
|
+
}
|
|
75
|
+
if (IS_WINDOWS) {
|
|
76
|
+
return `"${input.replace(/"/g, '""')}"`;
|
|
77
|
+
}
|
|
78
|
+
const escaped = input
|
|
79
|
+
.replace(/\\/g, "\\\\")
|
|
80
|
+
.replace(/"/g, '\\"')
|
|
81
|
+
.replace(/\$/g, "\\$")
|
|
82
|
+
.replace(/`/g, "\\`");
|
|
83
|
+
return `"${escaped}"`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Walk up from `startDir` toward `toolsRoot` looking for the nearest `package.json`.
|
|
87
|
+
*/
|
|
88
|
+
export function findNearestPackageDir(startDir, toolsRoot) {
|
|
89
|
+
let current = path.resolve(startDir);
|
|
90
|
+
const root = path.resolve(toolsRoot);
|
|
91
|
+
while (isWithin(current, root)) {
|
|
92
|
+
if (fs.existsSync(path.join(current, "package.json"))) {
|
|
93
|
+
return current;
|
|
94
|
+
}
|
|
95
|
+
if (current === root)
|
|
96
|
+
return undefined;
|
|
97
|
+
current = path.dirname(current);
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filesystem walker for agentikit stash directories.
|
|
3
|
+
*
|
|
4
|
+
* Provides a single implementation used by both the search fallback
|
|
5
|
+
* (stash.ts) and the indexer (indexer.ts) to walk type-specific asset
|
|
6
|
+
* directories and group files by parent directory.
|
|
7
|
+
*/
|
|
8
|
+
import { type AgentikitAssetType } from "./common";
|
|
9
|
+
export interface DirectoryGroup {
|
|
10
|
+
dirPath: string;
|
|
11
|
+
files: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Walk a type root directory and return files grouped by their parent directory.
|
|
15
|
+
*
|
|
16
|
+
* Only files relevant to the given `assetType` are included (e.g. `.md` for
|
|
17
|
+
* commands, script extensions for tools, `SKILL.md` for skills).
|
|
18
|
+
*/
|
|
19
|
+
export declare function walkStash(typeRoot: string, assetType: AgentikitAssetType): DirectoryGroup[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filesystem walker for agentikit stash directories.
|
|
3
|
+
*
|
|
4
|
+
* Provides a single implementation used by both the search fallback
|
|
5
|
+
* (stash.ts) and the indexer (indexer.ts) to walk type-specific asset
|
|
6
|
+
* directories and group files by parent directory.
|
|
7
|
+
*/
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { isRelevantAssetFile } from "./asset-spec";
|
|
11
|
+
/**
|
|
12
|
+
* Walk a type root directory and return files grouped by their parent directory.
|
|
13
|
+
*
|
|
14
|
+
* Only files relevant to the given `assetType` are included (e.g. `.md` for
|
|
15
|
+
* commands, script extensions for tools, `SKILL.md` for skills).
|
|
16
|
+
*/
|
|
17
|
+
export function walkStash(typeRoot, assetType) {
|
|
18
|
+
if (!fs.existsSync(typeRoot))
|
|
19
|
+
return [];
|
|
20
|
+
const groups = new Map();
|
|
21
|
+
const stack = [typeRoot];
|
|
22
|
+
while (stack.length > 0) {
|
|
23
|
+
const current = stack.pop();
|
|
24
|
+
if (!current)
|
|
25
|
+
continue;
|
|
26
|
+
const entries = fs.readdirSync(current, { withFileTypes: true });
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
if (entry.name === ".stash.json")
|
|
29
|
+
continue;
|
|
30
|
+
const fullPath = path.join(current, entry.name);
|
|
31
|
+
if (entry.isDirectory()) {
|
|
32
|
+
stack.push(fullPath);
|
|
33
|
+
}
|
|
34
|
+
else if (entry.isFile() && isRelevantAssetFile(assetType, entry.name)) {
|
|
35
|
+
const parentDir = path.dirname(fullPath);
|
|
36
|
+
const existing = groups.get(parentDir);
|
|
37
|
+
if (existing) {
|
|
38
|
+
existing.push(fullPath);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
groups.set(parentDir, [fullPath]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return Array.from(groups, ([dirPath, files]) => ({ dirPath, files }));
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentikit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "CLI tool to search, open, and run extension assets from an agentikit stash directory.",
|
|
6
6
|
"keywords": [
|
|
7
|
-
"opencode",
|
|
8
|
-
"opencode-ai",
|
|
9
|
-
"opencode-plugin",
|
|
10
|
-
"opencode-extensions",
|
|
11
|
-
"claude-code",
|
|
12
|
-
"claude-code-plugin",
|
|
13
7
|
"agentikit",
|
|
14
8
|
"ai-agent",
|
|
15
9
|
"agent-framework",
|
|
16
10
|
"developer-tools",
|
|
17
|
-
"
|
|
11
|
+
"cli",
|
|
18
12
|
"tools",
|
|
19
13
|
"skills",
|
|
20
14
|
"commands"
|
|
@@ -31,13 +25,10 @@
|
|
|
31
25
|
"files": [
|
|
32
26
|
"dist",
|
|
33
27
|
"src",
|
|
34
|
-
".claude-plugin",
|
|
35
|
-
"skills",
|
|
36
|
-
"commands",
|
|
37
28
|
"README.md"
|
|
38
29
|
],
|
|
39
30
|
"bin": {
|
|
40
|
-
"
|
|
31
|
+
"akm": "dist/src/cli.js"
|
|
41
32
|
},
|
|
42
33
|
"main": "./dist/index.js",
|
|
43
34
|
"types": "./dist/index.d.ts",
|
|
@@ -60,7 +51,10 @@
|
|
|
60
51
|
"@types/node": "^24.0.0",
|
|
61
52
|
"typescript": "^5.9.3"
|
|
62
53
|
},
|
|
54
|
+
"optionalDependencies": {
|
|
55
|
+
"@xenova/transformers": "^2.17.0"
|
|
56
|
+
},
|
|
63
57
|
"dependencies": {
|
|
64
|
-
"
|
|
58
|
+
"citty": "^0.2.1"
|
|
65
59
|
}
|
|
66
60
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import type { AgentikitAssetType } from "./common"
|
|
3
|
+
|
|
4
|
+
export const SCRIPT_EXTENSIONS = new Set([".sh", ".ts", ".js", ".ps1", ".cmd", ".bat"])
|
|
5
|
+
|
|
6
|
+
export interface AssetSpec {
|
|
7
|
+
stashDir: string
|
|
8
|
+
isRelevantFile: (fileName: string) => boolean
|
|
9
|
+
toCanonicalName: (typeRoot: string, filePath: string) => string | undefined
|
|
10
|
+
toAssetPath: (typeRoot: string, name: string) => string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const markdownSpec: Omit<AssetSpec, "stashDir"> = {
|
|
14
|
+
isRelevantFile: (fileName) => path.extname(fileName).toLowerCase() === ".md",
|
|
15
|
+
toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
|
|
16
|
+
toAssetPath: (typeRoot, name) => path.join(typeRoot, name),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ASSET_SPECS: Record<AgentikitAssetType, AssetSpec> = {
|
|
20
|
+
tool: {
|
|
21
|
+
stashDir: "tools",
|
|
22
|
+
isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path.extname(fileName).toLowerCase()),
|
|
23
|
+
toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
|
|
24
|
+
toAssetPath: (typeRoot, name) => path.join(typeRoot, name),
|
|
25
|
+
},
|
|
26
|
+
skill: {
|
|
27
|
+
stashDir: "skills",
|
|
28
|
+
isRelevantFile: (fileName) => fileName === "SKILL.md",
|
|
29
|
+
toCanonicalName: (typeRoot, filePath) => {
|
|
30
|
+
const relDir = toPosix(path.dirname(path.relative(typeRoot, filePath)))
|
|
31
|
+
if (!relDir || relDir === ".") return undefined
|
|
32
|
+
return relDir
|
|
33
|
+
},
|
|
34
|
+
toAssetPath: (typeRoot, name) => path.join(typeRoot, name, "SKILL.md"),
|
|
35
|
+
},
|
|
36
|
+
command: { stashDir: "commands", ...markdownSpec },
|
|
37
|
+
agent: { stashDir: "agents", ...markdownSpec },
|
|
38
|
+
knowledge: { stashDir: "knowledge", ...markdownSpec },
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const ASSET_TYPES = Object.keys(ASSET_SPECS) as AgentikitAssetType[]
|
|
42
|
+
|
|
43
|
+
export const TYPE_DIRS: Record<AgentikitAssetType, string> = ASSET_TYPES.reduce(
|
|
44
|
+
(acc, type) => {
|
|
45
|
+
acc[type] = ASSET_SPECS[type].stashDir
|
|
46
|
+
return acc
|
|
47
|
+
},
|
|
48
|
+
{} as Record<AgentikitAssetType, string>,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
export function isRelevantAssetFile(assetType: AgentikitAssetType, fileName: string): boolean {
|
|
52
|
+
return ASSET_SPECS[assetType].isRelevantFile(fileName)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function deriveCanonicalAssetName(
|
|
56
|
+
assetType: AgentikitAssetType,
|
|
57
|
+
typeRoot: string,
|
|
58
|
+
filePath: string,
|
|
59
|
+
): string | undefined {
|
|
60
|
+
return ASSET_SPECS[assetType].toCanonicalName(typeRoot, filePath)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function resolveAssetPathFromName(assetType: AgentikitAssetType, typeRoot: string, name: string): string {
|
|
64
|
+
return ASSET_SPECS[assetType].toAssetPath(typeRoot, name)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function toPosix(input: string): string {
|
|
68
|
+
return input.replace(/\\/g, "/")
|
|
69
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,60 +1,296 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { defineCommand, runMain } from "citty"
|
|
3
|
+
import {
|
|
4
|
+
agentikitAdd,
|
|
5
|
+
agentikitList,
|
|
6
|
+
agentikitReinstall,
|
|
7
|
+
agentikitRemove,
|
|
8
|
+
agentikitSearch,
|
|
9
|
+
agentikitShow,
|
|
10
|
+
agentikitUpdate,
|
|
11
|
+
type KnowledgeView,
|
|
12
|
+
} from "./stash"
|
|
13
|
+
import type { SearchSource, SearchUsageMode } from "./stash-types"
|
|
14
|
+
import { agentikitInit } from "./init"
|
|
3
15
|
import { agentikitIndex } from "./indexer"
|
|
16
|
+
import { loadConfig, updateConfig, type AgentikitConfig } from "./config"
|
|
17
|
+
import { resolveStashDir } from "./common"
|
|
4
18
|
|
|
5
|
-
const
|
|
6
|
-
|
|
19
|
+
const initCommand = defineCommand({
|
|
20
|
+
meta: { name: "init", description: "Initialize agentikit stash directory and set AGENTIKIT_STASH_DIR" },
|
|
21
|
+
run() {
|
|
22
|
+
return runWithJsonErrors(() => {
|
|
23
|
+
const result = agentikitInit()
|
|
24
|
+
console.log(JSON.stringify(result, null, 2))
|
|
25
|
+
})
|
|
26
|
+
},
|
|
27
|
+
})
|
|
7
28
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
const indexCommand = defineCommand({
|
|
30
|
+
meta: { name: "index", description: "Build search index (incremental by default; --full forces full reindex)" },
|
|
31
|
+
args: {
|
|
32
|
+
full: { type: "boolean", description: "Force full reindex", default: false },
|
|
33
|
+
},
|
|
34
|
+
async run({ args }) {
|
|
35
|
+
await runWithJsonErrors(async () => {
|
|
36
|
+
const result = await agentikitIndex({ full: args.full })
|
|
37
|
+
console.log(JSON.stringify(result, null, 2))
|
|
38
|
+
})
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const searchCommand = defineCommand({
|
|
43
|
+
meta: { name: "search", description: "Search the stash" },
|
|
44
|
+
args: {
|
|
45
|
+
query: { type: "positional", description: "Search query", required: false, default: "" },
|
|
46
|
+
type: { type: "string", description: "Asset type filter (tool|skill|command|agent|knowledge|any)" },
|
|
47
|
+
limit: { type: "string", description: "Maximum number of results" },
|
|
48
|
+
usage: { type: "string", description: "Usage metadata mode (none|both|item|guide)", default: "both" },
|
|
49
|
+
source: { type: "string", description: "Search source (local|registry|both)", default: "local" },
|
|
50
|
+
},
|
|
51
|
+
async run({ args }) {
|
|
52
|
+
await runWithJsonErrors(async () => {
|
|
53
|
+
const type = args.type as "tool" | "skill" | "command" | "agent" | "knowledge" | "any" | undefined
|
|
54
|
+
const limit = args.limit ? parseInt(args.limit, 10) : undefined
|
|
55
|
+
const usage = parseSearchUsageMode(args.usage)
|
|
56
|
+
const source = parseSearchSource(args.source)
|
|
57
|
+
console.log(JSON.stringify(await agentikitSearch({ query: args.query, type, limit, usage, source }), null, 2))
|
|
58
|
+
})
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const addCommand = defineCommand({
|
|
63
|
+
meta: { name: "add", description: "Install a registry package into the stash" },
|
|
64
|
+
args: {
|
|
65
|
+
ref: { type: "positional", description: "Registry ref (npm package, owner/repo, or github URL)", required: true },
|
|
66
|
+
},
|
|
67
|
+
async run({ args }) {
|
|
68
|
+
await runWithJsonErrors(async () => {
|
|
69
|
+
console.log(JSON.stringify(await agentikitAdd({ ref: args.ref }), null, 2))
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const listCommand = defineCommand({
|
|
75
|
+
meta: { name: "list", description: "List installed registry packages from config" },
|
|
76
|
+
async run() {
|
|
77
|
+
await runWithJsonErrors(async () => {
|
|
78
|
+
console.log(JSON.stringify(await agentikitList(), null, 2))
|
|
79
|
+
})
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const removeCommand = defineCommand({
|
|
84
|
+
meta: { name: "remove", description: "Remove an installed registry package by id or ref" },
|
|
85
|
+
args: {
|
|
86
|
+
target: { type: "positional", description: "Installed target (id or ref)", required: true },
|
|
87
|
+
},
|
|
88
|
+
async run({ args }) {
|
|
89
|
+
await runWithJsonErrors(async () => {
|
|
90
|
+
console.log(JSON.stringify(await agentikitRemove({ target: args.target }), null, 2))
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const updateCommand = defineCommand({
|
|
96
|
+
meta: { name: "update", description: "Update one or all installed registry packages" },
|
|
97
|
+
args: {
|
|
98
|
+
target: { type: "positional", description: "Installed target (id or ref)", required: false },
|
|
99
|
+
all: { type: "boolean", description: "Update all installed entries", default: false },
|
|
100
|
+
},
|
|
101
|
+
async run({ args }) {
|
|
102
|
+
await runWithJsonErrors(async () => {
|
|
103
|
+
console.log(JSON.stringify(await agentikitUpdate({ target: args.target, all: args.all }), null, 2))
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const reinstallCommand = defineCommand({
|
|
109
|
+
meta: { name: "reinstall", description: "Reinstall one or all installed registry packages" },
|
|
110
|
+
args: {
|
|
111
|
+
target: { type: "positional", description: "Installed target (id or ref)", required: false },
|
|
112
|
+
all: { type: "boolean", description: "Reinstall all installed entries", default: false },
|
|
113
|
+
},
|
|
114
|
+
async run({ args }) {
|
|
115
|
+
await runWithJsonErrors(async () => {
|
|
116
|
+
console.log(JSON.stringify(await agentikitReinstall({ target: args.target, all: args.all }), null, 2))
|
|
117
|
+
})
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const showCommand = defineCommand({
|
|
122
|
+
meta: { name: "show", description: "Show a stash asset by ref (e.g. agent:bunjs-typescript-coder.md)" },
|
|
123
|
+
args: {
|
|
124
|
+
ref: { type: "positional", description: "Asset ref (type:name)", required: true },
|
|
125
|
+
view: { type: "string", description: "Knowledge view mode (full|toc|frontmatter|section|lines)" },
|
|
126
|
+
heading: { type: "string", description: "Section heading (for --view section)" },
|
|
127
|
+
start: { type: "string", description: "Start line (for --view lines)" },
|
|
128
|
+
end: { type: "string", description: "End line (for --view lines)" },
|
|
129
|
+
},
|
|
130
|
+
run({ args }) {
|
|
131
|
+
return runWithJsonErrors(() => {
|
|
132
|
+
let view: KnowledgeView | undefined
|
|
133
|
+
if (args.view) {
|
|
134
|
+
switch (args.view) {
|
|
135
|
+
case "section":
|
|
136
|
+
view = { mode: "section", heading: args.heading ?? "" }
|
|
137
|
+
break
|
|
138
|
+
case "lines":
|
|
139
|
+
view = {
|
|
140
|
+
mode: "lines",
|
|
141
|
+
start: Number(args.start ?? "1"),
|
|
142
|
+
end: args.end ? parseInt(args.end, 10) : Number.MAX_SAFE_INTEGER,
|
|
143
|
+
}
|
|
144
|
+
break
|
|
145
|
+
case "toc":
|
|
146
|
+
case "frontmatter":
|
|
147
|
+
case "full":
|
|
148
|
+
view = { mode: args.view }
|
|
149
|
+
break
|
|
150
|
+
default:
|
|
151
|
+
throw new Error(`Unknown view mode: ${args.view}. Expected one of: full|toc|frontmatter|section|lines`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
console.log(JSON.stringify(agentikitShow({ ref: args.ref, view }), null, 2))
|
|
155
|
+
})
|
|
156
|
+
},
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const configCommand = defineCommand({
|
|
160
|
+
meta: { name: "config", description: "Show or update configuration" },
|
|
161
|
+
args: {
|
|
162
|
+
set: { type: "string", description: "Update a config key (key=value format)" },
|
|
163
|
+
},
|
|
164
|
+
run({ args }) {
|
|
165
|
+
return runWithJsonErrors(() => {
|
|
166
|
+
const stashDir = resolveStashDir()
|
|
167
|
+
|
|
168
|
+
if (args.set) {
|
|
169
|
+
const eqIndex = args.set.indexOf("=")
|
|
170
|
+
if (eqIndex === -1) {
|
|
171
|
+
throw new Error("--set expects key=value format")
|
|
172
|
+
}
|
|
173
|
+
const key = args.set.slice(0, eqIndex)
|
|
174
|
+
const value = args.set.slice(eqIndex + 1)
|
|
175
|
+
const partial = parseConfigValue(key, value)
|
|
176
|
+
const config = updateConfig(partial, stashDir)
|
|
177
|
+
console.log(JSON.stringify(config, null, 2))
|
|
178
|
+
} else {
|
|
179
|
+
const config = loadConfig(stashDir)
|
|
180
|
+
console.log(JSON.stringify(config, null, 2))
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
},
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const main = defineCommand({
|
|
187
|
+
meta: {
|
|
188
|
+
name: "akm",
|
|
189
|
+
description: "CLI tool to search, open, and run extension assets from an agentikit stash directory.",
|
|
190
|
+
},
|
|
191
|
+
subCommands: {
|
|
192
|
+
init: initCommand,
|
|
193
|
+
index: indexCommand,
|
|
194
|
+
add: addCommand,
|
|
195
|
+
list: listCommand,
|
|
196
|
+
remove: removeCommand,
|
|
197
|
+
update: updateCommand,
|
|
198
|
+
reinstall: reinstallCommand,
|
|
199
|
+
search: searchCommand,
|
|
200
|
+
show: showCommand,
|
|
201
|
+
config: configCommand,
|
|
202
|
+
},
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
runMain(main)
|
|
206
|
+
|
|
207
|
+
const SEARCH_USAGE_MODES: SearchUsageMode[] = ["none", "both", "item", "guide"]
|
|
208
|
+
const SEARCH_SOURCES: SearchSource[] = ["local", "registry", "both"]
|
|
209
|
+
|
|
210
|
+
function parseSearchUsageMode(value: string): SearchUsageMode {
|
|
211
|
+
if ((SEARCH_USAGE_MODES as string[]).includes(value)) return value as SearchUsageMode
|
|
212
|
+
throw new Error(`Invalid value for --usage: ${value}. Expected one of: ${SEARCH_USAGE_MODES.join("|")}`)
|
|
11
213
|
}
|
|
12
214
|
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
console.error("Commands:")
|
|
17
|
-
console.error(" init Initialize agentikit stash directory and set AGENTIKIT_STASH_DIR")
|
|
18
|
-
console.error(" index Build search index with metadata generation")
|
|
19
|
-
console.error(" search [query] Search the stash (--type tool|skill|command|agent|any) (--limit N)")
|
|
20
|
-
console.error(" open <type:name> Open a stash asset by ref")
|
|
21
|
-
console.error(" run <type:name> Run a tool by ref")
|
|
22
|
-
process.exit(1)
|
|
215
|
+
function parseSearchSource(value: string): SearchSource {
|
|
216
|
+
if ((SEARCH_SOURCES as string[]).includes(value)) return value as SearchSource
|
|
217
|
+
throw new Error(`Invalid value for --source: ${value}. Expected one of: ${SEARCH_SOURCES.join("|")}`)
|
|
23
218
|
}
|
|
24
219
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
220
|
+
function parseConnectionValue(
|
|
221
|
+
key: string,
|
|
222
|
+
value: string,
|
|
223
|
+
exampleEndpoint: string,
|
|
224
|
+
exampleModel: string,
|
|
225
|
+
): { endpoint: string; model: string; apiKey?: string } | undefined {
|
|
226
|
+
if (value === "null" || value === "") return undefined
|
|
227
|
+
let parsed: unknown
|
|
228
|
+
try {
|
|
229
|
+
parsed = JSON.parse(value)
|
|
230
|
+
} catch {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Invalid value for ${key}: expected JSON object with endpoint and model`
|
|
233
|
+
+ ` (e.g. '{"endpoint":"${exampleEndpoint}","model":"${exampleModel}"}')`,
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
237
|
+
throw new Error(`Invalid value for ${key}: expected a JSON object`)
|
|
30
238
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
break
|
|
239
|
+
const obj = parsed as Record<string, unknown>
|
|
240
|
+
if (typeof obj.endpoint !== "string" || !obj.endpoint || typeof obj.model !== "string" || !obj.model) {
|
|
241
|
+
throw new Error(`Invalid value for ${key}: "endpoint" and "model" are required string fields`)
|
|
35
242
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const limitStr = flag("--limit")
|
|
40
|
-
const limit = limitStr ? parseInt(limitStr, 10) : undefined
|
|
41
|
-
console.log(JSON.stringify(agentikitSearch({ query, type, limit }), null, 2))
|
|
42
|
-
break
|
|
243
|
+
const result: { endpoint: string; model: string; apiKey?: string } = {
|
|
244
|
+
endpoint: obj.endpoint,
|
|
245
|
+
model: obj.model,
|
|
43
246
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
247
|
+
if (typeof obj.apiKey === "string" && obj.apiKey) {
|
|
248
|
+
result.apiKey = obj.apiKey
|
|
249
|
+
}
|
|
250
|
+
return result
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function parseConfigValue(key: string, value: string): Partial<AgentikitConfig> {
|
|
254
|
+
switch (key) {
|
|
255
|
+
case "semanticSearch":
|
|
256
|
+
if (value !== "true" && value !== "false") {
|
|
257
|
+
throw new Error(`Invalid value for semanticSearch: expected "true" or "false"`)
|
|
258
|
+
}
|
|
259
|
+
return { semanticSearch: value === "true" }
|
|
260
|
+
case "additionalStashDirs":
|
|
261
|
+
try {
|
|
262
|
+
const parsed = JSON.parse(value)
|
|
263
|
+
if (!Array.isArray(parsed)) throw new Error("expected JSON array")
|
|
264
|
+
return { additionalStashDirs: parsed.filter((d: unknown): d is string => typeof d === "string") }
|
|
265
|
+
} catch {
|
|
266
|
+
throw new Error(`Invalid value for additionalStashDirs: expected JSON array (e.g. '["/path/a","/path/b"]')`)
|
|
267
|
+
}
|
|
268
|
+
case "embedding":
|
|
269
|
+
return { embedding: parseConnectionValue("embedding", value, "http://localhost:11434/v1/embeddings", "nomic-embed-text") }
|
|
270
|
+
case "llm":
|
|
271
|
+
return { llm: parseConnectionValue("llm", value, "http://localhost:11434/v1/chat/completions", "llama3.2") }
|
|
272
|
+
default:
|
|
273
|
+
throw new Error(`Unknown config key: ${key}`)
|
|
49
274
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async function runWithJsonErrors(fn: (() => void) | (() => Promise<void>)): Promise<void> {
|
|
278
|
+
try {
|
|
279
|
+
await fn()
|
|
280
|
+
} catch (error: unknown) {
|
|
281
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
282
|
+
const hint = buildHint(message)
|
|
283
|
+
console.error(JSON.stringify({ ok: false, error: message, hint }, null, 2))
|
|
284
|
+
process.exit(1)
|
|
57
285
|
}
|
|
58
|
-
|
|
59
|
-
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function buildHint(message: string): string | undefined {
|
|
289
|
+
if (message.includes("AGENTIKIT_STASH_DIR")) return "Run `akm init` or set AGENTIKIT_STASH_DIR to a valid directory."
|
|
290
|
+
if (message.includes("Either <target> or --all is required")) return "Use `akm update --all` or pass a target like `akm update npm:@scope/pkg`."
|
|
291
|
+
if (message.includes("Specify either <target> or --all")) return "Use only one: a positional target or `--all`."
|
|
292
|
+
if (message.includes("No installed registry entry matched target")) return "Run `akm list` to view installed ids/refs, then retry with one of those values."
|
|
293
|
+
if (message.includes("Invalid value for --source")) return "Pick one of: local, registry, both."
|
|
294
|
+
if (message.includes("Invalid value for --usage")) return "Pick one of: none, both, item, guide."
|
|
295
|
+
return undefined
|
|
60
296
|
}
|