akm-cli 0.9.0-beta.45 → 0.9.0-beta.46

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.
Files changed (77) hide show
  1. package/dist/cli/shared.js +28 -0
  2. package/dist/cli.js +1 -2
  3. package/dist/commands/env/env-cli.js +16 -24
  4. package/dist/commands/env/secret-cli.js +12 -20
  5. package/dist/commands/graph/graph-cli.js +5 -13
  6. package/dist/commands/graph/graph.js +3 -3
  7. package/dist/commands/improve/consolidate/chunking.js +141 -0
  8. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  9. package/dist/commands/improve/consolidate/merge.js +145 -0
  10. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  11. package/dist/commands/improve/consolidate/types.js +4 -0
  12. package/dist/commands/improve/consolidate.js +20 -571
  13. package/dist/commands/improve/distill.js +5 -9
  14. package/dist/commands/improve/eligibility.js +434 -0
  15. package/dist/commands/improve/extract-cli.js +9 -1
  16. package/dist/commands/improve/extract.js +5 -19
  17. package/dist/commands/improve/improve-auto-accept.js +4 -8
  18. package/dist/commands/improve/improve-cli.js +35 -60
  19. package/dist/commands/improve/improve-result-file.js +5 -23
  20. package/dist/commands/improve/improve-session.js +58 -0
  21. package/dist/commands/improve/improve.js +107 -3606
  22. package/dist/commands/improve/locks.js +154 -0
  23. package/dist/commands/improve/loop-stages.js +1079 -0
  24. package/dist/commands/improve/preparation.js +1963 -0
  25. package/dist/commands/improve/recombine.js +6 -12
  26. package/dist/commands/improve/reflect.js +29 -34
  27. package/dist/commands/proposal/drain.js +25 -48
  28. package/dist/commands/proposal/proposal-cli.js +21 -31
  29. package/dist/commands/proposal/validators/proposals.js +3 -7
  30. package/dist/commands/read/curate.js +70 -14
  31. package/dist/commands/read/knowledge.js +2 -2
  32. package/dist/commands/sources/self-update.js +2 -2
  33. package/dist/commands/sources/stash-cli.js +9 -37
  34. package/dist/commands/tasks/tasks-cli.js +19 -27
  35. package/dist/commands/wiki-cli.js +21 -35
  36. package/dist/core/config/config.js +18 -2
  37. package/dist/core/events.js +3 -7
  38. package/dist/core/logs-db.js +6 -63
  39. package/dist/core/state/migrations.js +714 -0
  40. package/dist/core/state-db.js +28 -779
  41. package/dist/indexer/db/db.js +82 -216
  42. package/dist/indexer/indexer.js +11 -112
  43. package/dist/indexer/passes/dir-staleness.js +114 -0
  44. package/dist/indexer/search/search-source.js +10 -24
  45. package/dist/integrations/agent/runner-dispatch.js +59 -0
  46. package/dist/llm/client.js +22 -11
  47. package/dist/llm/graph-extract.js +28 -39
  48. package/dist/llm/memory-infer.js +34 -22
  49. package/dist/llm/metadata-enhance.js +35 -30
  50. package/dist/llm/structured-call.js +49 -0
  51. package/dist/output/shapes/passthrough.js +0 -1
  52. package/dist/registry/providers/skills-sh.js +21 -147
  53. package/dist/registry/providers/static-index.js +15 -157
  54. package/dist/registry/resolve.js +22 -9
  55. package/dist/scripts/migrate-storage.js +892 -1186
  56. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +214 -179
  57. package/dist/setup/setup.js +26 -5
  58. package/dist/sources/providers/filesystem.js +0 -1
  59. package/dist/sources/providers/git-install.js +206 -0
  60. package/dist/sources/providers/git-provider.js +234 -0
  61. package/dist/sources/providers/git-stash.js +248 -0
  62. package/dist/sources/providers/git.js +10 -671
  63. package/dist/sources/providers/npm.js +2 -6
  64. package/dist/sources/providers/sync-from-ref.js +9 -1
  65. package/dist/sources/providers/website.js +2 -3
  66. package/dist/sources/website-ingest.js +51 -9
  67. package/dist/sources/wiki-fetchers/registry.js +53 -0
  68. package/dist/sources/wiki-fetchers/youtube.js +181 -0
  69. package/dist/storage/database.js +45 -10
  70. package/dist/storage/managed-db.js +82 -0
  71. package/dist/storage/repositories/registry-cache.js +92 -0
  72. package/dist/tasks/runner.js +5 -13
  73. package/dist/workflows/runtime/runs.js +1 -117
  74. package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
  75. package/package.json +5 -5
  76. package/dist/commands/db-cli.js +0 -23
  77. package/dist/indexer/db/db-backup.js +0 -376
@@ -33,7 +33,7 @@ import { loadConfig } from "../core/config/config.js";
33
33
  import { NotFoundError, rethrowIfTestIsolationError } from "../core/errors.js";
34
34
  import { buildTaskRunId, insertTaskLogLines, openLogsDatabase, } from "../core/logs-db.js";
35
35
  import { getTaskLogDir } from "../core/paths.js";
36
- import { getTaskHistory, openStateDatabase, queryTaskHistory, upsertTaskHistory } from "../core/state-db.js";
36
+ import { getTaskHistory, queryTaskHistory, upsertTaskHistory, withStateDb } from "../core/state-db.js";
37
37
  import { error } from "../core/warn.js";
38
38
  import { requireAgentProfile, runAgent } from "../integrations/agent/index.js";
39
39
  import { resolveProcessAgentProfile } from "../integrations/agent/config.js";
@@ -460,8 +460,7 @@ function persistRunLog(input) {
460
460
  // ── history ─────────────────────────────────────────────────────────────────
461
461
  function appendHistory(result) {
462
462
  try {
463
- const db = openStateDatabase();
464
- try {
463
+ withStateDb((db) => {
465
464
  upsertTaskHistory(db, {
466
465
  task_id: result.id,
467
466
  status: result.status,
@@ -477,10 +476,7 @@ function appendHistory(result) {
477
476
  profile: result.target.kind === "prompt" ? result.target.profile : undefined,
478
477
  }),
479
478
  });
480
- }
481
- finally {
482
- db.close();
483
- }
479
+ });
484
480
  }
485
481
  catch (err) {
486
482
  rethrowIfTestIsolationError(err);
@@ -488,8 +484,7 @@ function appendHistory(result) {
488
484
  }
489
485
  }
490
486
  export function readTaskHistory(options = {}) {
491
- const db = openStateDatabase();
492
- try {
487
+ return withStateDb((db) => {
493
488
  let rows;
494
489
  if (options.id) {
495
490
  const row = getTaskHistory(db, options.id);
@@ -503,10 +498,7 @@ export function readTaskHistory(options = {}) {
503
498
  return rows.slice(0, options.limit);
504
499
  }
505
500
  return rows;
506
- }
507
- finally {
508
- db.close();
509
- }
501
+ });
510
502
  }
511
503
  /**
512
504
  * Convert a `TaskHistoryRow` from state.db back to a `TaskRunResult` shape
@@ -2,23 +2,16 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { randomUUID } from "node:crypto";
5
- import fs from "node:fs";
6
5
  import { parseAssetRef } from "../../core/asset/asset-ref.js";
7
6
  import { loadConfig } from "../../core/config/config.js";
8
7
  import { NotFoundError, UsageError } from "../../core/errors.js";
9
8
  import { appendEvent } from "../../core/events.js";
10
- import { getDbPath } from "../../core/paths.js";
11
- import { closeDatabase, openExistingDatabase } from "../../indexer/db/db.js";
12
- import { resolveSourceEntries } from "../../indexer/search/search-source.js";
13
- import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
14
- import { resolveAssetPath } from "../../sources/resolve.js";
15
9
  import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
16
- import { formatWorkflowErrors } from "../authoring/authoring.js";
17
10
  import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
18
- import { parseWorkflow } from "../parser.js";
19
11
  import { validateStepSummary } from "../validate-summary.js";
20
12
  import { resolveAgentIdentity } from "./agent-identity.js";
21
13
  import { evaluateCheckin } from "./checkin.js";
14
+ import { loadWorkflowAsset, resolveWorkflowEntryId } from "./workflow-asset-loader.js";
22
15
  export async function startWorkflowRun(ref, params = {}, options) {
23
16
  const asset = await loadWorkflowAsset(ref);
24
17
  return withWorkflowRunsRepo(async (repo) => {
@@ -299,115 +292,6 @@ async function resolveRunSpecifier(repo, specifier, params) {
299
292
  const started = await startWorkflowRun(ref, params ?? {});
300
293
  return { run: readWorkflowRun(repo, started.run.id), autoStarted: true };
301
294
  }
302
- async function loadWorkflowAsset(ref) {
303
- const parsed = parseAssetRef(ref);
304
- if (parsed.type !== "workflow") {
305
- throw new UsageError(`Expected a workflow ref (workflow:<name>), got "${ref}".`);
306
- }
307
- const config = loadConfig();
308
- const allSources = resolveSourceEntries(undefined, config);
309
- const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
310
- let assetPath;
311
- let sourcePath;
312
- for (const source of searchSources) {
313
- try {
314
- assetPath = await resolveAssetPath(source.path, "workflow", parsed.name);
315
- sourcePath = source.path;
316
- break;
317
- }
318
- catch {
319
- /* continue */
320
- }
321
- }
322
- if (!assetPath) {
323
- throw new NotFoundError(`Workflow not found for ref: workflow:${parsed.name}`);
324
- }
325
- const resolvedSourcePath = sourcePath ?? config.stashDir ?? assetPath;
326
- const fullRef = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
327
- const cached = readWorkflowDocumentFromIndex(resolvedSourcePath, fullRef);
328
- const document = cached ?? loadWorkflowDocumentFromDisk(assetPath);
329
- return projectAsset(document, fullRef, assetPath, resolvedSourcePath);
330
- }
331
- function loadWorkflowDocumentFromDisk(assetPath) {
332
- const content = fs.readFileSync(assetPath, "utf8");
333
- const result = parseWorkflow(content, { path: assetPath });
334
- if (!result.ok) {
335
- throw new UsageError(formatWorkflowErrors(assetPath, result.errors));
336
- }
337
- return result.document;
338
- }
339
- function readWorkflowDocumentFromIndex(sourcePath, ref) {
340
- const dbPath = getDbPath();
341
- if (!fs.existsSync(dbPath))
342
- return null;
343
- const db = openExistingDatabase(dbPath);
344
- try {
345
- const parsed = parseAssetRef(ref);
346
- const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
347
- const row = db
348
- .prepare(`SELECT wd.document_json AS document_json
349
- FROM workflow_documents wd
350
- JOIN entries e ON e.id = wd.entry_id
351
- WHERE e.entry_type = 'workflow' AND e.entry_key = ?
352
- LIMIT 1`)
353
- .get(entryKey);
354
- if (!row)
355
- return null;
356
- try {
357
- return JSON.parse(row.document_json);
358
- }
359
- catch {
360
- return null;
361
- }
362
- }
363
- finally {
364
- closeDatabase(db);
365
- }
366
- }
367
- function projectAsset(doc, ref, assetPath, sourcePath) {
368
- return {
369
- ref,
370
- path: assetPath,
371
- sourcePath,
372
- title: doc.title,
373
- ...(doc.parameters
374
- ? {
375
- parameters: doc.parameters.map((p) => ({
376
- name: p.name,
377
- ...(p.description ? { description: p.description } : {}),
378
- })),
379
- }
380
- : {}),
381
- steps: doc.steps.map((s) => ({
382
- id: s.id,
383
- title: s.title,
384
- instructions: s.instructions.text,
385
- ...(s.completionCriteria ? { completionCriteria: s.completionCriteria.map((c) => c.text) } : {}),
386
- sequenceIndex: s.sequenceIndex,
387
- })),
388
- };
389
- }
390
- function resolveWorkflowEntryId(sourcePath, ref) {
391
- const dbPath = getDbPath();
392
- if (!fs.existsSync(dbPath))
393
- return null;
394
- const db = openExistingDatabase(dbPath);
395
- try {
396
- const parsed = parseAssetRef(ref);
397
- const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
398
- const row = db
399
- .prepare(`SELECT id
400
- FROM entries
401
- WHERE entry_type = 'workflow'
402
- AND entry_key = ?
403
- LIMIT 1`)
404
- .get(entryKey);
405
- return row?.id ?? null;
406
- }
407
- finally {
408
- closeDatabase(db);
409
- }
410
- }
411
295
  function readWorkflowRun(repo, runId) {
412
296
  const run = repo.getRunById(runId);
413
297
  if (!run) {
@@ -0,0 +1,125 @@
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/.
4
+ import fs from "node:fs";
5
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
6
+ import { loadConfig } from "../../core/config/config.js";
7
+ import { NotFoundError, UsageError } from "../../core/errors.js";
8
+ import { getDbPath } from "../../core/paths.js";
9
+ import { resolveSourceEntries } from "../../indexer/search/search-source.js";
10
+ import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
11
+ import { resolveAssetPath } from "../../sources/resolve.js";
12
+ import { withIndexDb } from "../../storage/repositories/index-db.js";
13
+ import { formatWorkflowErrors } from "../authoring/authoring.js";
14
+ import { parseWorkflow } from "../parser.js";
15
+ /**
16
+ * Resolve a `workflow:<name>` ref to a fully-projected {@link WorkflowAsset}.
17
+ *
18
+ * Prefers the parsed document cached in `index.db` (fast path) and falls back to
19
+ * reading + parsing the source file from disk. Pure loading/parsing concern —
20
+ * extracted from the run repository so run orchestration no longer owns asset
21
+ * resolution.
22
+ */
23
+ export async function loadWorkflowAsset(ref) {
24
+ const parsed = parseAssetRef(ref);
25
+ if (parsed.type !== "workflow") {
26
+ throw new UsageError(`Expected a workflow ref (workflow:<name>), got "${ref}".`);
27
+ }
28
+ const config = loadConfig();
29
+ const allSources = resolveSourceEntries(undefined, config);
30
+ const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
31
+ let assetPath;
32
+ let sourcePath;
33
+ for (const source of searchSources) {
34
+ try {
35
+ assetPath = await resolveAssetPath(source.path, "workflow", parsed.name);
36
+ sourcePath = source.path;
37
+ break;
38
+ }
39
+ catch {
40
+ /* continue */
41
+ }
42
+ }
43
+ if (!assetPath) {
44
+ throw new NotFoundError(`Workflow not found for ref: workflow:${parsed.name}`);
45
+ }
46
+ const resolvedSourcePath = sourcePath ?? config.stashDir ?? assetPath;
47
+ const fullRef = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
48
+ const cached = readWorkflowDocumentFromIndex(resolvedSourcePath, fullRef);
49
+ const document = cached ?? loadWorkflowDocumentFromDisk(assetPath);
50
+ return projectAsset(document, fullRef, assetPath, resolvedSourcePath);
51
+ }
52
+ /**
53
+ * Resolve the `entries.id` for an indexed workflow, or null when the index
54
+ * database does not yet exist or has no matching entry.
55
+ */
56
+ export function resolveWorkflowEntryId(sourcePath, ref) {
57
+ if (!fs.existsSync(getDbPath()))
58
+ return null;
59
+ const parsed = parseAssetRef(ref);
60
+ const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
61
+ return withIndexDb((db) => {
62
+ const row = db
63
+ .prepare(`SELECT id
64
+ FROM entries
65
+ WHERE entry_type = 'workflow'
66
+ AND entry_key = ?
67
+ LIMIT 1`)
68
+ .get(entryKey);
69
+ return row?.id ?? null;
70
+ });
71
+ }
72
+ function loadWorkflowDocumentFromDisk(assetPath) {
73
+ const content = fs.readFileSync(assetPath, "utf8");
74
+ const result = parseWorkflow(content, { path: assetPath });
75
+ if (!result.ok) {
76
+ throw new UsageError(formatWorkflowErrors(assetPath, result.errors));
77
+ }
78
+ return result.document;
79
+ }
80
+ function readWorkflowDocumentFromIndex(sourcePath, ref) {
81
+ if (!fs.existsSync(getDbPath()))
82
+ return null;
83
+ const parsed = parseAssetRef(ref);
84
+ const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
85
+ return withIndexDb((db) => {
86
+ const row = db
87
+ .prepare(`SELECT wd.document_json AS document_json
88
+ FROM workflow_documents wd
89
+ JOIN entries e ON e.id = wd.entry_id
90
+ WHERE e.entry_type = 'workflow' AND e.entry_key = ?
91
+ LIMIT 1`)
92
+ .get(entryKey);
93
+ if (!row)
94
+ return null;
95
+ try {
96
+ return JSON.parse(row.document_json);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ });
102
+ }
103
+ function projectAsset(doc, ref, assetPath, sourcePath) {
104
+ return {
105
+ ref,
106
+ path: assetPath,
107
+ sourcePath,
108
+ title: doc.title,
109
+ ...(doc.parameters
110
+ ? {
111
+ parameters: doc.parameters.map((p) => ({
112
+ name: p.name,
113
+ ...(p.description ? { description: p.description } : {}),
114
+ })),
115
+ }
116
+ : {}),
117
+ steps: doc.steps.map((s) => ({
118
+ id: s.id,
119
+ title: s.title,
120
+ instructions: s.instructions.text,
121
+ ...(s.completionCriteria ? { completionCriteria: s.completionCriteria.map((c) => c.text) } : {}),
122
+ sequenceIndex: s.sequenceIndex,
123
+ })),
124
+ };
125
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.0-beta.45",
3
+ "version": "0.9.0-beta.46",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [
@@ -56,9 +56,9 @@
56
56
  "check:fast": "bun run lint && bunx tsc --noEmit && bun run test:unit",
57
57
  "check:changed": "bun test tests/output-baseline.test.ts tests/integration/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
58
58
  "sweep:tmp": "bun scripts/sweep-test-tmp.ts",
59
- "test": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-1} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
60
- "test:unit": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-1} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
61
- "test:integration": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-1} --timeout=30000 ./tests/integration ./tests/commands ./tests/workflows",
59
+ "test": "bash scripts/test-unit.sh",
60
+ "test:unit": "bash scripts/test-unit.sh",
61
+ "test:integration": "bun run sweep:tmp && bun test --parallel=1 --timeout=30000 ./tests/integration ./tests/commands ./tests/workflows",
62
62
  "test:unit:shard": "bun run sweep:tmp && bun test --parallel=1 --timeout=30000 ./tests --path-ignore-patterns=tests/integration --shard=${SHARD:?set SHARD=k/N}",
63
63
  "test:integration:shard": "bun run sweep:tmp && bun test --parallel=1 --timeout=30000 ./tests/integration ./tests/commands ./tests/workflows --shard=${SHARD:?set SHARD=k/N}",
64
64
  "test:node-smoke": "bun scripts/node-smoke.ts",
@@ -69,7 +69,7 @@
69
69
  "lint:devto-posts:fix": "bun scripts/lint-devto-posts.ts --fix",
70
70
  "publish:devto": "npx -y @sinedied/devto-cli push \"docs/posts/**/*.md\" --token \"$DEVTO_TOKEN\" --repo \"$GITHUB_REPOSITORY\" --branch \"${GITHUB_REF_NAME:-main}\" --reconcile",
71
71
  "release:check": "./tests/release-check.sh",
72
- "lint": "bunx biome check src/ tests/ && bun scripts/lint-tests-isolation.ts && bun scripts/lint-license-headers.ts && bun scripts/lint-runtime-boundary.ts",
72
+ "lint": "bunx biome check src/ tests/ && bun scripts/lint-tests-isolation.ts && bun scripts/lint-license-headers.ts && bun scripts/lint-runtime-boundary.ts && bun scripts/lint-repository-sql.ts",
73
73
  "lint:runtime-boundary": "bun scripts/lint-runtime-boundary.ts",
74
74
  "lint:tests-isolation": "bun scripts/lint-tests-isolation.ts",
75
75
  "lint:fix": "bunx biome check --write src/ tests/",
@@ -1,23 +0,0 @@
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/.
4
- /**
5
- * CLI command surface for `akm db ...`.
6
- *
7
- * MVP scope: only `akm db backups` is exposed. It lists the pre-upgrade
8
- * snapshots written by `backupDataDir()` under `<dataDir>/backups/`.
9
- *
10
- * Restoration is intentionally NOT a CLI subcommand for MVP — operators are
11
- * expected to stop akm and use `scripts/migrations/restore-data-dir.sh` (or a
12
- * plain `mv`/`cp`) to recover. Keeping the surface narrow lets us evolve the
13
- * backup format under the hood without locking in an API.
14
- */
15
- import { getDataDir } from "../core/paths.js";
16
- import { listBackups } from "../indexer/db/db-backup.js";
17
- export function akmDbBackups() {
18
- const dataDir = getDataDir();
19
- return {
20
- dataDir,
21
- backups: listBackups(dataDir),
22
- };
23
- }