akm-cli 0.0.18 → 0.0.19
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/dist/common.js +6 -0
- package/dist/db.js +9 -1
- package/dist/indexer.js +15 -1
- package/dist/providers/skills-sh.js +1 -0
- package/dist/providers/static-index.js +14 -7
- package/dist/registry-resolve.js +37 -0
- package/package.json +1 -1
package/dist/common.js
CHANGED
|
@@ -147,6 +147,12 @@ export async function fetchWithTimeout(url, opts, timeoutMs = 30_000) {
|
|
|
147
147
|
try {
|
|
148
148
|
return await fetch(url, { ...opts, signal: controller.signal });
|
|
149
149
|
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
152
|
+
throw new Error(`Request timed out after ${timeoutMs}ms: ${url}`);
|
|
153
|
+
}
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
150
156
|
finally {
|
|
151
157
|
clearTimeout(timer);
|
|
152
158
|
}
|
package/dist/db.js
CHANGED
|
@@ -180,6 +180,15 @@ export function upsertEntry(db, entryKey, dirPath, filePath, stashDir, entry, se
|
|
|
180
180
|
}
|
|
181
181
|
export function deleteEntriesByDir(db, dirPath) {
|
|
182
182
|
const ids = db.prepare("SELECT id FROM entries WHERE dir_path = ?").all(dirPath);
|
|
183
|
+
deleteRelatedRows(db, ids);
|
|
184
|
+
db.prepare("DELETE FROM entries WHERE dir_path = ?").run(dirPath);
|
|
185
|
+
}
|
|
186
|
+
export function deleteEntriesByStashDir(db, stashDir) {
|
|
187
|
+
const ids = db.prepare("SELECT id FROM entries WHERE stash_dir = ?").all(stashDir);
|
|
188
|
+
deleteRelatedRows(db, ids);
|
|
189
|
+
db.prepare("DELETE FROM entries WHERE stash_dir = ?").run(stashDir);
|
|
190
|
+
}
|
|
191
|
+
function deleteRelatedRows(db, ids) {
|
|
183
192
|
for (const { id } of ids) {
|
|
184
193
|
try {
|
|
185
194
|
db.prepare("DELETE FROM embeddings WHERE id = ?").run(id);
|
|
@@ -196,7 +205,6 @@ export function deleteEntriesByDir(db, dirPath) {
|
|
|
196
205
|
}
|
|
197
206
|
}
|
|
198
207
|
}
|
|
199
|
-
db.prepare("DELETE FROM entries WHERE dir_path = ?").run(dirPath);
|
|
200
208
|
}
|
|
201
209
|
export function rebuildFts(db) {
|
|
202
210
|
db.exec("DELETE FROM entries_fts");
|
package/dist/indexer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { resolveStashDir } from "./common";
|
|
4
|
-
import { closeDatabase, DB_VERSION, deleteEntriesByDir, getEntriesByDir, getEntryCount, getMeta, isVecAvailable, openDatabase, rebuildFts, setMeta, upsertEmbedding, upsertEntry, warnIfVecMissing, } from "./db";
|
|
4
|
+
import { closeDatabase, DB_VERSION, deleteEntriesByDir, deleteEntriesByStashDir, getEntriesByDir, getEntryCount, getMeta, isVecAvailable, openDatabase, rebuildFts, setMeta, upsertEmbedding, upsertEntry, warnIfVecMissing, } from "./db";
|
|
5
5
|
import { generateMetadataFlat, loadStashFile } from "./metadata";
|
|
6
6
|
import { getDbPath } from "./paths";
|
|
7
7
|
import { walkStashFlat } from "./walker";
|
|
@@ -45,6 +45,20 @@ export async function agentikitIndex(options) {
|
|
|
45
45
|
db.exec("DELETE FROM entries_fts");
|
|
46
46
|
db.exec("DELETE FROM entries");
|
|
47
47
|
}
|
|
48
|
+
else {
|
|
49
|
+
// Incremental: purge entries from stash dirs that have been removed
|
|
50
|
+
// (e.g. after `akm remove`) so orphaned entries don't linger.
|
|
51
|
+
const prevStashDirsJson = getMeta(db, "stashDirs");
|
|
52
|
+
if (prevStashDirsJson) {
|
|
53
|
+
const prevStashDirs = JSON.parse(prevStashDirsJson);
|
|
54
|
+
const currentSet = new Set(allStashDirs);
|
|
55
|
+
for (const dir of prevStashDirs) {
|
|
56
|
+
if (!currentSet.has(dir)) {
|
|
57
|
+
deleteEntriesByStashDir(db, dir);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
48
62
|
const tWalkStart = Date.now();
|
|
49
63
|
// Walk stash dirs and index entries
|
|
50
64
|
const { scannedDirs, skippedDirs, generatedCount, dirsNeedingLlm } = indexEntries(db, allStashDirs, stashDir, isIncremental, builtAtMs);
|
|
@@ -219,6 +219,7 @@ function toSearchHit(kit, score, registryName) {
|
|
|
219
219
|
title: kit.name,
|
|
220
220
|
description: kit.description,
|
|
221
221
|
ref: kit.ref,
|
|
222
|
+
installRef: buildInstallRef(kit.source, kit.ref),
|
|
222
223
|
homepage: kit.homepage,
|
|
223
224
|
score: Math.round(score * 1000) / 1000,
|
|
224
225
|
metadata,
|
|
@@ -260,13 +261,7 @@ function scoreAssets(kits, query, limit) {
|
|
|
260
261
|
for (const { kit, registryName } of kits) {
|
|
261
262
|
if (!kit.assets || kit.assets.length === 0)
|
|
262
263
|
continue;
|
|
263
|
-
const installRef = kit.source
|
|
264
|
-
? `npm:${kit.ref}`
|
|
265
|
-
: kit.source === "git"
|
|
266
|
-
? `git+${kit.ref}`
|
|
267
|
-
: kit.source === "local"
|
|
268
|
-
? kit.ref
|
|
269
|
-
: `github:${kit.ref}`;
|
|
264
|
+
const installRef = buildInstallRef(kit.source, kit.ref);
|
|
270
265
|
for (const asset of kit.assets) {
|
|
271
266
|
const score = scoreAsset(asset, tokens);
|
|
272
267
|
if (score > 0) {
|
|
@@ -335,6 +330,18 @@ function asStringArray(value) {
|
|
|
335
330
|
const filtered = value.filter((v) => typeof v === "string");
|
|
336
331
|
return filtered.length > 0 ? filtered : undefined;
|
|
337
332
|
}
|
|
333
|
+
function buildInstallRef(source, ref) {
|
|
334
|
+
switch (source) {
|
|
335
|
+
case "npm":
|
|
336
|
+
return `npm:${ref}`;
|
|
337
|
+
case "git":
|
|
338
|
+
return `git+${ref}`;
|
|
339
|
+
case "local":
|
|
340
|
+
return ref;
|
|
341
|
+
default:
|
|
342
|
+
return `github:${ref}`;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
338
345
|
function toErrorMessage(error) {
|
|
339
346
|
return error instanceof Error ? error.message : String(error);
|
|
340
347
|
}
|
package/dist/registry-resolve.js
CHANGED
|
@@ -9,6 +9,12 @@ export function parseRegistryRef(rawRef) {
|
|
|
9
9
|
const ref = rawRef.trim();
|
|
10
10
|
if (!ref)
|
|
11
11
|
throw new Error("Registry ref is required.");
|
|
12
|
+
// Detect registry search result IDs (e.g. "skills-sh:org/skills/name")
|
|
13
|
+
// that are not installable refs. Known installable prefixes are handled below.
|
|
14
|
+
const registryIdHint = detectRegistrySearchId(ref);
|
|
15
|
+
if (registryIdHint) {
|
|
16
|
+
throw new Error(registryIdHint);
|
|
17
|
+
}
|
|
12
18
|
if (ref.startsWith("npm:")) {
|
|
13
19
|
return parseNpmRef(ref.slice(4), ref);
|
|
14
20
|
}
|
|
@@ -33,6 +39,37 @@ export function parseRegistryRef(rawRef) {
|
|
|
33
39
|
}
|
|
34
40
|
return parseGithubShorthand(ref, ref);
|
|
35
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Known prefixes that `parseRegistryRef` handles as installable sources.
|
|
44
|
+
* Anything with a colon that doesn't start with one of these is likely a
|
|
45
|
+
* registry search result ID (e.g. `skills-sh:org/skills/name`).
|
|
46
|
+
*/
|
|
47
|
+
const KNOWN_PREFIXES = ["npm:", "github:", "git+", "file:", "http://", "https://"];
|
|
48
|
+
function detectRegistrySearchId(ref) {
|
|
49
|
+
const colonIdx = ref.indexOf(":");
|
|
50
|
+
if (colonIdx < 1)
|
|
51
|
+
return undefined;
|
|
52
|
+
// Skip known installable prefixes
|
|
53
|
+
for (const prefix of KNOWN_PREFIXES) {
|
|
54
|
+
if (ref.startsWith(prefix))
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const prefix = ref.slice(0, colonIdx);
|
|
58
|
+
// Registry IDs use lowercase-with-hyphens prefixes (e.g. skills-sh, static-index)
|
|
59
|
+
if (!/^[a-z][a-z0-9-]*$/.test(prefix))
|
|
60
|
+
return undefined;
|
|
61
|
+
const rest = ref.slice(colonIdx + 1);
|
|
62
|
+
return [
|
|
63
|
+
`"${ref}" looks like a registry search result ID, not an installable ref.`,
|
|
64
|
+
`The "${prefix}:" prefix is a registry identifier and cannot be passed to \`akm add\`.`,
|
|
65
|
+
"",
|
|
66
|
+
"Use the installRef or ref field from the search result instead. For example:",
|
|
67
|
+
` akm registry search "${rest}" --format json`,
|
|
68
|
+
"Then install using the installRef value from the result:",
|
|
69
|
+
" akm add github:owner/repo",
|
|
70
|
+
" akm add npm:package-name",
|
|
71
|
+
].join("\n");
|
|
72
|
+
}
|
|
36
73
|
export async function resolveRegistryArtifact(parsed) {
|
|
37
74
|
if (parsed.source === "npm") {
|
|
38
75
|
return resolveNpmArtifact(parsed);
|