agentikit 0.0.7 → 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.
- package/README.md +113 -77
- package/dist/index.d.ts +13 -3
- package/dist/index.js +7 -2
- package/dist/src/asset-spec.d.ts +14 -0
- package/dist/src/asset-spec.js +46 -0
- package/dist/src/cli.js +154 -52
- package/dist/src/common.d.ts +8 -0
- package/dist/src/common.js +46 -0
- package/dist/src/config.d.ts +31 -0
- package/dist/src/config.js +74 -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 +10 -2
- package/dist/src/metadata.js +146 -30
- 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-ref.d.ts +7 -0
- package/dist/src/stash-ref.js +33 -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 +6 -0
- package/dist/src/stash-search.js +269 -0
- package/dist/src/stash-show.d.ts +5 -0
- package/dist/src/stash-show.js +107 -0
- package/dist/src/stash-types.d.ts +53 -0
- package/dist/src/stash-types.js +1 -0
- package/dist/src/stash.d.ts +8 -63
- package/dist/src/stash.js +4 -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 +164 -48
- package/src/common.ts +58 -0
- package/src/config.ts +124 -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 +157 -29
- 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-ref.ts +41 -0
- package/src/stash-resolve.ts +47 -0
- package/src/stash-search.ts +343 -0
- package/src/stash-show.ts +104 -0
- package/src/stash-types.ts +46 -0
- package/src/stash.ts +16 -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.8",
|
|
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,176 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { defineCommand, runMain } from "citty"
|
|
3
|
+
import { agentikitSearch, agentikitShow, type KnowledgeView } from "./stash"
|
|
4
|
+
import { agentikitInit } from "./init"
|
|
3
5
|
import { agentikitIndex } from "./indexer"
|
|
6
|
+
import { loadConfig, updateConfig, type AgentikitConfig } from "./config"
|
|
7
|
+
import { resolveStashDir } from "./common"
|
|
4
8
|
|
|
5
|
-
const
|
|
6
|
-
|
|
9
|
+
const initCommand = defineCommand({
|
|
10
|
+
meta: { name: "init", description: "Initialize agentikit stash directory and set AGENTIKIT_STASH_DIR" },
|
|
11
|
+
run() {
|
|
12
|
+
const result = agentikitInit()
|
|
13
|
+
console.log(JSON.stringify(result, null, 2))
|
|
14
|
+
},
|
|
15
|
+
})
|
|
7
16
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
17
|
+
const indexCommand = defineCommand({
|
|
18
|
+
meta: { name: "index", description: "Build search index (incremental by default; --full forces full reindex)" },
|
|
19
|
+
args: {
|
|
20
|
+
full: { type: "boolean", description: "Force full reindex", default: false },
|
|
21
|
+
},
|
|
22
|
+
async run({ args }) {
|
|
23
|
+
const result = await agentikitIndex({ full: args.full })
|
|
24
|
+
console.log(JSON.stringify(result, null, 2))
|
|
25
|
+
},
|
|
26
|
+
})
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
28
|
+
const searchCommand = defineCommand({
|
|
29
|
+
meta: { name: "search", description: "Search the stash" },
|
|
30
|
+
args: {
|
|
31
|
+
query: { type: "positional", description: "Search query", required: false, default: "" },
|
|
32
|
+
type: { type: "string", description: "Asset type filter (tool|skill|command|agent|knowledge|any)" },
|
|
33
|
+
limit: { type: "string", description: "Maximum number of results" },
|
|
34
|
+
},
|
|
35
|
+
async run({ args }) {
|
|
36
|
+
const type = args.type as "tool" | "skill" | "command" | "agent" | "knowledge" | "any" | undefined
|
|
37
|
+
const limit = args.limit ? parseInt(args.limit, 10) : undefined
|
|
38
|
+
console.log(JSON.stringify(await agentikitSearch({ query: args.query, type, limit }), null, 2))
|
|
39
|
+
},
|
|
40
|
+
})
|
|
24
41
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
const showCommand = defineCommand({
|
|
43
|
+
meta: { name: "show", description: "Show a stash asset by ref (e.g. agent:bunjs-typescript-coder.md)" },
|
|
44
|
+
args: {
|
|
45
|
+
ref: { type: "positional", description: "Asset ref (type:name)", required: true },
|
|
46
|
+
view: { type: "string", description: "Knowledge view mode (full|toc|frontmatter|section|lines)" },
|
|
47
|
+
heading: { type: "string", description: "Section heading (for --view section)" },
|
|
48
|
+
start: { type: "string", description: "Start line (for --view lines)" },
|
|
49
|
+
end: { type: "string", description: "End line (for --view lines)" },
|
|
50
|
+
},
|
|
51
|
+
run({ args }) {
|
|
52
|
+
let view: KnowledgeView | undefined
|
|
53
|
+
if (args.view) {
|
|
54
|
+
switch (args.view) {
|
|
55
|
+
case "section":
|
|
56
|
+
view = { mode: "section", heading: args.heading ?? "" }
|
|
57
|
+
break
|
|
58
|
+
case "lines":
|
|
59
|
+
view = {
|
|
60
|
+
mode: "lines",
|
|
61
|
+
start: Number(args.start ?? "1"),
|
|
62
|
+
end: args.end ? parseInt(args.end, 10) : Number.MAX_SAFE_INTEGER,
|
|
63
|
+
}
|
|
64
|
+
break
|
|
65
|
+
case "toc":
|
|
66
|
+
case "frontmatter":
|
|
67
|
+
case "full":
|
|
68
|
+
view = { mode: args.view }
|
|
69
|
+
break
|
|
70
|
+
default:
|
|
71
|
+
console.error(`Unknown view mode: ${args.view}`)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
console.log(JSON.stringify(agentikitShow({ ref: args.ref, view }), null, 2))
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const configCommand = defineCommand({
|
|
80
|
+
meta: { name: "config", description: "Show or update configuration" },
|
|
81
|
+
args: {
|
|
82
|
+
set: { type: "string", description: "Update a config key (key=value format)" },
|
|
83
|
+
},
|
|
84
|
+
run({ args }) {
|
|
85
|
+
const stashDir = resolveStashDir()
|
|
86
|
+
|
|
87
|
+
if (args.set) {
|
|
88
|
+
const eqIndex = args.set.indexOf("=")
|
|
89
|
+
if (eqIndex === -1) {
|
|
90
|
+
console.error("Error: --set expects key=value format")
|
|
91
|
+
process.exit(1)
|
|
92
|
+
}
|
|
93
|
+
const key = args.set.slice(0, eqIndex)
|
|
94
|
+
const value = args.set.slice(eqIndex + 1)
|
|
95
|
+
const partial = parseConfigValue(key, value)
|
|
96
|
+
const config = updateConfig(partial, stashDir)
|
|
97
|
+
console.log(JSON.stringify(config, null, 2))
|
|
98
|
+
} else {
|
|
99
|
+
const config = loadConfig(stashDir)
|
|
100
|
+
console.log(JSON.stringify(config, null, 2))
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const main = defineCommand({
|
|
106
|
+
meta: {
|
|
107
|
+
name: "akm",
|
|
108
|
+
description: "CLI tool to search, open, and run extension assets from an agentikit stash directory.",
|
|
109
|
+
},
|
|
110
|
+
subCommands: {
|
|
111
|
+
init: initCommand,
|
|
112
|
+
index: indexCommand,
|
|
113
|
+
search: searchCommand,
|
|
114
|
+
show: showCommand,
|
|
115
|
+
config: configCommand,
|
|
116
|
+
},
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
runMain(main)
|
|
120
|
+
|
|
121
|
+
function parseConnectionValue(
|
|
122
|
+
key: string,
|
|
123
|
+
value: string,
|
|
124
|
+
exampleEndpoint: string,
|
|
125
|
+
exampleModel: string,
|
|
126
|
+
): { endpoint: string; model: string; apiKey?: string } | undefined {
|
|
127
|
+
if (value === "null" || value === "") return undefined
|
|
128
|
+
let parsed: unknown
|
|
129
|
+
try {
|
|
130
|
+
parsed = JSON.parse(value)
|
|
131
|
+
} catch {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Invalid value for ${key}: expected JSON object with endpoint and model`
|
|
134
|
+
+ ` (e.g. '{"endpoint":"${exampleEndpoint}","model":"${exampleModel}"}')`,
|
|
135
|
+
)
|
|
30
136
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
console.log(JSON.stringify(result, null, 2))
|
|
34
|
-
break
|
|
137
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
138
|
+
throw new Error(`Invalid value for ${key}: expected a JSON object`)
|
|
35
139
|
}
|
|
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
|
|
140
|
+
const obj = parsed as Record<string, unknown>
|
|
141
|
+
if (typeof obj.endpoint !== "string" || !obj.endpoint || typeof obj.model !== "string" || !obj.model) {
|
|
142
|
+
throw new Error(`Invalid value for ${key}: "endpoint" and "model" are required string fields`)
|
|
43
143
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
console.log(JSON.stringify(agentikitOpen({ ref }), null, 2))
|
|
48
|
-
break
|
|
144
|
+
const result: { endpoint: string; model: string; apiKey?: string } = {
|
|
145
|
+
endpoint: obj.endpoint,
|
|
146
|
+
model: obj.model,
|
|
49
147
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
if (typeof obj.apiKey === "string" && obj.apiKey) {
|
|
149
|
+
result.apiKey = obj.apiKey
|
|
150
|
+
}
|
|
151
|
+
return result
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function parseConfigValue(key: string, value: string): Partial<AgentikitConfig> {
|
|
155
|
+
switch (key) {
|
|
156
|
+
case "semanticSearch":
|
|
157
|
+
if (value !== "true" && value !== "false") {
|
|
158
|
+
throw new Error(`Invalid value for semanticSearch: expected "true" or "false"`)
|
|
159
|
+
}
|
|
160
|
+
return { semanticSearch: value === "true" }
|
|
161
|
+
case "additionalStashDirs":
|
|
162
|
+
try {
|
|
163
|
+
const parsed = JSON.parse(value)
|
|
164
|
+
if (!Array.isArray(parsed)) throw new Error("expected JSON array")
|
|
165
|
+
return { additionalStashDirs: parsed.filter((d: unknown): d is string => typeof d === "string") }
|
|
166
|
+
} catch {
|
|
167
|
+
throw new Error(`Invalid value for additionalStashDirs: expected JSON array (e.g. '["/path/a","/path/b"]')`)
|
|
168
|
+
}
|
|
169
|
+
case "embedding":
|
|
170
|
+
return { embedding: parseConnectionValue("embedding", value, "http://localhost:11434/v1/embeddings", "nomic-embed-text") }
|
|
171
|
+
case "llm":
|
|
172
|
+
return { llm: parseConnectionValue("llm", value, "http://localhost:11434/v1/chat/completions", "llama3.2") }
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`Unknown config key: ${key}`)
|
|
57
175
|
}
|
|
58
|
-
default:
|
|
59
|
-
usage()
|
|
60
176
|
}
|
package/src/common.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { TYPE_DIRS } from "./asset-spec"
|
|
4
|
+
|
|
5
|
+
// ── Types ───────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export type AgentikitAssetType = "tool" | "skill" | "command" | "agent" | "knowledge"
|
|
8
|
+
|
|
9
|
+
// ── Constants ───────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
export const IS_WINDOWS = process.platform === "win32"
|
|
12
|
+
export { SCRIPT_EXTENSIONS, TYPE_DIRS } from "./asset-spec"
|
|
13
|
+
|
|
14
|
+
// ── Validators ──────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
export function isAssetType(type: string): type is AgentikitAssetType {
|
|
17
|
+
return type in TYPE_DIRS
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── Utilities ───────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
export function resolveStashDir(): string {
|
|
23
|
+
const raw = process.env.AGENTIKIT_STASH_DIR?.trim()
|
|
24
|
+
if (!raw) {
|
|
25
|
+
throw new Error("AGENTIKIT_STASH_DIR is not set. Set it to your Agentikit stash path.")
|
|
26
|
+
}
|
|
27
|
+
const stashDir = path.resolve(raw)
|
|
28
|
+
let stat: fs.Stats
|
|
29
|
+
try {
|
|
30
|
+
stat = fs.statSync(stashDir)
|
|
31
|
+
} catch {
|
|
32
|
+
throw new Error(`Unable to read AGENTIKIT_STASH_DIR at "${stashDir}".`)
|
|
33
|
+
}
|
|
34
|
+
if (!stat.isDirectory()) {
|
|
35
|
+
throw new Error(`AGENTIKIT_STASH_DIR must point to a directory: "${stashDir}".`)
|
|
36
|
+
}
|
|
37
|
+
return stashDir
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function toPosix(input: string): string {
|
|
41
|
+
return input.replace(/\\/g, "/")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function hasErrnoCode(error: unknown, code: string): boolean {
|
|
45
|
+
if (typeof error !== "object" || error === null || !("code" in error)) return false
|
|
46
|
+
return (error as Record<string, unknown>).code === code
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isWithin(candidate: string, root: string): boolean {
|
|
50
|
+
const normalizedRoot = normalizeFsPathForComparison(path.resolve(root))
|
|
51
|
+
const normalizedCandidate = normalizeFsPathForComparison(path.resolve(candidate))
|
|
52
|
+
const rel = path.relative(normalizedRoot, normalizedCandidate)
|
|
53
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeFsPathForComparison(value: string): string {
|
|
57
|
+
return process.platform === "win32" ? value.toLowerCase() : value
|
|
58
|
+
}
|