akm-cli 0.0.16 → 0.0.17
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 +58 -107
- package/dist/asset-spec.js +9 -9
- package/dist/cli.js +140 -118
- package/dist/common.js +0 -7
- package/dist/config-cli.js +38 -0
- package/dist/config.js +40 -26
- package/dist/file-context.js +3 -28
- package/dist/indexer.js +0 -30
- package/dist/llm.js +1 -1
- package/dist/matchers.js +4 -15
- package/dist/metadata.js +3 -3
- package/dist/registry-install.js +5 -5
- package/dist/registry-search.js +140 -30
- package/dist/renderers.js +1 -1
- package/dist/stash-add.js +2 -2
- package/dist/stash-ref.js +7 -9
- package/dist/stash-registry.js +6 -6
- package/dist/stash-resolve.js +7 -44
- package/dist/stash-search.js +8 -12
- package/dist/stash-show.js +1 -2
- package/dist/stash-source.js +6 -7
- package/dist/walker.js +1 -1
- package/package.json +1 -1
package/dist/stash-resolve.js
CHANGED
|
@@ -1,47 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { isRelevantAssetFile, resolveAssetPathFromName, TYPE_DIRS } from "./asset-spec";
|
|
4
|
-
import { hasErrnoCode, isWithin
|
|
4
|
+
import { hasErrnoCode, isWithin } from "./common";
|
|
5
5
|
import { NotFoundError, UsageError } from "./errors";
|
|
6
6
|
/**
|
|
7
7
|
* Resolve an asset path from a stash directory, type, and name.
|
|
8
|
-
*
|
|
9
|
-
* When `type` is "script" or "tool" (which is a transparent alias for "script"),
|
|
10
|
-
* resolution tries both the primary type directory and the alias directory:
|
|
11
|
-
* - script → tries scripts/ then tools/
|
|
12
|
-
* - tool → tries tools/ then scripts/
|
|
13
|
-
* This ensures that `script:deploy.sh` can find files in either `scripts/` or `tools/`.
|
|
14
8
|
*/
|
|
15
9
|
export function resolveAssetPath(stashDir, type, name) {
|
|
16
|
-
// For script/tool, try the primary directory first, then the alias directory.
|
|
17
|
-
if (type === "script" || type === "tool") {
|
|
18
|
-
const primaryDir = TYPE_DIRS[type];
|
|
19
|
-
const aliasDir = type === "script" ? "tools" : "scripts";
|
|
20
|
-
const dirsToTry = [primaryDir, aliasDir];
|
|
21
|
-
let primaryError;
|
|
22
|
-
let lastError;
|
|
23
|
-
for (let i = 0; i < dirsToTry.length; i++) {
|
|
24
|
-
try {
|
|
25
|
-
return resolveInTypeDir(stashDir, dirsToTry[i], type, name);
|
|
26
|
-
}
|
|
27
|
-
catch (err) {
|
|
28
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
29
|
-
if (i === 0)
|
|
30
|
-
primaryError = error;
|
|
31
|
-
lastError = error;
|
|
32
|
-
// Only fall through on NotFoundError -- rethrow security/usage errors immediately
|
|
33
|
-
if (err instanceof UsageError)
|
|
34
|
-
throw err;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Prefer the primary directory's error when it's about extension validation
|
|
38
|
-
// (i.e., the file was found but had the wrong extension) over a generic
|
|
39
|
-
// "not found" from the alias directory.
|
|
40
|
-
const errorToThrow = primaryError?.message.includes("supported script extension")
|
|
41
|
-
? primaryError
|
|
42
|
-
: (lastError ?? new NotFoundError(`Stash asset not found for ref: ${normalizeAssetType(type)}:${name}`));
|
|
43
|
-
throw errorToThrow;
|
|
44
|
-
}
|
|
45
10
|
return resolveInTypeDir(stashDir, TYPE_DIRS[type], type, name);
|
|
46
11
|
}
|
|
47
12
|
/**
|
|
@@ -56,26 +21,24 @@ function resolveInTypeDir(stashDir, typeDir, type, name) {
|
|
|
56
21
|
throw new UsageError("Ref resolves outside the stash root.");
|
|
57
22
|
}
|
|
58
23
|
if (!fs.existsSync(resolvedTarget) || !fs.statSync(resolvedTarget).isFile()) {
|
|
59
|
-
throw new NotFoundError(`Stash asset not found for ref: ${
|
|
24
|
+
throw new NotFoundError(`Stash asset not found for ref: ${type}:${name}`);
|
|
60
25
|
}
|
|
61
26
|
const realTarget = fs.realpathSync(resolvedTarget);
|
|
62
27
|
if (!isWithin(realTarget, resolvedRoot)) {
|
|
63
28
|
throw new UsageError("Ref resolves outside the stash root.");
|
|
64
29
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!isRelevantAssetFile(relevanceType, path.basename(resolvedTarget))) {
|
|
68
|
-
if (type === "tool" || type === "script") {
|
|
30
|
+
if (!isRelevantAssetFile(type, path.basename(resolvedTarget))) {
|
|
31
|
+
if (type === "script") {
|
|
69
32
|
throw new NotFoundError("Script ref must resolve to a file with a supported script extension. Refer to the akm documentation for the complete list of supported script extensions.");
|
|
70
33
|
}
|
|
71
|
-
throw new NotFoundError(`Stash asset not found for ref: ${
|
|
34
|
+
throw new NotFoundError(`Stash asset not found for ref: ${type}:${name}`);
|
|
72
35
|
}
|
|
73
36
|
return realTarget;
|
|
74
37
|
}
|
|
75
38
|
function resolveAndValidateTypeRoot(root, type, name) {
|
|
76
39
|
const rootStat = readTypeRootStat(root, type, name);
|
|
77
40
|
if (!rootStat.isDirectory()) {
|
|
78
|
-
throw new NotFoundError(`Stash type root is not a directory for ref: ${
|
|
41
|
+
throw new NotFoundError(`Stash type root is not a directory for ref: ${type}:${name}`);
|
|
79
42
|
}
|
|
80
43
|
return fs.realpathSync(root);
|
|
81
44
|
}
|
|
@@ -85,7 +48,7 @@ function readTypeRootStat(root, type, name) {
|
|
|
85
48
|
}
|
|
86
49
|
catch (error) {
|
|
87
50
|
if (hasErrnoCode(error, "ENOENT")) {
|
|
88
|
-
throw new NotFoundError(`Stash type root not found for ref: ${
|
|
51
|
+
throw new NotFoundError(`Stash type root not found for ref: ${type}:${name}`);
|
|
89
52
|
}
|
|
90
53
|
throw error;
|
|
91
54
|
}
|
package/dist/stash-search.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { deriveCanonicalAssetName, TYPE_DIRS } from "./asset-spec";
|
|
4
|
-
import { normalizeAssetType } from "./common";
|
|
5
4
|
import { loadConfig } from "./config";
|
|
6
5
|
import { closeDatabase, getAllEntries, getEntryById, getEntryCount, getMeta, openDatabase, searchFts, searchVec, } from "./db";
|
|
7
6
|
import { UsageError } from "./errors";
|
|
@@ -45,7 +44,7 @@ export async function agentikitSearch(input) {
|
|
|
45
44
|
sources,
|
|
46
45
|
config,
|
|
47
46
|
});
|
|
48
|
-
const registryResult = source === "local" ? undefined : await searchRegistry(query, { limit,
|
|
47
|
+
const registryResult = source === "local" ? undefined : await searchRegistry(query, { limit, registries: config.registries });
|
|
49
48
|
if (source === "local") {
|
|
50
49
|
return {
|
|
51
50
|
schemaVersion: 1,
|
|
@@ -67,6 +66,7 @@ export async function agentikitSearch(input) {
|
|
|
67
66
|
action: `akm add ${installRef} -> then search again`,
|
|
68
67
|
score: hit.score,
|
|
69
68
|
curated: hit.curated,
|
|
69
|
+
registryName: hit.registryName,
|
|
70
70
|
};
|
|
71
71
|
});
|
|
72
72
|
if (source === "registry") {
|
|
@@ -315,7 +315,7 @@ function buildDbHit(input) {
|
|
|
315
315
|
const source = findSourceForPath(input.path, input.sources);
|
|
316
316
|
const editable = isEditable(input.path, input.config);
|
|
317
317
|
const hit = {
|
|
318
|
-
type:
|
|
318
|
+
type: input.entry.type,
|
|
319
319
|
name: input.entry.name,
|
|
320
320
|
path: input.path,
|
|
321
321
|
ref: makeAssetRef(input.entry.type, refName, source?.registryId),
|
|
@@ -325,7 +325,7 @@ function buildDbHit(input) {
|
|
|
325
325
|
description: input.entry.description,
|
|
326
326
|
tags: input.entry.tags,
|
|
327
327
|
size: deriveSize(input.entry.fileSize),
|
|
328
|
-
action: buildLocalAction(
|
|
328
|
+
action: buildLocalAction(input.entry.type, makeAssetRef(input.entry.type, refName, source?.registryId)),
|
|
329
329
|
score,
|
|
330
330
|
whyMatched,
|
|
331
331
|
};
|
|
@@ -364,7 +364,7 @@ function assetToSearchHit(asset, stashDir, sources, config) {
|
|
|
364
364
|
const fileSize = readFileSize(asset.path);
|
|
365
365
|
const size = deriveSize(fileSize);
|
|
366
366
|
const hit = {
|
|
367
|
-
type:
|
|
367
|
+
type: asset.entry.type,
|
|
368
368
|
name: asset.entry.name,
|
|
369
369
|
path: asset.path,
|
|
370
370
|
ref,
|
|
@@ -376,7 +376,7 @@ function assetToSearchHit(asset, stashDir, sources, config) {
|
|
|
376
376
|
description: asset.entry.description,
|
|
377
377
|
tags: asset.entry.tags,
|
|
378
378
|
...(size ? { size } : {}),
|
|
379
|
-
action: buildLocalAction(
|
|
379
|
+
action: buildLocalAction(asset.entry.type, ref),
|
|
380
380
|
};
|
|
381
381
|
const renderer = rendererForType(asset.entry.type);
|
|
382
382
|
if (renderer?.enrichSearchHit) {
|
|
@@ -404,7 +404,6 @@ function mergeSearchHits(localHits, registryHits, limit) {
|
|
|
404
404
|
}
|
|
405
405
|
/** Map asset types to their primary renderer names. */
|
|
406
406
|
const TYPE_TO_RENDERER = {
|
|
407
|
-
tool: "script-source",
|
|
408
407
|
script: "script-source",
|
|
409
408
|
skill: "skill-md",
|
|
410
409
|
command: "command-md",
|
|
@@ -426,8 +425,6 @@ function buildLocalAction(type, ref) {
|
|
|
426
425
|
return `akm show ${ref} -> dispatch with full prompt`;
|
|
427
426
|
case "knowledge":
|
|
428
427
|
return `akm show ${ref} -> read reference material`;
|
|
429
|
-
case "tool":
|
|
430
|
-
return `akm show ${ref} -> execute the run command`;
|
|
431
428
|
}
|
|
432
429
|
}
|
|
433
430
|
function deriveSize(bytes) {
|
|
@@ -449,7 +446,7 @@ function readFileSize(filePath) {
|
|
|
449
446
|
}
|
|
450
447
|
function indexAssets(stashDir, type) {
|
|
451
448
|
const assets = [];
|
|
452
|
-
const filterType = type === "any" ? undefined :
|
|
449
|
+
const filterType = type === "any" ? undefined : type;
|
|
453
450
|
const fileContexts = walkStashFlat(stashDir);
|
|
454
451
|
const dirGroups = new Map();
|
|
455
452
|
for (const ctx of fileContexts) {
|
|
@@ -478,8 +475,7 @@ function indexAssets(stashDir, type) {
|
|
|
478
475
|
stash = generated;
|
|
479
476
|
}
|
|
480
477
|
for (const entry of stash.entries) {
|
|
481
|
-
|
|
482
|
-
if (filterType && normalizedType !== filterType)
|
|
478
|
+
if (filterType && entry.type !== filterType)
|
|
483
479
|
continue;
|
|
484
480
|
const entryPath = entry.filename ? path.join(dirPath, entry.filename) : files[0] || dirPath;
|
|
485
481
|
assets.push({ entry, path: entryPath });
|
package/dist/stash-show.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { normalizeAssetType } from "./common";
|
|
2
1
|
import { loadConfig } from "./config";
|
|
3
2
|
import { NotFoundError, UsageError } from "./errors";
|
|
4
3
|
import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "./file-context";
|
|
@@ -8,7 +7,7 @@ import { resolveAssetPath } from "./stash-resolve";
|
|
|
8
7
|
import { buildEditHint, findSourceForPath, isEditable, resolveStashSources } from "./stash-source";
|
|
9
8
|
export async function agentikitShow(input) {
|
|
10
9
|
const parsed = parseAssetRef(input.ref);
|
|
11
|
-
const displayType =
|
|
10
|
+
const displayType = parsed.type;
|
|
12
11
|
const config = loadConfig();
|
|
13
12
|
const allSources = resolveStashSources();
|
|
14
13
|
const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
|
package/dist/stash-source.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveStashDir } from "./common";
|
|
4
4
|
import { loadConfig } from "./config";
|
|
5
5
|
import { warn } from "./warn";
|
|
6
6
|
// ── Resolution ──────────────────────────────────────────────────────────────
|
|
@@ -11,7 +11,7 @@ import { warn } from "./warn";
|
|
|
11
11
|
* 3. Installed kit paths (cache-managed, from registry)
|
|
12
12
|
*
|
|
13
13
|
* The first entry is always the primary stash. Additional entries come
|
|
14
|
-
* from `searchPaths` config and `
|
|
14
|
+
* from `searchPaths` config and `installed` kit entries.
|
|
15
15
|
*/
|
|
16
16
|
export function resolveStashSources(overrideStashDir, existingConfig) {
|
|
17
17
|
const stashDir = overrideStashDir ?? resolveStashDir();
|
|
@@ -25,7 +25,7 @@ export function resolveStashSources(overrideStashDir, existingConfig) {
|
|
|
25
25
|
sources.push({ path: dir });
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
for (const entry of config.
|
|
28
|
+
for (const entry of config.installed ?? []) {
|
|
29
29
|
if (isSuspiciousStashRoot(entry.stashRoot)) {
|
|
30
30
|
warn(`Warning: stash root "${entry.stashRoot}" appears to be a system directory. This may be unintentional.`);
|
|
31
31
|
}
|
|
@@ -67,7 +67,7 @@ export function getPrimarySource(sources) {
|
|
|
67
67
|
* Determine whether a file is safe to edit in place.
|
|
68
68
|
*
|
|
69
69
|
* The only files that are NOT editable are those inside a cache directory
|
|
70
|
-
* managed by the package manager (`
|
|
70
|
+
* managed by the package manager (`installed[].cacheDir`). These
|
|
71
71
|
* will be overwritten by `akm update` without warning.
|
|
72
72
|
*
|
|
73
73
|
* Everything else — working stash, search paths, local project dirs — is
|
|
@@ -76,7 +76,7 @@ export function getPrimarySource(sources) {
|
|
|
76
76
|
export function isEditable(filePath, config) {
|
|
77
77
|
const cfg = config ?? loadConfig();
|
|
78
78
|
const resolved = path.resolve(filePath);
|
|
79
|
-
const cacheManaged = cfg.
|
|
79
|
+
const cacheManaged = cfg.installed ?? [];
|
|
80
80
|
const isWin = process.platform === "win32";
|
|
81
81
|
for (const entry of cacheManaged) {
|
|
82
82
|
// Local sources reference original paths — always editable
|
|
@@ -101,8 +101,7 @@ export function isEditable(filePath, config) {
|
|
|
101
101
|
* unconditionally returns the hint string.
|
|
102
102
|
*/
|
|
103
103
|
export function buildEditHint(_filePath, assetType, assetName, origin) {
|
|
104
|
-
const
|
|
105
|
-
const ref = origin ? `${origin}//${normalizedType}:${assetName}` : `${normalizedType}:${assetName}`;
|
|
104
|
+
const ref = origin ? `${origin}//${assetType}:${assetName}` : `${assetType}:${assetName}`;
|
|
106
105
|
return `This asset is managed by akm and may be overwritten on update. To edit, run: akm clone ${ref}`;
|
|
107
106
|
}
|
|
108
107
|
// ── Validation ──────────────────────────────────────────────────────────────
|
package/dist/walker.js
CHANGED
|
@@ -14,7 +14,7 @@ import { buildFileContext } from "./file-context";
|
|
|
14
14
|
* Walk a type root directory and return files grouped by their parent directory.
|
|
15
15
|
*
|
|
16
16
|
* Only files relevant to the given `assetType` are included (e.g. `.md` for
|
|
17
|
-
* commands, script extensions for
|
|
17
|
+
* commands, script extensions for scripts, `SKILL.md` for skills).
|
|
18
18
|
*/
|
|
19
19
|
export function walkStash(typeRoot, assetType) {
|
|
20
20
|
if (!fs.existsSync(typeRoot))
|