akm-cli 0.7.5 → 0.8.0-rc.6
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/{.github/CHANGELOG.md → CHANGELOG.md} +113 -2
- package/README.md +20 -4
- package/SECURITY.md +93 -0
- package/dist/cli/config-migrate.js +144 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/confirm.js +73 -0
- package/dist/cli/parse-args.js +133 -0
- package/dist/cli.js +1995 -551
- package/dist/commands/agent-dispatch.js +110 -0
- package/dist/commands/agent-support.js +68 -0
- package/dist/commands/completions.js +3 -0
- package/dist/commands/config-cli.js +130 -534
- package/dist/commands/consolidate.js +1531 -0
- package/dist/commands/curate.js +44 -3
- package/dist/commands/db-cli.js +23 -0
- package/dist/commands/distill-promotion-policy.js +660 -0
- package/dist/commands/distill.js +990 -75
- package/dist/commands/eval-cases.js +43 -0
- package/dist/commands/events.js +5 -23
- package/dist/commands/graph.js +477 -0
- package/dist/commands/health.js +400 -0
- package/dist/commands/help/help-accept.md +9 -0
- package/dist/commands/help/help-improve.md +77 -0
- package/dist/commands/help/help-proposals.md +15 -0
- package/dist/commands/help/help-propose.md +17 -0
- package/dist/commands/help/help-reject.md +8 -0
- package/dist/commands/history.js +54 -46
- package/dist/commands/improve-profiles.js +146 -0
- package/dist/commands/improve-result-file.js +103 -0
- package/dist/commands/improve.js +2175 -0
- package/dist/commands/info.js +5 -2
- package/dist/commands/init.js +50 -2
- package/dist/commands/installed-stashes.js +102 -139
- package/dist/commands/knowledge.js +136 -0
- package/dist/commands/lint/agent-linter.js +49 -0
- package/dist/commands/lint/base-linter.js +479 -0
- package/dist/commands/lint/command-linter.js +49 -0
- package/dist/commands/lint/default-linter.js +16 -0
- package/dist/commands/lint/index.js +183 -0
- package/dist/commands/lint/knowledge-linter.js +16 -0
- package/dist/commands/lint/markdown-insertion.js +343 -0
- package/dist/commands/lint/memory-linter.js +61 -0
- package/dist/commands/lint/registry.js +36 -0
- package/dist/commands/lint/skill-linter.js +45 -0
- package/dist/commands/lint/task-linter.js +50 -0
- package/dist/commands/lint/types.js +4 -0
- package/dist/commands/lint/vault-key-rules.js +139 -0
- package/dist/commands/lint/workflow-linter.js +56 -0
- package/dist/commands/lint.js +4 -0
- package/dist/commands/migration-help.js +5 -2
- package/dist/commands/proposal.js +66 -12
- package/dist/commands/propose.js +86 -31
- package/dist/commands/reflect.js +1119 -73
- package/dist/commands/registry-search.js +5 -2
- package/dist/commands/remember.js +69 -6
- package/dist/commands/schema-repair.js +203 -0
- package/dist/commands/search.js +115 -14
- package/dist/commands/self-update.js +3 -0
- package/dist/commands/show.js +144 -25
- package/dist/commands/source-add.js +17 -45
- package/dist/commands/source-clone.js +3 -0
- package/dist/commands/source-manage.js +14 -19
- package/dist/commands/tasks.js +438 -0
- package/dist/commands/url-checker.js +42 -0
- package/dist/commands/vault.js +130 -77
- package/dist/core/action-contributors.js +28 -0
- package/dist/core/asset-ref.js +7 -0
- package/dist/core/asset-registry.js +7 -16
- package/dist/core/asset-serialize.js +88 -0
- package/dist/core/asset-spec.js +22 -0
- package/dist/core/common.js +157 -0
- package/dist/core/concurrent.js +25 -0
- package/dist/core/config-io.js +347 -0
- package/dist/core/config-migration.js +625 -0
- package/dist/core/config-schema.js +501 -0
- package/dist/core/config-sources.js +108 -0
- package/dist/core/config-types.js +4 -0
- package/dist/core/config-walker.js +337 -0
- package/dist/core/config.js +327 -987
- package/dist/core/errors.js +40 -19
- package/dist/core/events.js +91 -138
- package/dist/core/file-lock.js +104 -0
- package/dist/core/frontmatter.js +3 -6
- package/dist/core/lesson-lint.js +3 -0
- package/dist/core/markdown.js +20 -0
- package/dist/core/memory-belief.js +62 -0
- package/dist/core/memory-contradiction-detect.js +274 -0
- package/dist/core/memory-improve.js +806 -0
- package/dist/core/parse.js +158 -0
- package/dist/core/paths.js +326 -14
- package/dist/core/proposal-quality-validators.js +364 -0
- package/dist/core/proposal-validators.js +69 -0
- package/dist/core/proposals.js +498 -42
- package/dist/core/state-db.js +927 -0
- package/dist/core/text-truncation.js +107 -0
- package/dist/core/time.js +54 -0
- package/dist/core/warn.js +62 -1
- package/dist/core/write-source.js +3 -0
- package/dist/indexer/db-backup.js +391 -0
- package/dist/indexer/db-search.js +152 -253
- package/dist/indexer/db.js +933 -103
- package/dist/indexer/ensure-index.js +64 -0
- package/dist/indexer/file-context.js +3 -0
- package/dist/indexer/graph-boost.js +376 -101
- package/dist/indexer/graph-db.js +391 -0
- package/dist/indexer/graph-dedup.js +95 -0
- package/dist/indexer/graph-extraction.js +550 -124
- package/dist/indexer/index-context.js +4 -0
- package/dist/indexer/indexer.js +506 -291
- package/dist/indexer/llm-cache.js +47 -0
- package/dist/indexer/manifest.js +3 -0
- package/dist/indexer/matchers.js +148 -160
- package/dist/indexer/memory-inference.js +99 -74
- package/dist/indexer/metadata-contributors.js +29 -0
- package/dist/indexer/metadata.js +255 -196
- package/dist/indexer/path-resolver.js +92 -0
- package/dist/indexer/project-context.js +192 -0
- package/dist/indexer/ranking-contributors.js +331 -0
- package/dist/indexer/ranking.js +81 -0
- package/dist/indexer/search-fields.js +5 -9
- package/dist/indexer/search-hit-enrichers.js +111 -0
- package/dist/indexer/search-source.js +44 -10
- package/dist/indexer/semantic-status.js +5 -16
- package/dist/indexer/staleness-detect.js +447 -0
- package/dist/indexer/usage-events.js +12 -9
- package/dist/indexer/walker.js +28 -0
- package/dist/integrations/agent/builders.js +135 -0
- package/dist/integrations/agent/config.js +122 -230
- package/dist/integrations/agent/detect.js +3 -0
- package/dist/integrations/agent/index.js +7 -13
- package/dist/integrations/agent/model-aliases.js +55 -0
- package/dist/integrations/agent/profiles.js +70 -5
- package/dist/integrations/agent/prompts.js +150 -74
- package/dist/integrations/agent/runner.js +151 -0
- package/dist/integrations/agent/sdk-runner.js +126 -0
- package/dist/integrations/agent/spawn.js +118 -23
- package/dist/integrations/github.js +3 -0
- package/dist/integrations/lockfile.js +32 -69
- package/dist/integrations/session-logs/index.js +68 -0
- package/dist/integrations/session-logs/providers/claude-code.js +59 -0
- package/dist/integrations/session-logs/providers/opencode.js +55 -0
- package/dist/integrations/session-logs/types.js +4 -0
- package/dist/llm/call-ai.js +62 -0
- package/dist/llm/client.js +72 -124
- package/dist/llm/embedder.js +3 -19
- package/dist/llm/embedders/cache.js +3 -7
- package/dist/llm/embedders/local.js +3 -0
- package/dist/llm/embedders/remote.js +20 -8
- package/dist/llm/embedders/types.js +3 -7
- package/dist/llm/feature-gate.js +89 -48
- package/dist/llm/graph-extract.js +676 -70
- package/dist/llm/index-passes.js +9 -23
- package/dist/llm/memory-infer.js +52 -71
- package/dist/llm/metadata-enhance.js +42 -29
- package/dist/llm/prompts/graph-extract-user-prompt.md +35 -0
- package/dist/output/cli-hints-full.md +281 -0
- package/dist/output/cli-hints-short.md +65 -0
- package/dist/output/cli-hints.js +5 -318
- package/dist/output/context.js +3 -0
- package/dist/output/renderers.js +223 -256
- package/dist/output/shapes.js +150 -105
- package/dist/output/text.js +318 -30
- package/dist/registry/build-index.js +3 -0
- package/dist/registry/create-provider-registry.js +3 -0
- package/dist/registry/factory.js +3 -0
- package/dist/registry/origin-resolve.js +3 -0
- package/dist/registry/providers/index.js +3 -0
- package/dist/registry/providers/skills-sh.js +70 -49
- package/dist/registry/providers/static-index.js +53 -48
- package/dist/registry/providers/types.js +3 -24
- package/dist/registry/resolve.js +11 -16
- package/dist/registry/types.js +3 -0
- package/dist/scripts/migrate-storage.js +17307 -0
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8900 -0
- package/dist/scripts/migrations/v16-to-v17.js +141 -0
- package/dist/setup/detect.js +3 -0
- package/dist/setup/ripgrep-install.js +3 -0
- package/dist/setup/ripgrep-resolve.js +3 -0
- package/dist/setup/setup.js +775 -37
- package/dist/setup/steps.js +3 -15
- package/dist/sources/include.js +3 -0
- package/dist/sources/provider-factory.js +5 -12
- package/dist/sources/provider.js +3 -20
- package/dist/sources/providers/filesystem.js +19 -23
- package/dist/sources/providers/git.js +7 -5
- package/dist/sources/providers/index.js +3 -0
- package/dist/sources/providers/install-types.js +3 -13
- package/dist/sources/providers/npm.js +3 -4
- package/dist/sources/providers/provider-utils.js +3 -0
- package/dist/sources/providers/sync-from-ref.js +3 -11
- package/dist/sources/providers/tar-utils.js +3 -0
- package/dist/sources/providers/website.js +18 -22
- package/dist/sources/resolve.js +3 -0
- package/dist/sources/types.js +3 -0
- package/dist/sources/website-ingest.js +7 -0
- package/dist/tasks/backends/cron.js +203 -0
- package/dist/tasks/backends/exec-utils.js +28 -0
- package/dist/tasks/backends/index.js +24 -0
- package/dist/tasks/backends/launchd-template.xml +19 -0
- package/dist/tasks/backends/launchd.js +187 -0
- package/dist/tasks/backends/schtasks-template.xml +29 -0
- package/dist/tasks/backends/schtasks.js +215 -0
- package/dist/tasks/parser.js +211 -0
- package/dist/tasks/resolveAkmBin.js +87 -0
- package/dist/tasks/runner.js +458 -0
- package/dist/tasks/schedule.js +211 -0
- package/dist/tasks/schema.js +15 -0
- package/dist/tasks/validator.js +62 -0
- package/dist/version.js +3 -0
- package/dist/wiki/index-template.md +12 -0
- package/dist/wiki/ingest-workflow-template.md +54 -0
- package/dist/wiki/log-template.md +8 -0
- package/dist/wiki/schema-template.md +61 -0
- package/dist/wiki/wiki-templates.js +15 -0
- package/dist/wiki/wiki.js +13 -61
- package/dist/workflows/authoring.js +8 -25
- package/dist/workflows/cli.js +3 -0
- package/dist/workflows/db.js +140 -10
- package/dist/workflows/document-cache.js +3 -10
- package/dist/workflows/parser.js +3 -0
- package/dist/workflows/renderer.js +11 -3
- package/dist/workflows/runs.js +62 -91
- package/dist/workflows/schema.js +3 -0
- package/dist/workflows/scope-key.js +3 -0
- package/dist/workflows/validator.js +4 -8
- package/dist/workflows/workflow-template.md +24 -0
- package/docs/README.md +9 -2
- package/docs/data-and-telemetry.md +225 -0
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +2 -2
- package/docs/migration/release-notes/0.8.0.md +48 -0
- package/docs/migration/v0.7-to-v0.8.md +1307 -0
- package/package.json +20 -8
- package/.github/LICENSE +0 -374
- package/dist/commands/install-audit.js +0 -381
- package/dist/templates/wiki-templates.js +0 -100
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
3
4
|
import { fetchWithRetry } from "../../core/common";
|
|
4
|
-
import {
|
|
5
|
+
import { rethrowIfTestIsolationError } from "../../core/errors";
|
|
6
|
+
import { closeDatabase, getRegistryIndexCache, openDatabase, upsertRegistryIndexCache } from "../../indexer/db";
|
|
5
7
|
import { registerProvider } from "../factory";
|
|
6
8
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
7
9
|
/** Per-query cache TTL in milliseconds (15 minutes). */
|
|
8
10
|
const QUERY_CACHE_TTL_MS = 15 * 60 * 1000;
|
|
9
|
-
/** Maximum age before query cache is considered stale but still usable (1 day). */
|
|
10
|
-
const QUERY_CACHE_STALE_MS = 24 * 60 * 60 * 1000;
|
|
11
11
|
// ── Provider class ──────────────────────────────────────────────────────────
|
|
12
12
|
class SkillsShProvider {
|
|
13
13
|
type = "skills-sh";
|
|
@@ -89,13 +89,38 @@ class SkillsShProvider {
|
|
|
89
89
|
return ref.source === "github";
|
|
90
90
|
}
|
|
91
91
|
async fetchSkills(query, limit) {
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
// Build a stable DB cache key for this query
|
|
93
|
+
const dbCacheKey = this.queryDbCacheKey(query, limit);
|
|
94
|
+
// ── Step 1: Try DB cache (index.db) ───────────────────────────────────
|
|
95
|
+
let db;
|
|
96
|
+
let dbCacheResult;
|
|
97
|
+
try {
|
|
98
|
+
db = openDatabase();
|
|
99
|
+
dbCacheResult = getRegistryIndexCache(db, dbCacheKey, QUERY_CACHE_TTL_MS);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
// Never mask the bun-test isolation guard as "DB unavailable" — see
|
|
103
|
+
// rethrowIfTestIsolationError in src/core/errors.ts. Without this,
|
|
104
|
+
// a leaky test silently gets a cold cache + fresh fetch instead of
|
|
105
|
+
// the loud TEST_ISOLATION_MISSING failure the guard intends.
|
|
106
|
+
rethrowIfTestIsolationError(err);
|
|
107
|
+
// index.db not available yet (pre-migration install or test env) — fall through
|
|
97
108
|
}
|
|
98
|
-
|
|
109
|
+
if (dbCacheResult) {
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(dbCacheResult.indexJson);
|
|
112
|
+
if (Array.isArray(parsed)) {
|
|
113
|
+
const entries = parsed.filter(isValidSkillsEntry);
|
|
114
|
+
if (db)
|
|
115
|
+
closeDatabase(db);
|
|
116
|
+
return entries;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* corrupt DB entry — fall through */
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// ── Step 2: Fetch from API ─────────────────────────────────────────────
|
|
99
124
|
const baseUrl = this.config.url.replace(/\/+$/, "");
|
|
100
125
|
const url = `${baseUrl}/api/search?q=${encodeURIComponent(query)}&limit=${limit}`;
|
|
101
126
|
try {
|
|
@@ -105,13 +130,40 @@ class SkillsShProvider {
|
|
|
105
130
|
}
|
|
106
131
|
const data = (await response.json());
|
|
107
132
|
const entries = parseSkillsResponse(data);
|
|
108
|
-
|
|
133
|
+
// Write to DB cache (primary)
|
|
134
|
+
if (db) {
|
|
135
|
+
try {
|
|
136
|
+
upsertRegistryIndexCache(db, dbCacheKey, JSON.stringify(entries));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
/* best-effort */
|
|
140
|
+
}
|
|
141
|
+
closeDatabase(db);
|
|
142
|
+
}
|
|
109
143
|
return entries;
|
|
110
144
|
}
|
|
111
145
|
catch (err) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
146
|
+
if (db) {
|
|
147
|
+
try {
|
|
148
|
+
closeDatabase(db);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* ignore */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Fetch failed — use stale DB cache if available
|
|
155
|
+
if (dbCacheResult) {
|
|
156
|
+
try {
|
|
157
|
+
const parsed = JSON.parse(dbCacheResult.indexJson);
|
|
158
|
+
if (Array.isArray(parsed)) {
|
|
159
|
+
const entries = parsed.filter(isValidSkillsEntry);
|
|
160
|
+
if (entries.length > 0)
|
|
161
|
+
return entries;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* ignore */
|
|
166
|
+
}
|
|
115
167
|
}
|
|
116
168
|
throw err;
|
|
117
169
|
}
|
|
@@ -167,9 +219,8 @@ class SkillsShProvider {
|
|
|
167
219
|
});
|
|
168
220
|
return hits.length > 0 ? hits : undefined;
|
|
169
221
|
}
|
|
170
|
-
// ──
|
|
171
|
-
|
|
172
|
-
const cacheDir = getRegistryIndexCacheDir();
|
|
222
|
+
// ── DB cache key ────────────────────────────────────────────────────────
|
|
223
|
+
queryDbCacheKey(query, limit) {
|
|
173
224
|
const hasher = new Bun.CryptoHasher("md5");
|
|
174
225
|
hasher.update(this.config.url);
|
|
175
226
|
hasher.update("\0");
|
|
@@ -177,33 +228,7 @@ class SkillsShProvider {
|
|
|
177
228
|
hasher.update("\0");
|
|
178
229
|
hasher.update(String(limit));
|
|
179
230
|
const hash = hasher.digest("hex");
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
readQueryCache(cachePath) {
|
|
183
|
-
try {
|
|
184
|
-
const stat = fs.statSync(cachePath);
|
|
185
|
-
const raw = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
186
|
-
if (!Array.isArray(raw))
|
|
187
|
-
return null;
|
|
188
|
-
const entries = raw.filter(isValidSkillsEntry);
|
|
189
|
-
return { entries, mtime: stat.mtimeMs };
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
writeQueryCache(cachePath, entries) {
|
|
196
|
-
try {
|
|
197
|
-
const dir = path.dirname(cachePath);
|
|
198
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
199
|
-
const tmpPath = `${cachePath}.tmp.${process.pid}`;
|
|
200
|
-
// 0o600: owner read/write only — cache may contain search terms tied to API keys
|
|
201
|
-
fs.writeFileSync(tmpPath, JSON.stringify(entries), { encoding: "utf8", mode: 0o600 });
|
|
202
|
-
fs.renameSync(tmpPath, cachePath);
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
// Best-effort caching
|
|
206
|
-
}
|
|
231
|
+
return `skills-sh:${hash}`;
|
|
207
232
|
}
|
|
208
233
|
}
|
|
209
234
|
// ── Self-register ───────────────────────────────────────────────────────────
|
|
@@ -226,7 +251,3 @@ function isValidSkillsEntry(entry) {
|
|
|
226
251
|
typeof obj.installs === "number" &&
|
|
227
252
|
typeof obj.source === "string");
|
|
228
253
|
}
|
|
229
|
-
// ── Utilities ───────────────────────────────────────────────────────────────
|
|
230
|
-
function isExpired(mtimeMs, ttlMs) {
|
|
231
|
-
return Date.now() - mtimeMs > ttlMs;
|
|
232
|
-
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
3
4
|
import { fetchWithRetry, jsonWithByteCap, toErrorMessage } from "../../core/common";
|
|
4
|
-
import {
|
|
5
|
+
import { rethrowIfTestIsolationError } from "../../core/errors";
|
|
6
|
+
import { closeDatabase, getRegistryIndexCache, openDatabase, upsertRegistryIndexCache } from "../../indexer/db";
|
|
5
7
|
import { asString } from "../../integrations/github";
|
|
6
8
|
import { registerProvider } from "../factory";
|
|
7
9
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
@@ -114,13 +116,30 @@ function assetHitToPreview(hit) {
|
|
|
114
116
|
registerProvider("static-index", (config) => new StaticIndexProvider(config));
|
|
115
117
|
// ── Index loading with cache ────────────────────────────────────────────────
|
|
116
118
|
async function loadIndex(entry) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
// ── Step 1: Try DB cache (index.db) ─────────────────────────────────────
|
|
120
|
+
let db;
|
|
121
|
+
let dbCacheResult;
|
|
122
|
+
try {
|
|
123
|
+
db = openDatabase();
|
|
124
|
+
dbCacheResult = getRegistryIndexCache(db, entry.url, CACHE_TTL_MS);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
// Never mask the bun-test isolation guard as "DB unavailable" — see
|
|
128
|
+
// rethrowIfTestIsolationError in src/core/errors.ts. Without this, a
|
|
129
|
+
// leaky test silently gets a cold cache instead of the loud
|
|
130
|
+
// TEST_ISOLATION_MISSING failure the guard intends.
|
|
131
|
+
rethrowIfTestIsolationError(err);
|
|
132
|
+
// index.db not available yet (pre-migration install or test env) — fall through
|
|
133
|
+
}
|
|
134
|
+
if (dbCacheResult) {
|
|
135
|
+
const index = parseRegistryIndex(JSON.parse(dbCacheResult.indexJson));
|
|
136
|
+
if (index) {
|
|
137
|
+
if (db)
|
|
138
|
+
closeDatabase(db);
|
|
139
|
+
return index;
|
|
140
|
+
}
|
|
122
141
|
}
|
|
123
|
-
//
|
|
142
|
+
// ── Step 2: Fetch fresh index from remote ────────────────────────────────
|
|
124
143
|
try {
|
|
125
144
|
const response = await fetchWithRetry(entry.url, undefined, { timeout: 10_000 });
|
|
126
145
|
if (!response.ok) {
|
|
@@ -131,54 +150,40 @@ async function loadIndex(entry) {
|
|
|
131
150
|
const data = await jsonWithByteCap(response, 50 * 1024 * 1024);
|
|
132
151
|
const index = parseRegistryIndex(data);
|
|
133
152
|
if (index) {
|
|
134
|
-
|
|
153
|
+
// Write to DB cache (primary)
|
|
154
|
+
if (db) {
|
|
155
|
+
try {
|
|
156
|
+
const etag = response.headers.get("etag") ?? undefined;
|
|
157
|
+
const lastModified = response.headers.get("last-modified") ?? undefined;
|
|
158
|
+
upsertRegistryIndexCache(db, entry.url, JSON.stringify(index), { etag, lastModified });
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* best-effort */
|
|
162
|
+
}
|
|
163
|
+
closeDatabase(db);
|
|
164
|
+
}
|
|
135
165
|
return index;
|
|
136
166
|
}
|
|
137
167
|
throw new Error("Invalid registry index format");
|
|
138
168
|
}
|
|
139
169
|
catch (err) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
if (db) {
|
|
171
|
+
try {
|
|
172
|
+
closeDatabase(db);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
/* ignore */
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Fetch failed — use stale DB cache if available
|
|
179
|
+
if (dbCacheResult) {
|
|
180
|
+
const index = parseRegistryIndex(JSON.parse(dbCacheResult.indexJson));
|
|
181
|
+
if (index)
|
|
182
|
+
return index;
|
|
143
183
|
}
|
|
144
184
|
throw err;
|
|
145
185
|
}
|
|
146
186
|
}
|
|
147
|
-
// ── Cache helpers (exported for reuse by other providers) ───────────────────
|
|
148
|
-
export function indexCachePath(url) {
|
|
149
|
-
const indexDir = getRegistryIndexCacheDir();
|
|
150
|
-
// Deterministic filename from URL
|
|
151
|
-
const slug = url
|
|
152
|
-
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
153
|
-
.replace(/^-+|-+$/g, "")
|
|
154
|
-
.slice(0, 120);
|
|
155
|
-
return path.join(indexDir, `${slug}.json`);
|
|
156
|
-
}
|
|
157
|
-
export function readCachedIndex(cachePath) {
|
|
158
|
-
try {
|
|
159
|
-
const stat = fs.statSync(cachePath);
|
|
160
|
-
const raw = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
161
|
-
const index = parseRegistryIndex(raw);
|
|
162
|
-
if (!index)
|
|
163
|
-
return null;
|
|
164
|
-
return { index, mtime: stat.mtimeMs };
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
export function writeCachedIndex(cachePath, index) {
|
|
171
|
-
try {
|
|
172
|
-
const dir = path.dirname(cachePath);
|
|
173
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
174
|
-
const tmpPath = `${cachePath}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;
|
|
175
|
-
fs.writeFileSync(tmpPath, JSON.stringify(index), "utf8");
|
|
176
|
-
fs.renameSync(tmpPath, cachePath);
|
|
177
|
-
}
|
|
178
|
-
catch {
|
|
179
|
-
// Best-effort caching — don't fail the search if we can't write
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
187
|
export function isCacheExpired(mtimeMs) {
|
|
183
188
|
return Date.now() - mtimeMs > CACHE_TTL_MS;
|
|
184
189
|
}
|
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* A `RegistryProvider` is a read-only catalog that lists installable kits and
|
|
5
|
-
* (optionally) previews assets within them. It is *not* a `SourceProvider`:
|
|
6
|
-
* registry providers do not materialise files to disk — they only answer
|
|
7
|
-
* discovery queries.
|
|
8
|
-
*
|
|
9
|
-
* The two built-in registry providers at v1 are:
|
|
10
|
-
*
|
|
11
|
-
* - `static-index` — reads the v2 JSON index schema (the official akm registry
|
|
12
|
-
* and any static-hosted team registry). The v2 schema is owned by this
|
|
13
|
-
* provider, not by core akm.
|
|
14
|
-
* - `skills-sh` — wraps the skills.sh REST API.
|
|
15
|
-
*
|
|
16
|
-
* Context Hub is **not** a registry provider — it is an ordinary git repository
|
|
17
|
-
* recommended via the official static-index registry (see CLAUDE.md).
|
|
18
|
-
*
|
|
19
|
-
* Note: the simple `search()` method is the v0.6 surface and remains the
|
|
20
|
-
* primary entry point used by the orchestrator. The `searchKits` /
|
|
21
|
-
* `searchAssets` / `getKit` / `canHandle` methods are the v1-spec contract
|
|
22
|
-
* (§3.1) which built-in providers also implement so the orchestrator can be
|
|
23
|
-
* iterated cleanly post-Phase 6 without reaching into provider-specific shapes.
|
|
24
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
25
4
|
export {};
|
package/dist/registry/resolve.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { spawnSync } from "node:child_process";
|
|
2
5
|
import fs from "node:fs";
|
|
3
6
|
import os from "node:os";
|
|
@@ -340,6 +343,7 @@ async function resolveNpmArtifact(parsed) {
|
|
|
340
343
|
}
|
|
341
344
|
async function resolveGithubArtifact(parsed) {
|
|
342
345
|
const gitUrl = `https://github.com/${encodeURIComponent(parsed.owner)}/${encodeURIComponent(parsed.repo)}.git`;
|
|
346
|
+
const repoBase = `${GITHUB_API_BASE}/repos/${encodeURIComponent(parsed.owner)}/${encodeURIComponent(parsed.repo)}`;
|
|
343
347
|
// Prefer git-backed installs so private GitHub repos work with the user's
|
|
344
348
|
// normal git credential helper rather than requiring API-specific auth.
|
|
345
349
|
const gitResolvedRevision = resolveGitRevisionFromRemote(gitUrl, parsed.requestedRef);
|
|
@@ -355,18 +359,18 @@ async function resolveGithubArtifact(parsed) {
|
|
|
355
359
|
}
|
|
356
360
|
const headers = githubHeaders();
|
|
357
361
|
if (parsed.requestedRef) {
|
|
358
|
-
const commit = await tryFetchJson(`${
|
|
362
|
+
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(parsed.requestedRef)}`, headers);
|
|
359
363
|
const resolvedRevision = asString(commit?.sha) ?? parsed.requestedRef;
|
|
360
364
|
return {
|
|
361
365
|
id: parsed.id,
|
|
362
366
|
source: parsed.source,
|
|
363
367
|
ref: parsed.ref,
|
|
364
|
-
artifactUrl: `${
|
|
368
|
+
artifactUrl: `${repoBase}/tarball/${encodeURIComponent(parsed.requestedRef)}`,
|
|
365
369
|
resolvedRevision,
|
|
366
370
|
resolvedVersion: parsed.requestedRef,
|
|
367
371
|
};
|
|
368
372
|
}
|
|
369
|
-
const latestRelease = await tryFetchJson(`${
|
|
373
|
+
const latestRelease = await tryFetchJson(`${repoBase}/releases/latest`, headers);
|
|
370
374
|
if (latestRelease) {
|
|
371
375
|
const tarballUrl = asString(latestRelease.tarball_url);
|
|
372
376
|
if (tarballUrl) {
|
|
@@ -380,17 +384,17 @@ async function resolveGithubArtifact(parsed) {
|
|
|
380
384
|
};
|
|
381
385
|
}
|
|
382
386
|
}
|
|
383
|
-
const repoMeta = await fetchJson(
|
|
387
|
+
const repoMeta = await fetchJson(repoBase, headers);
|
|
384
388
|
const defaultBranch = asString(repoMeta.default_branch);
|
|
385
389
|
if (!defaultBranch) {
|
|
386
390
|
throw new Error(`Unable to resolve default branch for ${parsed.owner}/${parsed.repo}.`);
|
|
387
391
|
}
|
|
388
|
-
const commit = await tryFetchJson(`${
|
|
392
|
+
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(defaultBranch)}`, headers);
|
|
389
393
|
return {
|
|
390
394
|
id: parsed.id,
|
|
391
395
|
source: parsed.source,
|
|
392
396
|
ref: parsed.ref,
|
|
393
|
-
artifactUrl: `${
|
|
397
|
+
artifactUrl: `${repoBase}/tarball/${encodeURIComponent(defaultBranch)}`,
|
|
394
398
|
resolvedVersion: defaultBranch,
|
|
395
399
|
resolvedRevision: asString(commit?.sha) ?? defaultBranch,
|
|
396
400
|
};
|
|
@@ -407,16 +411,7 @@ function resolveGitRevisionFromRemote(url, requestedRef) {
|
|
|
407
411
|
return firstLine?.split(/\s/)[0] || undefined;
|
|
408
412
|
}
|
|
409
413
|
async function resolveGitArtifact(parsed) {
|
|
410
|
-
|
|
411
|
-
const ref = parsed.requestedRef ?? "HEAD";
|
|
412
|
-
if (parsed.requestedRef)
|
|
413
|
-
validateGitRef(parsed.requestedRef);
|
|
414
|
-
const result = spawnSync("git", ["ls-remote", parsed.url, ref], { encoding: "utf8", timeout: 30_000 });
|
|
415
|
-
let resolvedRevision;
|
|
416
|
-
if (result.status === 0) {
|
|
417
|
-
const firstLine = result.stdout.trim().split(/\r?\n/)[0];
|
|
418
|
-
resolvedRevision = firstLine?.split(/\s/)[0] || undefined;
|
|
419
|
-
}
|
|
414
|
+
const resolvedRevision = resolveGitRevisionFromRemote(parsed.url, parsed.requestedRef);
|
|
420
415
|
return {
|
|
421
416
|
id: parsed.id,
|
|
422
417
|
source: parsed.source,
|
package/dist/registry/types.js
CHANGED