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/self-update.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { fetchWithRetry, IS_WINDOWS } from "./common";
|
|
5
5
|
import { githubHeaders } from "./github";
|
|
6
6
|
const REPO = "itlackey/agentikit";
|
|
7
7
|
export function detectInstallMethod() {
|
|
@@ -43,7 +43,7 @@ export async function checkForUpdate(currentVersion) {
|
|
|
43
43
|
return {
|
|
44
44
|
currentVersion,
|
|
45
45
|
latestVersion,
|
|
46
|
-
updateAvailable: latestVersion !== "" && latestVersion
|
|
46
|
+
updateAvailable: latestVersion !== "" && Bun.semver.order(currentVersion, latestVersion) < 0,
|
|
47
47
|
installMethod,
|
|
48
48
|
};
|
|
49
49
|
}
|
|
@@ -101,9 +101,7 @@ export async function performUpgrade(check, opts) {
|
|
|
101
101
|
if (expectedHash) {
|
|
102
102
|
const actualHash = createHash("sha256").update(binaryData).digest("hex");
|
|
103
103
|
if (actualHash !== expectedHash) {
|
|
104
|
-
throw new Error(`Checksum mismatch for ${binaryName}.\n` +
|
|
105
|
-
`Expected: ${expectedHash}\n` +
|
|
106
|
-
`Got: ${actualHash}`);
|
|
104
|
+
throw new Error(`Checksum mismatch for ${binaryName}.\n` + `Expected: ${expectedHash}\n` + `Got: ${actualHash}`);
|
|
107
105
|
}
|
|
108
106
|
checksumVerified = true;
|
|
109
107
|
}
|
|
@@ -162,7 +160,9 @@ export async function performUpgrade(check, opts) {
|
|
|
162
160
|
try {
|
|
163
161
|
fs.unlinkSync(tmpPath);
|
|
164
162
|
}
|
|
165
|
-
catch {
|
|
163
|
+
catch {
|
|
164
|
+
/* ignore */
|
|
165
|
+
}
|
|
166
166
|
const code = err.code;
|
|
167
167
|
if (code === "EACCES" || code === "EPERM") {
|
|
168
168
|
throw new Error(`Permission denied writing to ${execDir}.\n` +
|
|
@@ -181,20 +181,26 @@ export async function performUpgrade(check, opts) {
|
|
|
181
181
|
try {
|
|
182
182
|
fs.unlinkSync(tmpPath);
|
|
183
183
|
}
|
|
184
|
-
catch {
|
|
184
|
+
catch {
|
|
185
|
+
/* ignore */
|
|
186
|
+
}
|
|
185
187
|
try {
|
|
186
188
|
if (fs.existsSync(bakPath) && !fs.existsSync(execPath)) {
|
|
187
189
|
fs.renameSync(bakPath, execPath);
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
|
-
catch {
|
|
192
|
+
catch {
|
|
193
|
+
/* ignore */
|
|
194
|
+
}
|
|
191
195
|
throw err;
|
|
192
196
|
}
|
|
193
197
|
// Cleanup backup
|
|
194
198
|
try {
|
|
195
199
|
fs.unlinkSync(bakPath);
|
|
196
200
|
}
|
|
197
|
-
catch {
|
|
201
|
+
catch {
|
|
202
|
+
/* ignore */
|
|
203
|
+
}
|
|
198
204
|
}
|
|
199
205
|
return {
|
|
200
206
|
currentVersion,
|
package/dist/stash-add.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { agentikitIndex } from "./indexer";
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import { resolveStashDir } from "./common";
|
|
4
3
|
import { loadConfig } from "./config";
|
|
4
|
+
import { UsageError } from "./errors";
|
|
5
|
+
import { agentikitIndex } from "./indexer";
|
|
5
6
|
import { upsertLockEntry } from "./lockfile";
|
|
6
|
-
import {
|
|
7
|
+
import { installRegistryRef, upsertInstalledRegistryEntry } from "./registry-install";
|
|
7
8
|
export async function agentikitAdd(input) {
|
|
8
9
|
const ref = input.ref.trim();
|
|
9
10
|
if (!ref)
|
|
10
|
-
throw new
|
|
11
|
+
throw new UsageError("Install ref or local directory is required.");
|
|
11
12
|
const stashDir = resolveStashDir();
|
|
12
13
|
const installed = await installRegistryRef(ref);
|
|
13
14
|
const replaced = loadConfig().registry?.installed.find((entry) => entry.id === installed.id);
|
package/dist/stash-clone.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { TYPE_DIRS } from "./asset-spec";
|
|
4
|
-
import {
|
|
5
|
-
import { resolveSourcesForOrigin, isRemoteOrigin } from "./origin-resolve";
|
|
6
|
-
import { resolveAssetPath } from "./stash-resolve";
|
|
7
|
-
import { resolveStashSources, findSourceForPath, getPrimarySource } from "./stash-source";
|
|
4
|
+
import { isRemoteOrigin, resolveSourcesForOrigin } from "./origin-resolve";
|
|
8
5
|
import { installRegistryRef } from "./registry-install";
|
|
6
|
+
import { makeAssetRef, parseAssetRef } from "./stash-ref";
|
|
7
|
+
import { resolveAssetPath } from "./stash-resolve";
|
|
8
|
+
import { findSourceForPath, getPrimarySource, resolveStashSources } from "./stash-source";
|
|
9
9
|
export async function agentikitClone(options) {
|
|
10
10
|
const parsed = parseAssetRef(options.sourceRef);
|
|
11
11
|
// When --dest is provided, the working stash is optional
|
package/dist/stash-ref.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { isAssetType } from "./common";
|
|
3
|
+
import { UsageError } from "./errors";
|
|
3
4
|
// ── Construction ────────────────────────────────────────────────────────────
|
|
4
5
|
/**
|
|
5
6
|
* Build a ref string from components.
|
|
@@ -29,7 +30,7 @@ export function makeAssetRef(type, name, origin) {
|
|
|
29
30
|
export function parseAssetRef(ref) {
|
|
30
31
|
const trimmed = ref.trim();
|
|
31
32
|
if (!trimmed)
|
|
32
|
-
throw new
|
|
33
|
+
throw new UsageError("Empty ref.");
|
|
33
34
|
let origin;
|
|
34
35
|
let body = trimmed;
|
|
35
36
|
const boundary = trimmed.indexOf("//");
|
|
@@ -37,16 +38,16 @@ export function parseAssetRef(ref) {
|
|
|
37
38
|
origin = trimmed.slice(0, boundary);
|
|
38
39
|
body = trimmed.slice(boundary + 2);
|
|
39
40
|
if (!origin)
|
|
40
|
-
throw new
|
|
41
|
+
throw new UsageError("Empty origin in ref.");
|
|
41
42
|
}
|
|
42
43
|
const colon = body.indexOf(":");
|
|
43
44
|
if (colon <= 0) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new UsageError(`Invalid ref "${trimmed}". Expected [origin//]type:name`);
|
|
45
46
|
}
|
|
46
47
|
const rawType = body.slice(0, colon);
|
|
47
48
|
const rawName = body.slice(colon + 1);
|
|
48
49
|
if (!isAssetType(rawType)) {
|
|
49
|
-
throw new
|
|
50
|
+
throw new UsageError(`Invalid asset type: "${rawType}".`);
|
|
50
51
|
}
|
|
51
52
|
validateName(rawName);
|
|
52
53
|
const name = normalizeName(rawName);
|
|
@@ -55,16 +56,16 @@ export function parseAssetRef(ref) {
|
|
|
55
56
|
// ── Validation ──────────────────────────────────────────────────────────────
|
|
56
57
|
function validateName(name) {
|
|
57
58
|
if (!name)
|
|
58
|
-
throw new
|
|
59
|
+
throw new UsageError("Empty asset name.");
|
|
59
60
|
if (name.includes("\0"))
|
|
60
|
-
throw new
|
|
61
|
+
throw new UsageError("Null byte in asset name.");
|
|
61
62
|
if (/^[A-Za-z]:/.test(name))
|
|
62
|
-
throw new
|
|
63
|
+
throw new UsageError("Windows drive path in asset name.");
|
|
63
64
|
const normalized = path.posix.normalize(name.replace(/\\/g, "/"));
|
|
64
65
|
if (path.posix.isAbsolute(normalized))
|
|
65
|
-
throw new
|
|
66
|
+
throw new UsageError("Absolute path in asset name.");
|
|
66
67
|
if (normalized === ".." || normalized.startsWith("../")) {
|
|
67
|
-
throw new
|
|
68
|
+
throw new UsageError("Path traversal in asset name.");
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
function normalizeName(name) {
|
package/dist/stash-registry.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { resolveStashDir } from "./common";
|
|
3
3
|
import { loadConfig } from "./config";
|
|
4
|
+
import { NotFoundError, UsageError } from "./errors";
|
|
4
5
|
import { agentikitIndex } from "./indexer";
|
|
5
6
|
import { removeLockEntry, upsertLockEntry } from "./lockfile";
|
|
6
|
-
import { installRegistryRef, removeInstalledRegistryEntry, upsertInstalledRegistryEntry
|
|
7
|
+
import { installRegistryRef, removeInstalledRegistryEntry, upsertInstalledRegistryEntry } from "./registry-install";
|
|
7
8
|
import { parseRegistryRef } from "./registry-resolve";
|
|
8
9
|
export async function agentikitList(input) {
|
|
9
10
|
const stashDir = input?.stashDir ?? resolveStashDir();
|
|
@@ -24,7 +25,7 @@ export async function agentikitList(input) {
|
|
|
24
25
|
export async function agentikitRemove(input) {
|
|
25
26
|
const target = input.target.trim();
|
|
26
27
|
if (!target)
|
|
27
|
-
throw new
|
|
28
|
+
throw new UsageError("Target is required.");
|
|
28
29
|
const stashDir = input.stashDir ?? resolveStashDir();
|
|
29
30
|
const config = loadConfig();
|
|
30
31
|
const installed = config.registry?.installed ?? [];
|
|
@@ -120,12 +121,12 @@ export async function agentikitUpdate(input) {
|
|
|
120
121
|
}
|
|
121
122
|
function selectTargets(installed, target, all) {
|
|
122
123
|
if (all && target) {
|
|
123
|
-
throw new
|
|
124
|
+
throw new UsageError("Specify either <target> or --all, not both.");
|
|
124
125
|
}
|
|
125
126
|
if (all)
|
|
126
127
|
return installed;
|
|
127
128
|
if (!target) {
|
|
128
|
-
throw new
|
|
129
|
+
throw new UsageError("Either <target> or --all is required.");
|
|
129
130
|
}
|
|
130
131
|
return [resolveInstalledTarget(installed, target)];
|
|
131
132
|
}
|
|
@@ -148,7 +149,7 @@ function resolveInstalledTarget(installed, target) {
|
|
|
148
149
|
if (byParsedId)
|
|
149
150
|
return byParsedId;
|
|
150
151
|
}
|
|
151
|
-
throw new
|
|
152
|
+
throw new NotFoundError(`No installed registry entry matched target: ${target}`);
|
|
152
153
|
}
|
|
153
154
|
function toInstalledEntry(status) {
|
|
154
155
|
return {
|
package/dist/stash-resolve.js
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { isRelevantAssetFile, resolveAssetPathFromName, TYPE_DIRS } from "./asset-spec";
|
|
3
4
|
import { hasErrnoCode, isWithin } from "./common";
|
|
4
|
-
import {
|
|
5
|
+
import { NotFoundError, UsageError } from "./errors";
|
|
5
6
|
export function resolveAssetPath(stashDir, type, name) {
|
|
6
7
|
const root = path.join(stashDir, TYPE_DIRS[type]);
|
|
7
8
|
const target = resolveAssetPathFromName(type, root, name);
|
|
8
9
|
const resolvedRoot = resolveAndValidateTypeRoot(root, type, name);
|
|
9
10
|
const resolvedTarget = path.resolve(target);
|
|
10
11
|
if (!isWithin(resolvedTarget, resolvedRoot)) {
|
|
11
|
-
throw new
|
|
12
|
+
throw new UsageError("Ref resolves outside the stash root.");
|
|
12
13
|
}
|
|
13
14
|
if (!fs.existsSync(resolvedTarget) || !fs.statSync(resolvedTarget).isFile()) {
|
|
14
|
-
throw new
|
|
15
|
+
throw new NotFoundError(`Stash asset not found for ref: ${type}:${name}`);
|
|
15
16
|
}
|
|
16
17
|
const realTarget = fs.realpathSync(resolvedTarget);
|
|
17
18
|
if (!isWithin(realTarget, resolvedRoot)) {
|
|
18
|
-
throw new
|
|
19
|
+
throw new UsageError("Ref resolves outside the stash root.");
|
|
19
20
|
}
|
|
20
21
|
if (!isRelevantAssetFile(type, path.basename(resolvedTarget))) {
|
|
21
22
|
if (type === "tool") {
|
|
22
|
-
throw new
|
|
23
|
+
throw new NotFoundError("Tool ref must resolve to a .sh, .ts, .js, .ps1, .cmd, or .bat file.");
|
|
23
24
|
}
|
|
24
25
|
if (type === "script") {
|
|
25
|
-
throw new
|
|
26
|
+
throw new NotFoundError("Script ref must resolve to a file with a supported script extension. Refer to the Agentikit documentation for the complete list of supported script extensions.");
|
|
26
27
|
}
|
|
27
|
-
throw new
|
|
28
|
+
throw new NotFoundError(`Stash asset not found for ref: ${type}:${name}`);
|
|
28
29
|
}
|
|
29
30
|
return realTarget;
|
|
30
31
|
}
|
|
31
32
|
function resolveAndValidateTypeRoot(root, type, name) {
|
|
32
33
|
const rootStat = readTypeRootStat(root, type, name);
|
|
33
34
|
if (!rootStat.isDirectory()) {
|
|
34
|
-
throw new
|
|
35
|
+
throw new NotFoundError(`Stash type root is not a directory for ref: ${type}:${name}`);
|
|
35
36
|
}
|
|
36
37
|
return fs.realpathSync(root);
|
|
37
38
|
}
|
|
@@ -41,7 +42,7 @@ function readTypeRootStat(root, type, name) {
|
|
|
41
42
|
}
|
|
42
43
|
catch (error) {
|
|
43
44
|
if (hasErrnoCode(error, "ENOENT")) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new NotFoundError(`Stash type root not found for ref: ${type}:${name}`);
|
|
45
46
|
}
|
|
46
47
|
throw error;
|
|
47
48
|
}
|
package/dist/stash-search.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { ASSET_TYPES,
|
|
4
|
-
import {
|
|
5
|
-
import { makeAssetRef } from "./stash-ref";
|
|
3
|
+
import { ASSET_TYPES, deriveCanonicalAssetName, TYPE_DIRS } from "./asset-spec";
|
|
4
|
+
import { tryGetHandler } from "./asset-type-handler";
|
|
6
5
|
import { loadConfig } from "./config";
|
|
6
|
+
import { closeDatabase, getAllEntries, getEntryById, getEntryCount, getMeta, openDatabase, searchFts, searchVec, } from "./db";
|
|
7
|
+
import { UsageError } from "./errors";
|
|
8
|
+
import { getDbPath } from "./paths";
|
|
7
9
|
import { searchRegistry } from "./registry-search";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { makeAssetRef } from "./stash-ref";
|
|
11
|
+
import { buildEditHint, findSourceForPath, isEditable, resolveStashSources } from "./stash-source";
|
|
12
|
+
import { walkStash } from "./walker";
|
|
13
|
+
import { warn } from "./warn";
|
|
11
14
|
const DEFAULT_LIMIT = 20;
|
|
12
15
|
export async function agentikitSearch(input) {
|
|
13
16
|
const t0 = Date.now();
|
|
@@ -17,7 +20,8 @@ export async function agentikitSearch(input) {
|
|
|
17
20
|
const limit = normalizeLimit(input.limit);
|
|
18
21
|
const usageMode = parseSearchUsageMode(input.usage);
|
|
19
22
|
const source = parseSearchSource(input.source);
|
|
20
|
-
const
|
|
23
|
+
const config = loadConfig();
|
|
24
|
+
const sources = resolveStashSources(undefined, config);
|
|
21
25
|
if (sources.length === 0) {
|
|
22
26
|
return {
|
|
23
27
|
stashDir: "",
|
|
@@ -37,11 +41,9 @@ export async function agentikitSearch(input) {
|
|
|
37
41
|
usageMode,
|
|
38
42
|
stashDir,
|
|
39
43
|
sources,
|
|
44
|
+
config,
|
|
40
45
|
});
|
|
41
|
-
const
|
|
42
|
-
const registryResult = source === "local"
|
|
43
|
-
? undefined
|
|
44
|
-
: await searchRegistry(query, { limit, registryUrls: config.registryUrls });
|
|
46
|
+
const registryResult = source === "local" ? undefined : await searchRegistry(query, { limit, registryUrls: config.registryUrls });
|
|
45
47
|
if (source === "local") {
|
|
46
48
|
return {
|
|
47
49
|
stashDir,
|
|
@@ -83,21 +85,19 @@ export async function agentikitSearch(input) {
|
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
const mergedHits = mergeSearchHits(localResult?.hits ?? [], registryHits, limit);
|
|
88
|
+
const warnings = [...(localResult?.warnings ?? []), ...(registryResult?.warnings ?? [])];
|
|
86
89
|
return {
|
|
87
90
|
stashDir,
|
|
88
91
|
source,
|
|
89
92
|
hits: mergedHits,
|
|
90
93
|
usageGuide: localResult?.usageGuide,
|
|
91
94
|
tip: mergedHits.length === 0 ? "No matching stash assets or registry entries were found." : undefined,
|
|
92
|
-
warnings:
|
|
93
|
-
? [...(localResult?.warnings ?? []), ...(registryResult?.warnings ?? [])]
|
|
94
|
-
: undefined,
|
|
95
|
+
warnings: warnings.length ? warnings : undefined,
|
|
95
96
|
timing: { totalMs: Date.now() - t0 },
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
async function searchLocal(input) {
|
|
99
|
-
const { query, searchType, limit, usageMode, stashDir, sources } = input;
|
|
100
|
-
const config = loadConfig();
|
|
100
|
+
const { query, searchType, limit, usageMode, stashDir, sources, config } = input;
|
|
101
101
|
const allStashDirs = sources.map((s) => s.path);
|
|
102
102
|
// Try to open the database
|
|
103
103
|
const dbPath = getDbPath();
|
|
@@ -113,7 +113,9 @@ async function searchLocal(input) {
|
|
|
113
113
|
return {
|
|
114
114
|
hits,
|
|
115
115
|
usageGuide,
|
|
116
|
-
tip: hits.length === 0
|
|
116
|
+
tip: hits.length === 0
|
|
117
|
+
? "No matching stash assets were found. Try running 'akm index' to rebuild."
|
|
118
|
+
: undefined,
|
|
117
119
|
embedMs,
|
|
118
120
|
rankMs,
|
|
119
121
|
};
|
|
@@ -125,12 +127,14 @@ async function searchLocal(input) {
|
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
catch (error) {
|
|
128
|
-
|
|
130
|
+
warn("Search index unavailable, falling back to substring search:", error instanceof Error ? error.message : String(error));
|
|
129
131
|
}
|
|
130
132
|
const hits = allStashDirs
|
|
131
133
|
.flatMap((dir) => substringSearch(query, searchType, limit, dir, sources, config))
|
|
132
134
|
.slice(0, limit);
|
|
133
|
-
const usageGuide = shouldIncludeUsageGuide(usageMode)
|
|
135
|
+
const usageGuide = shouldIncludeUsageGuide(usageMode)
|
|
136
|
+
? buildUsageGuide(hits.map((hit) => hit.type), searchType)
|
|
137
|
+
: undefined;
|
|
134
138
|
return {
|
|
135
139
|
hits,
|
|
136
140
|
usageGuide,
|
|
@@ -297,7 +301,7 @@ async function tryVecScores(db, query, k, config) {
|
|
|
297
301
|
return scores;
|
|
298
302
|
}
|
|
299
303
|
catch (error) {
|
|
300
|
-
|
|
304
|
+
warn("Vector search failed, skipping:", error instanceof Error ? error.message : String(error));
|
|
301
305
|
return null;
|
|
302
306
|
}
|
|
303
307
|
}
|
|
@@ -314,8 +318,7 @@ function substringSearch(query, searchType, limit, stashDir, sources, config) {
|
|
|
314
318
|
function buildDbHit(input) {
|
|
315
319
|
const entryStashDir = findSourceForPath(input.path, input.sources)?.path ?? input.defaultStashDir;
|
|
316
320
|
const typeRoot = path.join(entryStashDir, TYPE_DIRS[input.entry.type]);
|
|
317
|
-
const openRefName = deriveCanonicalAssetName(input.entry.type, typeRoot, input.path)
|
|
318
|
-
?? input.entry.name;
|
|
321
|
+
const openRefName = deriveCanonicalAssetName(input.entry.type, typeRoot, input.path) ?? input.entry.name;
|
|
319
322
|
const qualityBoost = input.entry.generated === true ? 0 : 0.05;
|
|
320
323
|
const confidenceBoost = typeof input.entry.confidence === "number" ? Math.min(0.05, Math.max(0, input.entry.confidence) * 0.05) : 0;
|
|
321
324
|
const score = Math.round(input.score * (1 + qualityBoost + confidenceBoost) * 1000) / 1000;
|
|
@@ -398,14 +401,14 @@ function parseSearchUsageMode(mode) {
|
|
|
398
401
|
}
|
|
399
402
|
if (typeof mode === "undefined")
|
|
400
403
|
return "both";
|
|
401
|
-
throw new
|
|
404
|
+
throw new UsageError(`Invalid usage mode: ${String(mode)}. Expected one of: none|both|item|guide`);
|
|
402
405
|
}
|
|
403
406
|
function parseSearchSource(source) {
|
|
404
407
|
if (source === "local" || source === "registry" || source === "both")
|
|
405
408
|
return source;
|
|
406
409
|
if (typeof source === "undefined")
|
|
407
410
|
return "local";
|
|
408
|
-
throw new
|
|
411
|
+
throw new UsageError(`Invalid search source: ${String(source)}. Expected one of: local|registry|both`);
|
|
409
412
|
}
|
|
410
413
|
function mergeSearchHits(localHits, registryHits, limit) {
|
|
411
414
|
const all = [...localHits, ...registryHits];
|
package/dist/stash-show.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import { parseAssetRef } from "./stash-ref";
|
|
3
|
-
import { resolveSourcesForOrigin } from "./origin-resolve";
|
|
4
|
-
import { resolveAssetPath } from "./stash-resolve";
|
|
5
2
|
import { getHandler } from "./asset-type-handler";
|
|
6
|
-
import { resolveStashSources, findSourceForPath, isEditable, buildEditHint } from "./stash-source";
|
|
7
|
-
import { buildFileContext, runMatchers, getRenderer, buildRenderContext } from "./file-context";
|
|
8
3
|
import { loadConfig } from "./config";
|
|
4
|
+
import { NotFoundError } from "./errors";
|
|
5
|
+
import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "./file-context";
|
|
6
|
+
import { resolveSourcesForOrigin } from "./origin-resolve";
|
|
7
|
+
import { parseAssetRef } from "./stash-ref";
|
|
8
|
+
import { resolveAssetPath } from "./stash-resolve";
|
|
9
|
+
import { buildEditHint, findSourceForPath, isEditable, resolveStashSources } from "./stash-source";
|
|
9
10
|
export async function agentikitShow(input) {
|
|
10
11
|
const parsed = parseAssetRef(input.ref);
|
|
11
12
|
const config = loadConfig();
|
|
@@ -25,11 +26,11 @@ export async function agentikitShow(input) {
|
|
|
25
26
|
}
|
|
26
27
|
if (!assetPath && parsed.origin && searchSources.length === 0) {
|
|
27
28
|
const installCmd = `akm add ${parsed.origin}`;
|
|
28
|
-
throw new
|
|
29
|
+
throw new NotFoundError(`Stash asset not found for ref: ${parsed.type}:${parsed.name}. ` +
|
|
29
30
|
`Kit "${parsed.origin}" is not installed. Run: ${installCmd}`);
|
|
30
31
|
}
|
|
31
32
|
if (!assetPath) {
|
|
32
|
-
throw lastError ?? new
|
|
33
|
+
throw lastError ?? new NotFoundError(`Stash asset not found for ref: ${parsed.type}:${parsed.name}`);
|
|
33
34
|
}
|
|
34
35
|
const source = findSourceForPath(assetPath, allSources);
|
|
35
36
|
const sourceStashDir = source?.path ?? allStashDirs[0];
|
package/dist/stash-source.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { resolveStashDir } from "./common";
|
|
4
4
|
import { loadConfig } from "./config";
|
|
5
|
+
import { warn } from "./warn";
|
|
5
6
|
// ── Resolution ──────────────────────────────────────────────────────────────
|
|
6
7
|
/**
|
|
7
8
|
* Build the ordered list of stash sources (search paths):
|
|
@@ -12,15 +13,13 @@ import { loadConfig } from "./config";
|
|
|
12
13
|
* The first entry is always the primary stash. Additional entries come
|
|
13
14
|
* from `searchPaths` config and `registry.installed` entries.
|
|
14
15
|
*/
|
|
15
|
-
export function resolveStashSources(overrideStashDir) {
|
|
16
|
+
export function resolveStashSources(overrideStashDir, existingConfig) {
|
|
16
17
|
const stashDir = overrideStashDir ?? resolveStashDir();
|
|
17
|
-
const config = loadConfig();
|
|
18
|
-
const sources = [
|
|
19
|
-
{ path: stashDir },
|
|
20
|
-
];
|
|
18
|
+
const config = existingConfig ?? loadConfig();
|
|
19
|
+
const sources = [{ path: stashDir }];
|
|
21
20
|
for (const dir of config.searchPaths) {
|
|
22
21
|
if (isSuspiciousStashRoot(dir)) {
|
|
23
|
-
|
|
22
|
+
warn(`Warning: stash root "${dir}" appears to be a system directory. This may be unintentional.`);
|
|
24
23
|
}
|
|
25
24
|
if (isValidDirectory(dir)) {
|
|
26
25
|
sources.push({ path: dir });
|
|
@@ -28,7 +27,7 @@ export function resolveStashSources(overrideStashDir) {
|
|
|
28
27
|
}
|
|
29
28
|
for (const entry of config.registry?.installed ?? []) {
|
|
30
29
|
if (isSuspiciousStashRoot(entry.stashRoot)) {
|
|
31
|
-
|
|
30
|
+
warn(`Warning: stash root "${entry.stashRoot}" appears to be a system directory. This may be unintentional.`);
|
|
32
31
|
}
|
|
33
32
|
if (isValidDirectory(entry.stashRoot)) {
|
|
34
33
|
sources.push({
|
|
@@ -103,15 +102,15 @@ export function buildEditHint(filePath, assetType, assetName, origin) {
|
|
|
103
102
|
return `This asset is managed by akm and may be overwritten on update. To edit, run: akm clone ${ref}`;
|
|
104
103
|
}
|
|
105
104
|
// ── Validation ──────────────────────────────────────────────────────────────
|
|
106
|
-
const SUSPICIOUS_ROOTS = new Set([
|
|
105
|
+
const SUSPICIOUS_ROOTS = new Set(["/", "/etc", "/bin", "/sbin", "/usr", "/var", "/tmp", "/dev", "/proc", "/sys"]);
|
|
107
106
|
function isSuspiciousStashRoot(dir) {
|
|
108
107
|
const resolved = path.resolve(dir);
|
|
109
|
-
const normalized = process.platform ===
|
|
108
|
+
const normalized = process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
110
109
|
if (SUSPICIOUS_ROOTS.has(normalized))
|
|
111
110
|
return true;
|
|
112
|
-
if (process.platform ===
|
|
111
|
+
if (process.platform === "win32") {
|
|
113
112
|
// Check for Windows system directories
|
|
114
|
-
const winDir = (process.env.SystemRoot ||
|
|
113
|
+
const winDir = (process.env.SystemRoot || "C:\\Windows").toLowerCase();
|
|
115
114
|
if (normalized === winDir || normalized.startsWith(winDir + path.sep))
|
|
116
115
|
return true;
|
|
117
116
|
}
|
package/dist/submit.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
6
|
import { fetchWithRetry, isAssetType } from "./common";
|
|
7
|
-
import {
|
|
7
|
+
import { asRecord, asString, GITHUB_API_BASE, githubHeaders } from "./github";
|
|
8
8
|
import { parseRegistryRef } from "./registry-resolve";
|
|
9
9
|
const REGISTRY_OWNER = "itlackey";
|
|
10
10
|
const REGISTRY_REPO = "agentikit-registry";
|
|
@@ -66,7 +66,9 @@ export async function agentikitSubmit(options = {}) {
|
|
|
66
66
|
let forkCreated = false;
|
|
67
67
|
try {
|
|
68
68
|
progress("Forking and cloning agentikit-registry");
|
|
69
|
-
runCommand(runtime, "gh", ["repo", "fork", `${REGISTRY_OWNER}/${REGISTRY_REPO}`, "--clone", "--remote"], {
|
|
69
|
+
runCommand(runtime, "gh", ["repo", "fork", `${REGISTRY_OWNER}/${REGISTRY_REPO}`, "--clone", "--remote"], {
|
|
70
|
+
cwd: tempRoot,
|
|
71
|
+
});
|
|
70
72
|
forkCreated = true;
|
|
71
73
|
progress(`Creating branch ${branchName}`);
|
|
72
74
|
runCommand(runtime, "git", ["checkout", "-b", branchName], { cwd: cloneDir });
|
|
@@ -112,20 +114,13 @@ export async function agentikitSubmit(options = {}) {
|
|
|
112
114
|
export async function buildSubmitEntry(options) {
|
|
113
115
|
const packageJson = options.packageJson;
|
|
114
116
|
const interactive = options.interactive === true;
|
|
115
|
-
const defaultName = options.name?.trim()
|
|
116
|
-
|
|
117
|
-
|| inferNameFromParsedRef(options.parsed);
|
|
118
|
-
const defaultDescription = options.description?.trim()
|
|
119
|
-
|| packageJson?.description;
|
|
117
|
+
const defaultName = options.name?.trim() || packageJson?.name || inferNameFromParsedRef(options.parsed);
|
|
118
|
+
const defaultDescription = options.description?.trim() || packageJson?.description;
|
|
120
119
|
const defaultTags = normalizeTags(options.tags ?? packageJson?.keywords ?? []);
|
|
121
120
|
const defaultAssetTypes = normalizeAssetTypes(options.assetTypes ?? packageJson?.agentikitAssetTypes ?? []);
|
|
122
|
-
const defaultAuthor = options.author?.trim()
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|| packageJson?.license;
|
|
126
|
-
const defaultHomepage = options.homepage?.trim()
|
|
127
|
-
|| packageJson?.homepage
|
|
128
|
-
|| inferHomepage(options.parsed);
|
|
121
|
+
const defaultAuthor = options.author?.trim() || packageJson?.author;
|
|
122
|
+
const defaultLicense = options.license?.trim() || packageJson?.license;
|
|
123
|
+
const defaultHomepage = options.homepage?.trim() || packageJson?.homepage || inferHomepage(options.parsed);
|
|
129
124
|
const rl = interactive ? createInterface({ input: process.stdin, output: process.stdout }) : undefined;
|
|
130
125
|
try {
|
|
131
126
|
const promptedName = await promptWithDefault("Name", defaultName, rl);
|
|
@@ -209,8 +204,7 @@ async function inferSubmitTargetFromDir(dir) {
|
|
|
209
204
|
if (packageJson.name) {
|
|
210
205
|
candidates.push(parseSubmitRef(packageJson.name));
|
|
211
206
|
}
|
|
212
|
-
const githubRef = extractGithubRepoRef(packageJson.repositoryUrl)
|
|
213
|
-
?? extractGithubRepoRef(packageJson.homepage);
|
|
207
|
+
const githubRef = extractGithubRepoRef(packageJson.repositoryUrl) ?? extractGithubRepoRef(packageJson.homepage);
|
|
214
208
|
if (githubRef) {
|
|
215
209
|
candidates.push(parseSubmitRef(githubRef));
|
|
216
210
|
}
|
|
@@ -277,7 +271,9 @@ function inferNameFromParsedRef(parsed) {
|
|
|
277
271
|
function canonicalSubmitRef(parsed) {
|
|
278
272
|
if (parsed.source === "npm")
|
|
279
273
|
return parsed.packageName;
|
|
280
|
-
return parsed.requestedRef
|
|
274
|
+
return parsed.requestedRef
|
|
275
|
+
? `${parsed.owner}/${parsed.repo}#${parsed.requestedRef}`
|
|
276
|
+
: `${parsed.owner}/${parsed.repo}`;
|
|
281
277
|
}
|
|
282
278
|
function inferHomepage(parsed) {
|
|
283
279
|
if (parsed.source === "npm") {
|
|
@@ -394,7 +390,7 @@ async function fetchRegistryManualEntries() {
|
|
|
394
390
|
if (!entriesResponse.ok) {
|
|
395
391
|
throw new Error(`Failed to load ${MANUAL_ENTRIES_FILE} from ${REGISTRY_OWNER}/${REGISTRY_REPO} (${entriesResponse.status}).`);
|
|
396
392
|
}
|
|
397
|
-
const parsed = await entriesResponse.json();
|
|
393
|
+
const parsed = (await entriesResponse.json());
|
|
398
394
|
if (!Array.isArray(parsed)) {
|
|
399
395
|
throw new Error(`${MANUAL_ENTRIES_FILE} is not a JSON array.`);
|
|
400
396
|
}
|
|
@@ -424,7 +420,10 @@ function readManualEntriesFile(filePath) {
|
|
|
424
420
|
}
|
|
425
421
|
function createPullRequest(options) {
|
|
426
422
|
const output = runCommand(options.runtime, "gh", buildPullRequestArgs(options.entry, options.username, options.branchName, options.pullRequestBody), { cwd: options.cloneDir });
|
|
427
|
-
const url = output.stdout
|
|
423
|
+
const url = output.stdout
|
|
424
|
+
.trim()
|
|
425
|
+
.split(/\r?\n/)
|
|
426
|
+
.find((line) => /^https:\/\/github\.com\//.test(line));
|
|
428
427
|
if (!url) {
|
|
429
428
|
throw new Error("gh pr create did not return a pull request URL.");
|
|
430
429
|
}
|
|
@@ -460,7 +459,10 @@ function buildPlannedCommands(options) {
|
|
|
460
459
|
formatCommand(["git", "add", MANUAL_ENTRIES_FILE]),
|
|
461
460
|
formatCommand(["git", "commit", "-m", `feat: add ${options.entry.name} to registry`]),
|
|
462
461
|
formatCommand(["git", "push", "origin", options.branchName]),
|
|
463
|
-
formatCommand([
|
|
462
|
+
formatCommand([
|
|
463
|
+
"gh",
|
|
464
|
+
...buildPullRequestArgs(options.entry, options.username, options.branchName, options.pullRequestBody),
|
|
465
|
+
]),
|
|
464
466
|
];
|
|
465
467
|
if (options.cleanupFork) {
|
|
466
468
|
commands.push(`# After PR is merged: ${formatCommand(["gh", "repo", "delete", `${options.username}/${REGISTRY_REPO}`, "--yes"])}`);
|
|
@@ -512,7 +514,10 @@ function ensureGhAvailable(runtime) {
|
|
|
512
514
|
}
|
|
513
515
|
}
|
|
514
516
|
function ensureGhAuthenticated(runtime) {
|
|
515
|
-
const result = spawnSync(runtime.ghBin, ["auth", "status", "--hostname", "github.com"], {
|
|
517
|
+
const result = spawnSync(runtime.ghBin, ["auth", "status", "--hostname", "github.com"], {
|
|
518
|
+
encoding: "utf8",
|
|
519
|
+
timeout: 10_000,
|
|
520
|
+
});
|
|
516
521
|
if (result.status !== 0) {
|
|
517
522
|
throw new Error("gh CLI is not authenticated for github.com.");
|
|
518
523
|
}
|
package/dist/tool-runner.js
CHANGED
|
@@ -88,11 +88,7 @@ export function shellQuote(input) {
|
|
|
88
88
|
.replace(/"/g, '""');
|
|
89
89
|
return `"${escaped}"`;
|
|
90
90
|
}
|
|
91
|
-
const escaped = input
|
|
92
|
-
.replace(/\\/g, "\\\\")
|
|
93
|
-
.replace(/"/g, '\\"')
|
|
94
|
-
.replace(/\$/g, "\\$")
|
|
95
|
-
.replace(/`/g, "\\`");
|
|
91
|
+
const escaped = input.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\$/g, "\\$").replace(/`/g, "\\`");
|
|
96
92
|
return `"${escaped}"`;
|
|
97
93
|
}
|
|
98
94
|
/**
|
package/dist/warn.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level quiet flag for suppressing stderr warnings.
|
|
3
|
+
* Controlled by the CLI --quiet / -q flag.
|
|
4
|
+
*/
|
|
5
|
+
let quiet = false;
|
|
6
|
+
export function setQuiet(value) {
|
|
7
|
+
quiet = value;
|
|
8
|
+
}
|
|
9
|
+
export function isQuiet() {
|
|
10
|
+
return quiet;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Emit a warning to stderr unless --quiet is active.
|
|
14
|
+
* Drop-in replacement for console.warn() across the codebase.
|
|
15
|
+
*/
|
|
16
|
+
export function warn(...args) {
|
|
17
|
+
if (!quiet) {
|
|
18
|
+
console.warn(...args);
|
|
19
|
+
}
|
|
20
|
+
}
|