agentikit 0.0.14 → 0.0.15
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 +14 -7
- package/dist/asset-spec.js +11 -2
- package/dist/asset-type-handler.js +4 -3
- package/dist/cli.js +100 -62
- package/dist/common.js +6 -6
- package/dist/config-cli.js +23 -25
- package/dist/config.js +3 -1
- package/dist/db.js +28 -30
- package/dist/errors.js +28 -0
- package/dist/file-context.js +36 -6
- package/dist/frontmatter.js +1 -1
- package/dist/github.js +1 -3
- package/dist/handlers/agent-handler.js +6 -13
- package/dist/handlers/command-handler.js +8 -13
- package/dist/handlers/handler-bridge.js +51 -0
- package/dist/handlers/index.js +12 -10
- package/dist/handlers/knowledge-handler.js +7 -31
- package/dist/handlers/script-handler.js +9 -45
- package/dist/handlers/skill-handler.js +5 -6
- package/dist/handlers/tool-handler.js +8 -24
- package/dist/indexer.js +21 -21
- package/dist/init.js +3 -3
- package/dist/llm.js +6 -11
- package/dist/lockfile.js +9 -4
- package/dist/matchers.js +11 -5
- package/dist/metadata.js +25 -16
- package/dist/paths.js +5 -4
- package/dist/registry-install.js +9 -5
- package/dist/registry-resolve.js +12 -8
- package/dist/registry-search.js +5 -5
- package/dist/renderers.js +24 -14
- package/dist/ripgrep-install.js +3 -22
- package/dist/ripgrep.js +1 -1
- package/dist/self-update.js +15 -9
- package/dist/stash-add.js +4 -3
- package/dist/stash-clone.js +4 -4
- package/dist/stash-ref.js +10 -9
- package/dist/stash-registry.js +6 -5
- package/dist/stash-resolve.js +10 -9
- package/dist/stash-search.js +27 -24
- package/dist/stash-show.js +8 -7
- package/dist/stash-source.js +10 -11
- package/dist/submit.js +26 -21
- package/dist/tool-runner.js +1 -5
- package/dist/warn.js +20 -0
- package/package.json +7 -3
package/dist/db.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
1
2
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import
|
|
4
|
+
import path from "node:path";
|
|
5
5
|
import { cosineSimilarity } from "./embedder";
|
|
6
|
-
import { getDbPath
|
|
6
|
+
import { getDbPath } from "./paths";
|
|
7
|
+
import { warn } from "./warn";
|
|
7
8
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
8
9
|
export const DB_VERSION = 6;
|
|
9
10
|
export const EMBEDDING_DIM = 384;
|
|
10
|
-
// ── Path ────────────────────────────────────────────────────────────────────
|
|
11
|
-
export function getDbPath() {
|
|
12
|
-
return _getDbPath();
|
|
13
|
-
}
|
|
14
11
|
// ── Database lifecycle ──────────────────────────────────────────────────────
|
|
15
12
|
export function openDatabase(dbPath, options) {
|
|
16
13
|
const resolvedPath = dbPath ?? getDbPath();
|
|
@@ -63,12 +60,14 @@ export function warnIfVecMissing(db, { once } = { once: false }) {
|
|
|
63
60
|
const row = db.prepare("SELECT COUNT(*) AS cnt FROM embeddings").get();
|
|
64
61
|
const count = row?.cnt ?? 0;
|
|
65
62
|
if (count >= VEC_FALLBACK_THRESHOLD) {
|
|
66
|
-
|
|
63
|
+
warn("Semantic search is using JS fallback for %d entries. Install sqlite-vec for faster performance.\n See: %s", count, VEC_DOCS_URL);
|
|
67
64
|
if (once)
|
|
68
65
|
vecInitWarned = true;
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
|
-
catch {
|
|
68
|
+
catch {
|
|
69
|
+
/* embeddings table may not exist yet during init */
|
|
70
|
+
}
|
|
72
71
|
}
|
|
73
72
|
// ── Schema ──────────────────────────────────────────────────────────────────
|
|
74
73
|
function ensureSchema(db, embeddingDim) {
|
|
@@ -114,9 +113,7 @@ function ensureSchema(db, embeddingDim) {
|
|
|
114
113
|
);
|
|
115
114
|
`);
|
|
116
115
|
// FTS5 table — standalone with explicit entry_id for joining
|
|
117
|
-
const ftsExists = db
|
|
118
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries_fts'")
|
|
119
|
-
.get();
|
|
116
|
+
const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries_fts'").get();
|
|
120
117
|
if (!ftsExists) {
|
|
121
118
|
db.exec(`
|
|
122
119
|
CREATE VIRTUAL TABLE entries_fts USING fts5(
|
|
@@ -134,11 +131,11 @@ function ensureSchema(db, embeddingDim) {
|
|
|
134
131
|
try {
|
|
135
132
|
db.exec("DROP TABLE IF EXISTS entries_vec");
|
|
136
133
|
}
|
|
137
|
-
catch {
|
|
134
|
+
catch {
|
|
135
|
+
/* ignore */
|
|
136
|
+
}
|
|
138
137
|
}
|
|
139
|
-
const vecExists = db
|
|
140
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries_vec'")
|
|
141
|
-
.get();
|
|
138
|
+
const vecExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries_vec'").get();
|
|
142
139
|
if (!vecExists) {
|
|
143
140
|
db.exec(`
|
|
144
141
|
CREATE VIRTUAL TABLE entries_vec USING vec0(
|
|
@@ -182,19 +179,21 @@ export function upsertEntry(db, entryKey, dirPath, filePath, stashDir, entry, se
|
|
|
182
179
|
return row.id;
|
|
183
180
|
}
|
|
184
181
|
export function deleteEntriesByDir(db, dirPath) {
|
|
185
|
-
const ids = db
|
|
186
|
-
.prepare("SELECT id FROM entries WHERE dir_path = ?")
|
|
187
|
-
.all(dirPath);
|
|
182
|
+
const ids = db.prepare("SELECT id FROM entries WHERE dir_path = ?").all(dirPath);
|
|
188
183
|
for (const { id } of ids) {
|
|
189
184
|
try {
|
|
190
185
|
db.prepare("DELETE FROM embeddings WHERE id = ?").run(id);
|
|
191
186
|
}
|
|
192
|
-
catch {
|
|
187
|
+
catch {
|
|
188
|
+
/* ignore */
|
|
189
|
+
}
|
|
193
190
|
if (isVecAvailable(db)) {
|
|
194
191
|
try {
|
|
195
192
|
db.prepare("DELETE FROM entries_vec WHERE id = ?").run(id);
|
|
196
193
|
}
|
|
197
|
-
catch {
|
|
194
|
+
catch {
|
|
195
|
+
/* ignore */
|
|
196
|
+
}
|
|
198
197
|
}
|
|
199
198
|
}
|
|
200
199
|
db.prepare("DELETE FROM entries WHERE dir_path = ?").run(dirPath);
|
|
@@ -213,7 +212,9 @@ export function upsertEmbedding(db, entryId, embedding) {
|
|
|
213
212
|
try {
|
|
214
213
|
db.prepare("DELETE FROM entries_vec WHERE id = ?").run(entryId);
|
|
215
214
|
}
|
|
216
|
-
catch {
|
|
215
|
+
catch {
|
|
216
|
+
/* ignore */
|
|
217
|
+
}
|
|
217
218
|
db.prepare("INSERT INTO entries_vec (id, embedding) VALUES (?, ?)").run(entryId, buf);
|
|
218
219
|
}
|
|
219
220
|
}
|
|
@@ -243,9 +244,7 @@ function bufferToFloat32(buf) {
|
|
|
243
244
|
}
|
|
244
245
|
function searchBlobVec(db, queryEmbedding, k) {
|
|
245
246
|
try {
|
|
246
|
-
const rows = db
|
|
247
|
-
.prepare("SELECT id, embedding FROM embeddings")
|
|
248
|
-
.all();
|
|
247
|
+
const rows = db.prepare("SELECT id, embedding FROM embeddings").all();
|
|
249
248
|
if (rows.length === 0)
|
|
250
249
|
return [];
|
|
251
250
|
const scored = [];
|
|
@@ -316,7 +315,7 @@ function sanitizeFtsQuery(query) {
|
|
|
316
315
|
const tokens = query
|
|
317
316
|
.replace(/[^a-zA-Z0-9\s]/g, " ")
|
|
318
317
|
.split(/\s+/)
|
|
319
|
-
.filter((t) => t.length
|
|
318
|
+
.filter((t) => t.length >= 1);
|
|
320
319
|
if (tokens.length === 0)
|
|
321
320
|
return "";
|
|
322
321
|
// Use unquoted tokens so the porter stemmer can normalize word forms
|
|
@@ -327,7 +326,8 @@ export function getAllEntries(db, entryType) {
|
|
|
327
326
|
let sql;
|
|
328
327
|
let params;
|
|
329
328
|
if (entryType && entryType !== "any") {
|
|
330
|
-
sql =
|
|
329
|
+
sql =
|
|
330
|
+
"SELECT id, entry_key, dir_path, file_path, stash_dir, entry_json, search_text FROM entries WHERE entry_type = ?";
|
|
331
331
|
params = [entryType];
|
|
332
332
|
}
|
|
333
333
|
else {
|
|
@@ -350,9 +350,7 @@ export function getEntryCount(db) {
|
|
|
350
350
|
return row.cnt;
|
|
351
351
|
}
|
|
352
352
|
export function getEntryById(db, id) {
|
|
353
|
-
const row = db
|
|
354
|
-
.prepare("SELECT file_path, entry_json FROM entries WHERE id = ?")
|
|
355
|
-
.get(id);
|
|
353
|
+
const row = db.prepare("SELECT file_path, entry_json FROM entries WHERE id = ?").get(id);
|
|
356
354
|
if (!row)
|
|
357
355
|
return undefined;
|
|
358
356
|
return { filePath: row.file_path, entry: JSON.parse(row.entry_json) };
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error classes for structured exit code classification.
|
|
3
|
+
*
|
|
4
|
+
* - ConfigError -> exit 78 (configuration / environment problems)
|
|
5
|
+
* - UsageError -> exit 2 (bad CLI arguments or invalid input)
|
|
6
|
+
* - NotFoundError -> exit 1 (requested resource missing)
|
|
7
|
+
*/
|
|
8
|
+
/** Raised when configuration or environment is invalid or missing. */
|
|
9
|
+
export class ConfigError extends Error {
|
|
10
|
+
constructor(msg) {
|
|
11
|
+
super(msg);
|
|
12
|
+
this.name = "ConfigError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Raised when the user supplies invalid arguments or input. */
|
|
16
|
+
export class UsageError extends Error {
|
|
17
|
+
constructor(msg) {
|
|
18
|
+
super(msg);
|
|
19
|
+
this.name = "UsageError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Raised when a requested resource (asset, entry, file) is not found. */
|
|
23
|
+
export class NotFoundError extends Error {
|
|
24
|
+
constructor(msg) {
|
|
25
|
+
super(msg);
|
|
26
|
+
this.name = "NotFoundError";
|
|
27
|
+
}
|
|
28
|
+
}
|
package/dist/file-context.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import { parseFrontmatter } from "./frontmatter";
|
|
10
9
|
import { toPosix } from "./common";
|
|
10
|
+
import { parseFrontmatter } from "./frontmatter";
|
|
11
11
|
/**
|
|
12
12
|
* Build a FileContext from a stash root and an absolute file path.
|
|
13
13
|
*
|
|
@@ -50,8 +50,7 @@ export function buildFileContext(stashRoot, absPath) {
|
|
|
50
50
|
if (!frontmatterComputed) {
|
|
51
51
|
const raw = this.content();
|
|
52
52
|
const parsed = parseFrontmatter(raw);
|
|
53
|
-
cachedFrontmatter =
|
|
54
|
-
Object.keys(parsed.data).length > 0 ? parsed.data : null;
|
|
53
|
+
cachedFrontmatter = Object.keys(parsed.data).length > 0 ? parsed.data : null;
|
|
55
54
|
frontmatterComputed = true;
|
|
56
55
|
}
|
|
57
56
|
return cachedFrontmatter;
|
|
@@ -70,17 +69,48 @@ const matchers = [];
|
|
|
70
69
|
/** Renderer lookup by name. */
|
|
71
70
|
const renderers = new Map();
|
|
72
71
|
let builtinsInitialized = false;
|
|
72
|
+
/** Pluggable initializer set via `setBuiltinRegistrar`. */
|
|
73
|
+
let builtinRegistrar = null;
|
|
74
|
+
/**
|
|
75
|
+
* Set the function that registers built-in matchers and renderers.
|
|
76
|
+
*
|
|
77
|
+
* This breaks the static import cycle: `file-context.ts` does not need to
|
|
78
|
+
* import `matchers.ts` or `renderers.ts` at the top level. Instead, a
|
|
79
|
+
* one-time call from outside (e.g. the test file or CLI entry) provides the
|
|
80
|
+
* registration callback.
|
|
81
|
+
*
|
|
82
|
+
* If no registrar is set by the time `ensureBuiltinsRegistered` runs, it
|
|
83
|
+
* falls back to a dynamic `require()` for backward compatibility.
|
|
84
|
+
*/
|
|
85
|
+
export function setBuiltinRegistrar(fn) {
|
|
86
|
+
builtinRegistrar = fn;
|
|
87
|
+
}
|
|
73
88
|
/**
|
|
74
89
|
* Ensure that built-in matchers and renderers are registered.
|
|
75
90
|
* Called lazily on first use of runMatchers/getRenderer.
|
|
91
|
+
*
|
|
92
|
+
* Uses the registrar set via `setBuiltinRegistrar`, or falls back to
|
|
93
|
+
* a direct import of the registration modules. The dynamic import
|
|
94
|
+
* avoids a static circular dependency between file-context, renderers,
|
|
95
|
+
* and asset-spec.
|
|
76
96
|
*/
|
|
77
97
|
function ensureBuiltinsRegistered() {
|
|
78
98
|
if (builtinsInitialized)
|
|
79
99
|
return;
|
|
80
100
|
builtinsInitialized = true;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
if (builtinRegistrar) {
|
|
102
|
+
builtinRegistrar();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Lazy inline require avoids a top-level static import cycle:
|
|
106
|
+
// file-context -> renderers -> asset-spec -> asset-type-handler -> handlers -> file-context
|
|
107
|
+
// These are only evaluated once and only when no explicit registrar was set.
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
109
|
+
const { registerBuiltinMatchers } = require("./matchers");
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
111
|
+
const { registerBuiltinRenderers } = require("./renderers");
|
|
112
|
+
registerBuiltinMatchers();
|
|
113
|
+
registerBuiltinRenderers();
|
|
84
114
|
}
|
|
85
115
|
/**
|
|
86
116
|
* Register an AssetMatcher.
|
package/dist/frontmatter.js
CHANGED
|
@@ -18,7 +18,7 @@ export function parseFrontmatter(raw) {
|
|
|
18
18
|
let currentKey = null;
|
|
19
19
|
let nested = null;
|
|
20
20
|
for (const line of parsedBlock.frontmatter.split(/\r?\n/)) {
|
|
21
|
-
const indented = line.match(/^
|
|
21
|
+
const indented = line.match(/^ {2}(\w[\w-]*):\s*(.+)$/);
|
|
22
22
|
if (indented && currentKey && nested) {
|
|
23
23
|
nested[indented[1]] = parseYamlScalar(indented[2].trim());
|
|
24
24
|
continue;
|
package/dist/github.js
CHANGED
|
@@ -10,9 +10,7 @@ export function githubHeaders() {
|
|
|
10
10
|
return headers;
|
|
11
11
|
}
|
|
12
12
|
export function asRecord(value) {
|
|
13
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
14
|
-
? value
|
|
15
|
-
: {};
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
16
14
|
}
|
|
17
15
|
export function asString(value) {
|
|
18
16
|
return typeof value === "string" && value ? value : undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getRenderer } from "../file-context";
|
|
2
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
3
|
+
import { isMarkdownFile, markdownAssetPath, markdownCanonicalName } from "./markdown-helpers";
|
|
3
4
|
export const agentHandler = {
|
|
4
5
|
typeName: "agent",
|
|
5
6
|
stashDir: "agents",
|
|
@@ -7,17 +8,9 @@ export const agentHandler = {
|
|
|
7
8
|
toCanonicalName: markdownCanonicalName,
|
|
8
9
|
toAssetPath: markdownAssetPath,
|
|
9
10
|
buildShowResponse(input) {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
name: input.name,
|
|
14
|
-
path: input.path,
|
|
15
|
-
description: toStringOrUndefined(parsedMd.data.description),
|
|
16
|
-
prompt: "Dispatching prompt must include the agent's full prompt content verbatim; summaries are non-compliant. \n\n"
|
|
17
|
-
+ parsedMd.content,
|
|
18
|
-
toolPolicy: parsedMd.data.tools,
|
|
19
|
-
modelHint: parsedMd.data.model,
|
|
20
|
-
};
|
|
11
|
+
const renderer = getRenderer("agent-md");
|
|
12
|
+
const ctx = showInputToRenderContext(input, "agent-md");
|
|
13
|
+
return renderer.buildShowResponse(ctx);
|
|
21
14
|
},
|
|
22
15
|
defaultUsageGuide: [
|
|
23
16
|
"Read the .md file and dispatch an agent using the content of the file. Use modelHint/toolPolicy when present to run the agent with compatible settings.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getRenderer } from "../file-context";
|
|
2
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
3
|
+
import { isMarkdownFile, markdownAssetPath, markdownCanonicalName } from "./markdown-helpers";
|
|
3
4
|
export const commandHandler = {
|
|
4
5
|
typeName: "command",
|
|
5
6
|
stashDir: "commands",
|
|
@@ -7,19 +8,13 @@ export const commandHandler = {
|
|
|
7
8
|
toCanonicalName: markdownCanonicalName,
|
|
8
9
|
toAssetPath: markdownAssetPath,
|
|
9
10
|
buildShowResponse(input) {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
name: input.name,
|
|
14
|
-
path: input.path,
|
|
15
|
-
description: toStringOrUndefined(parsedMd.data.description),
|
|
16
|
-
template: parsedMd.content,
|
|
17
|
-
modelHint: parsedMd.data.model,
|
|
18
|
-
agent: toStringOrUndefined(parsedMd.data.agent),
|
|
19
|
-
};
|
|
11
|
+
const renderer = getRenderer("command-md");
|
|
12
|
+
const ctx = showInputToRenderContext(input, "command-md");
|
|
13
|
+
return renderer.buildShowResponse(ctx);
|
|
20
14
|
},
|
|
21
15
|
defaultUsageGuide: [
|
|
22
|
-
"Read the .md file, fill placeholders, and run it in the current repo context.",
|
|
16
|
+
"Read the .md file, fill $ARGUMENTS placeholders, and run it in the current repo context.",
|
|
23
17
|
"Use `akm show <openRef>` to retrieve the command template body.",
|
|
18
|
+
"When `agent` is specified, dispatch the command to that agent.",
|
|
24
19
|
],
|
|
25
20
|
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge utility that converts legacy ShowInput into a RenderContext,
|
|
3
|
+
* allowing handlers to delegate their buildShowResponse to renderers.
|
|
4
|
+
*/
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { toPosix } from "../common";
|
|
7
|
+
/**
|
|
8
|
+
* Convert a legacy ShowInput into a RenderContext suitable for passing
|
|
9
|
+
* to an AssetRenderer's buildShowResponse method.
|
|
10
|
+
*
|
|
11
|
+
* This avoids hitting the filesystem since ShowInput already carries
|
|
12
|
+
* the file content.
|
|
13
|
+
*/
|
|
14
|
+
export function showInputToRenderContext(input, rendererName) {
|
|
15
|
+
const absPath = path.resolve(input.path);
|
|
16
|
+
const stashDirs = input.stashDirs ?? [];
|
|
17
|
+
// Derive a stash root from stashDirs if possible
|
|
18
|
+
const stashRoot = stashDirs.find((d) => absPath.startsWith(path.resolve(d) + path.sep)) ?? stashDirs[0] ?? path.dirname(absPath);
|
|
19
|
+
const relPath = toPosix(path.relative(stashRoot, absPath));
|
|
20
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
21
|
+
const fileName = path.basename(absPath);
|
|
22
|
+
const parentDirAbs = path.dirname(absPath);
|
|
23
|
+
const parentDir = path.basename(parentDirAbs);
|
|
24
|
+
const relDir = toPosix(path.dirname(relPath));
|
|
25
|
+
const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
|
|
26
|
+
// Cache the content from input (no filesystem read needed)
|
|
27
|
+
const cachedContent = input.content;
|
|
28
|
+
const matchResult = {
|
|
29
|
+
type: rendererName.split("-")[0], // e.g. "tool" from "tool-script"
|
|
30
|
+
specificity: 10,
|
|
31
|
+
renderer: rendererName,
|
|
32
|
+
meta: { name: input.name, view: input.view },
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
absPath,
|
|
36
|
+
relPath,
|
|
37
|
+
ext,
|
|
38
|
+
fileName,
|
|
39
|
+
parentDir,
|
|
40
|
+
parentDirAbs,
|
|
41
|
+
ancestorDirs,
|
|
42
|
+
stashRoot,
|
|
43
|
+
content: () => cachedContent,
|
|
44
|
+
frontmatter: () => null, // Renderers parse frontmatter from content() themselves
|
|
45
|
+
stat() {
|
|
46
|
+
throw new Error("stat() not available in handler bridge context");
|
|
47
|
+
},
|
|
48
|
+
matchResult,
|
|
49
|
+
stashDirs,
|
|
50
|
+
};
|
|
51
|
+
}
|
package/dist/handlers/index.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { registerAssetType } from "../asset-type-handler";
|
|
2
|
-
import { toolHandler } from "./tool-handler";
|
|
3
|
-
import { skillHandler } from "./skill-handler";
|
|
4
|
-
import { commandHandler } from "./command-handler";
|
|
5
2
|
import { agentHandler } from "./agent-handler";
|
|
3
|
+
import { commandHandler } from "./command-handler";
|
|
6
4
|
import { knowledgeHandler } from "./knowledge-handler";
|
|
7
5
|
import { scriptHandler } from "./script-handler";
|
|
6
|
+
import { skillHandler } from "./skill-handler";
|
|
7
|
+
import { toolHandler } from "./tool-handler";
|
|
8
8
|
/**
|
|
9
9
|
* Register all built-in asset type handlers.
|
|
10
|
-
*
|
|
10
|
+
* Called once from ensureHandlersRegistered in asset-type-handler.ts.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
registerAssetType(
|
|
14
|
-
registerAssetType(
|
|
15
|
-
registerAssetType(
|
|
16
|
-
registerAssetType(
|
|
17
|
-
registerAssetType(
|
|
12
|
+
export function registerBuiltinHandlers() {
|
|
13
|
+
registerAssetType(toolHandler);
|
|
14
|
+
registerAssetType(skillHandler);
|
|
15
|
+
registerAssetType(commandHandler);
|
|
16
|
+
registerAssetType(agentHandler);
|
|
17
|
+
registerAssetType(knowledgeHandler);
|
|
18
|
+
registerAssetType(scriptHandler);
|
|
19
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { getRenderer } from "../file-context";
|
|
3
|
+
import { parseMarkdownToc } from "../markdown";
|
|
4
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
5
|
+
import { isMarkdownFile, markdownAssetPath, markdownCanonicalName } from "./markdown-helpers";
|
|
4
6
|
export const knowledgeHandler = {
|
|
5
7
|
typeName: "knowledge",
|
|
6
8
|
stashDir: "knowledge",
|
|
@@ -8,35 +10,9 @@ export const knowledgeHandler = {
|
|
|
8
10
|
toCanonicalName: markdownCanonicalName,
|
|
9
11
|
toAssetPath: markdownAssetPath,
|
|
10
12
|
buildShowResponse(input) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const toc = parseMarkdownToc(input.content);
|
|
15
|
-
return { type: "knowledge", name: input.name, path: input.path, content: formatToc(toc) };
|
|
16
|
-
}
|
|
17
|
-
case "frontmatter": {
|
|
18
|
-
const fm = extractFrontmatterOnly(input.content);
|
|
19
|
-
return { type: "knowledge", name: input.name, path: input.path, content: fm ?? "(no frontmatter)" };
|
|
20
|
-
}
|
|
21
|
-
case "section": {
|
|
22
|
-
const section = extractSection(input.content, v.heading);
|
|
23
|
-
if (!section) {
|
|
24
|
-
return {
|
|
25
|
-
type: "knowledge",
|
|
26
|
-
name: input.name,
|
|
27
|
-
path: input.path,
|
|
28
|
-
content: `Section "${v.heading}" not found in ${input.name}. Try --view toc to discover available headings.`,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
return { type: "knowledge", name: input.name, path: input.path, content: section.content };
|
|
32
|
-
}
|
|
33
|
-
case "lines": {
|
|
34
|
-
return { type: "knowledge", name: input.name, path: input.path, content: extractLineRange(input.content, v.start, v.end) };
|
|
35
|
-
}
|
|
36
|
-
default: {
|
|
37
|
-
return { type: "knowledge", name: input.name, path: input.path, content: input.content };
|
|
38
|
-
}
|
|
39
|
-
}
|
|
13
|
+
const renderer = getRenderer("knowledge-md");
|
|
14
|
+
const ctx = showInputToRenderContext(input, "knowledge-md");
|
|
15
|
+
return renderer.buildShowResponse(ctx);
|
|
40
16
|
},
|
|
41
17
|
defaultUsageGuide: [
|
|
42
18
|
"Use `akm show <openRef>` to read the document; start with `--view toc` for large files.",
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { SCRIPT_EXTENSIONS_BROAD } from "../asset-spec";
|
|
3
|
+
import { toPosix } from "../common";
|
|
4
|
+
import { getRenderer } from "../file-context";
|
|
5
5
|
import { extractDescriptionFromComments } from "../metadata";
|
|
6
|
-
|
|
7
|
-
const RUNNABLE_EXTENSIONS = SCRIPT_EXTENSIONS;
|
|
6
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
8
7
|
export const scriptHandler = {
|
|
9
8
|
typeName: "script",
|
|
10
9
|
stashDir: "scripts",
|
|
@@ -18,48 +17,13 @@ export const scriptHandler = {
|
|
|
18
17
|
return path.join(typeRoot, name);
|
|
19
18
|
},
|
|
20
19
|
buildShowResponse(input) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const stashDirs = input.stashDirs ?? [];
|
|
25
|
-
const assetStashDir = stashDirs.find((d) => path.resolve(input.path).startsWith(path.resolve(d) + path.sep)) ?? stashDirs[0];
|
|
26
|
-
if (assetStashDir) {
|
|
27
|
-
try {
|
|
28
|
-
const toolInfo = buildToolInfo(assetStashDir, input.path);
|
|
29
|
-
return {
|
|
30
|
-
type: "script",
|
|
31
|
-
name: input.name,
|
|
32
|
-
path: input.path,
|
|
33
|
-
runCmd: toolInfo.runCmd,
|
|
34
|
-
kind: toolInfo.kind,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// Fall through to content display
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// For other extensions or when buildToolInfo fails, show file content
|
|
43
|
-
return {
|
|
44
|
-
type: "script",
|
|
45
|
-
name: input.name,
|
|
46
|
-
path: input.path,
|
|
47
|
-
content: input.content,
|
|
48
|
-
};
|
|
20
|
+
const renderer = getRenderer("script-source");
|
|
21
|
+
const ctx = showInputToRenderContext(input, "script-source");
|
|
22
|
+
return renderer.buildShowResponse(ctx);
|
|
49
23
|
},
|
|
50
24
|
enrichSearchHit(hit, stashDir) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
return;
|
|
54
|
-
try {
|
|
55
|
-
const toolInfo = buildToolInfo(stashDir, hit.path);
|
|
56
|
-
hit.runCmd = toolInfo.runCmd;
|
|
57
|
-
hit.kind = toolInfo.kind;
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
if (!hasErrnoCode(error, "ENOENT"))
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
25
|
+
const renderer = getRenderer("script-source");
|
|
26
|
+
renderer.enrichSearchHit(hit, stashDir);
|
|
63
27
|
},
|
|
64
28
|
defaultUsageGuide: [
|
|
65
29
|
"Use the hit's runCmd for execution when available, or run the script directly with the appropriate interpreter.",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { toPosix } from "../common";
|
|
3
|
+
import { getRenderer } from "../file-context";
|
|
4
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
3
5
|
export const skillHandler = {
|
|
4
6
|
typeName: "skill",
|
|
5
7
|
stashDir: "skills",
|
|
@@ -16,12 +18,9 @@ export const skillHandler = {
|
|
|
16
18
|
return path.join(typeRoot, name, "SKILL.md");
|
|
17
19
|
},
|
|
18
20
|
buildShowResponse(input) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
path: input.path,
|
|
23
|
-
content: input.content,
|
|
24
|
-
};
|
|
21
|
+
const renderer = getRenderer("skill-md");
|
|
22
|
+
const ctx = showInputToRenderContext(input, "skill-md");
|
|
23
|
+
return renderer.buildShowResponse(ctx);
|
|
25
24
|
},
|
|
26
25
|
defaultUsageGuide: [
|
|
27
26
|
"Read and apply the skill instructions as written, then adapt examples to your current repo state and task.",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { SCRIPT_EXTENSIONS } from "../asset-spec";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { toPosix } from "../common";
|
|
4
|
+
import { getRenderer } from "../file-context";
|
|
5
5
|
import { extractDescriptionFromComments } from "../metadata";
|
|
6
|
+
import { showInputToRenderContext } from "./handler-bridge";
|
|
6
7
|
export const toolHandler = {
|
|
7
8
|
typeName: "tool",
|
|
8
9
|
stashDir: "tools",
|
|
@@ -16,30 +17,13 @@ export const toolHandler = {
|
|
|
16
17
|
return path.join(typeRoot, name);
|
|
17
18
|
},
|
|
18
19
|
buildShowResponse(input) {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
return { type: "tool", name: input.name, path: input.path, content: input.content };
|
|
23
|
-
}
|
|
24
|
-
const toolInfo = buildToolInfo(assetStashDir, input.path);
|
|
25
|
-
return {
|
|
26
|
-
type: "tool",
|
|
27
|
-
name: input.name,
|
|
28
|
-
path: input.path,
|
|
29
|
-
runCmd: toolInfo.runCmd,
|
|
30
|
-
kind: toolInfo.kind,
|
|
31
|
-
};
|
|
20
|
+
const renderer = getRenderer("tool-script");
|
|
21
|
+
const ctx = showInputToRenderContext(input, "tool-script");
|
|
22
|
+
return renderer.buildShowResponse(ctx);
|
|
32
23
|
},
|
|
33
24
|
enrichSearchHit(hit, stashDir) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
hit.runCmd = toolInfo.runCmd;
|
|
37
|
-
hit.kind = toolInfo.kind;
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
if (!hasErrnoCode(error, "ENOENT"))
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
25
|
+
const renderer = getRenderer("tool-script");
|
|
26
|
+
renderer.enrichSearchHit(hit, stashDir);
|
|
43
27
|
},
|
|
44
28
|
defaultUsageGuide: [
|
|
45
29
|
"Use the hit's runCmd for execution so runtime and working directory stay correct.",
|