akm-cli 0.9.0-beta.53 → 0.9.0-beta.55

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 (123) hide show
  1. package/dist/cli/clack.js +56 -0
  2. package/dist/cli/confirm.js +1 -1
  3. package/dist/cli.js +5 -3
  4. package/dist/commands/agent/contribute-cli.js +2 -3
  5. package/dist/commands/env/env-cli.js +187 -202
  6. package/dist/commands/env/secret-cli.js +109 -121
  7. package/dist/commands/feedback-cli.js +152 -155
  8. package/dist/commands/health/advisories.js +151 -0
  9. package/dist/commands/health/html-report.js +33 -10
  10. package/dist/commands/health/improve-metrics.js +754 -0
  11. package/dist/commands/health/llm-usage.js +65 -0
  12. package/dist/commands/health/md-report.js +103 -0
  13. package/dist/commands/health/metrics.js +278 -0
  14. package/dist/commands/health/task-runs.js +135 -0
  15. package/dist/commands/health/types.js +18 -0
  16. package/dist/commands/health/windows.js +196 -0
  17. package/dist/commands/health.js +15 -1492
  18. package/dist/commands/improve/anti-collapse.js +170 -0
  19. package/dist/commands/improve/collapse-detector.js +3 -2
  20. package/dist/commands/improve/consolidate.js +636 -633
  21. package/dist/commands/improve/dedup.js +1 -1
  22. package/dist/commands/improve/distill/content-repair.js +202 -0
  23. package/dist/commands/improve/distill/promote-memory.js +228 -0
  24. package/dist/commands/improve/distill/quality-gate.js +233 -0
  25. package/dist/commands/improve/distill-guards.js +127 -0
  26. package/dist/commands/improve/distill.js +49 -575
  27. package/dist/commands/improve/extract-cli.js +74 -76
  28. package/dist/commands/improve/extract.js +6 -4
  29. package/dist/commands/improve/hot-probation.js +45 -0
  30. package/dist/commands/improve/improve-auto-accept.js +3 -2
  31. package/dist/commands/improve/improve-cli.js +14 -13
  32. package/dist/commands/improve/improve-result-file.js +2 -1
  33. package/dist/commands/improve/improve.js +6 -5
  34. package/dist/commands/improve/loop-stages.js +19 -21
  35. package/dist/commands/improve/outcome-loop.js +18 -16
  36. package/dist/commands/improve/preparation.js +23 -5
  37. package/dist/commands/improve/procedural.js +10 -31
  38. package/dist/commands/improve/recombine.js +19 -43
  39. package/dist/commands/improve/reflect.js +1 -1
  40. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  41. package/dist/commands/improve/shared.js +48 -0
  42. package/dist/commands/observability-cli.js +4 -4
  43. package/dist/commands/proposal/drain-policies.js +2 -2
  44. package/dist/commands/proposal/drain.js +1 -1
  45. package/dist/commands/proposal/legacy-import.js +115 -0
  46. package/dist/commands/proposal/proposal-cli.js +3 -3
  47. package/dist/commands/proposal/proposal.js +2 -1
  48. package/dist/commands/proposal/propose.js +1 -1
  49. package/dist/commands/proposal/repository.js +829 -0
  50. package/dist/commands/proposal/validators/proposals.js +5 -920
  51. package/dist/commands/read/curate.js +4 -4
  52. package/dist/commands/read/remember-cli.js +132 -137
  53. package/dist/commands/read/search-cli.js +7 -5
  54. package/dist/commands/read/search.js +7 -3
  55. package/dist/commands/read/show.js +3 -5
  56. package/dist/commands/registry-cli.js +76 -87
  57. package/dist/commands/sources/add-cli.js +91 -95
  58. package/dist/commands/sources/history.js +1 -1
  59. package/dist/commands/sources/init.js +12 -0
  60. package/dist/commands/sources/schema-repair.js +1 -1
  61. package/dist/commands/sources/sources-cli.js +3 -3
  62. package/dist/commands/sources/stash-cli.js +2 -2
  63. package/dist/commands/tasks/default-tasks.js +12 -0
  64. package/dist/commands/tasks/tasks-cli.js +1 -2
  65. package/dist/commands/wiki-cli.js +2 -3
  66. package/dist/core/common.js +3 -3
  67. package/dist/core/config/config-schema.js +6 -0
  68. package/dist/core/config/config.js +12 -0
  69. package/dist/core/deep-merge.js +38 -0
  70. package/dist/core/events.js +2 -1
  71. package/dist/core/logs-db.js +8 -13
  72. package/dist/core/paths.js +14 -14
  73. package/dist/core/state-db.js +13 -1140
  74. package/dist/core/warn.js +21 -0
  75. package/dist/indexer/db/db.js +72 -709
  76. package/dist/indexer/db/entry-mapper.js +41 -0
  77. package/dist/indexer/db/schema.js +516 -0
  78. package/dist/indexer/ensure-index.js +3 -2
  79. package/dist/indexer/feedback/utility-policy.js +85 -0
  80. package/dist/indexer/graph/graph-extraction.js +2 -1
  81. package/dist/indexer/index-writer-lock.js +18 -0
  82. package/dist/indexer/indexer.js +94 -27
  83. package/dist/indexer/read-preflight.js +23 -0
  84. package/dist/indexer/search/fts-query.js +51 -0
  85. package/dist/indexer/walk/walker.js +21 -13
  86. package/dist/integrations/agent/detect.js +9 -0
  87. package/dist/integrations/agent/index.js +1 -1
  88. package/dist/integrations/agent/spawn.js +15 -66
  89. package/dist/llm/client.js +12 -0
  90. package/dist/llm/embedder.js +26 -2
  91. package/dist/llm/embedders/local.js +7 -1
  92. package/dist/output/text/helpers.js +13 -0
  93. package/dist/scripts/migrate-storage.js +6903 -7424
  94. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +49 -44
  95. package/dist/setup/detect.js +9 -0
  96. package/dist/setup/legacy-config.js +106 -0
  97. package/dist/setup/prompt.js +57 -0
  98. package/dist/setup/providers.js +14 -0
  99. package/dist/setup/registry-stash-loader.js +12 -0
  100. package/dist/setup/semantic-assets.js +124 -0
  101. package/dist/setup/setup.js +25 -1608
  102. package/dist/setup/steps/connection.js +734 -0
  103. package/dist/setup/steps/output.js +31 -0
  104. package/dist/setup/steps/platforms.js +124 -0
  105. package/dist/setup/steps/semantic.js +27 -0
  106. package/dist/setup/steps/sources.js +222 -0
  107. package/dist/setup/steps/stashdir.js +42 -0
  108. package/dist/setup/steps/tasks.js +152 -0
  109. package/dist/storage/repositories/canaries-repository.js +107 -0
  110. package/dist/storage/repositories/consolidation-repository.js +38 -0
  111. package/dist/storage/repositories/embeddings-repository.js +72 -0
  112. package/dist/storage/repositories/events-repository.js +187 -0
  113. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  114. package/dist/storage/repositories/improve-runs-repository.js +130 -0
  115. package/dist/storage/repositories/index-db.js +4 -7
  116. package/dist/storage/repositories/proposals-repository.js +220 -0
  117. package/dist/storage/repositories/recombine-repository.js +213 -0
  118. package/dist/storage/repositories/task-history-repository.js +93 -0
  119. package/dist/storage/sqlite-pragmas.js +3 -3
  120. package/dist/tasks/backends/index.js +9 -0
  121. package/dist/tasks/runner.js +11 -1
  122. package/package.json +2 -2
  123. package/dist/commands/improve/homeostatic.js +0 -497
@@ -846,6 +846,12 @@ export const AkmConfigShape = {
846
846
  semanticSearchMode: z.enum(["off", "auto"]).default("auto"),
847
847
  embedding: EmbeddingConnectionConfigSchema.optional(),
848
848
  index: IndexConfigSchema.optional(),
849
+ // The `installed[]` shape is OWNED by the registry (`InstalledStashEntry`):
850
+ // its `source` is the 4-value `InstallKind` produced by the registry ref
851
+ // parser, and installed entries never carry the extra passthrough keys. The
852
+ // schema still validates entries at runtime, but its OUTPUT type is pinned to
853
+ // the domain type so config consumers get the registry `InstalledStashEntry`
854
+ // (not a looser schema-local mirror) — the single-source-of-truth boundary.
849
855
  installed: z.array(InstalledStashEntrySchema).optional(),
850
856
  registries: z.array(RegistryConfigEntrySchema).optional(),
851
857
  sources: z.array(SourceConfigEntrySchema).optional(),
@@ -278,7 +278,19 @@ export function loadConfig() {
278
278
  warnIfProjectConfigPresent(process.cwd());
279
279
  return loadUserConfig();
280
280
  }
281
+ let saveConfigOverride;
282
+ /** TEST-ONLY. Swap the implementation of `saveConfig`; pass undefined to restore. */
283
+ export function _setSaveConfigForTests(fake) {
284
+ saveConfigOverride = fake;
285
+ }
281
286
  export function saveConfig(config) {
287
+ if (saveConfigOverride) {
288
+ saveConfigOverride(config);
289
+ return;
290
+ }
291
+ saveConfigReal(config);
292
+ }
293
+ function saveConfigReal(config) {
282
294
  cachedConfig = undefined;
283
295
  const configPath = getConfigPath();
284
296
  const dir = path.dirname(configPath);
@@ -0,0 +1,38 @@
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
+ * Generic recursive object merge, extracted from the setup wizard (it is not
6
+ * setup-specific). Plain objects merge key-by-key; arrays and scalars replace
7
+ * wholesale. Used to apply a partial `--file` config over the existing config
8
+ * without dropping sibling subkeys.
9
+ */
10
+ /** True for non-null, non-array plain objects. */
11
+ export function isPlainObject(value) {
12
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13
+ }
14
+ /**
15
+ * Recursively merge `incoming` into `base`: plain objects merge key-by-key,
16
+ * while arrays and scalars replace wholesale. A partial input therefore only
17
+ * updates the keys it carries and never drops sibling subkeys (e.g. a file
18
+ * containing `{ output: { format: "text" } }` leaves `output.detail` intact).
19
+ *
20
+ * `base` is treated as immutable — a fresh object graph is returned.
21
+ */
22
+ export function deepMergeConfig(base, incoming) {
23
+ if (!isPlainObject(incoming))
24
+ return incoming;
25
+ const baseObj = isPlainObject(base) ? base : {};
26
+ const out = { ...baseObj };
27
+ for (const [key, value] of Object.entries(incoming)) {
28
+ if (value === undefined)
29
+ continue;
30
+ if (isPlainObject(value) && isPlainObject(baseObj[key])) {
31
+ out[key] = deepMergeConfig(baseObj[key], value);
32
+ }
33
+ else {
34
+ out[key] = value;
35
+ }
36
+ }
37
+ return out;
38
+ }
@@ -25,9 +25,10 @@
25
25
  * - `ts` is ISO-8601 (UTC, millisecond precision).
26
26
  */
27
27
  import path from "node:path";
28
+ import { insertEvent, readStateEvents } from "../storage/repositories/events-repository.js";
28
29
  import { rethrowIfTestIsolationError } from "./errors.js";
29
30
  import { getDataDir } from "./paths.js";
30
- import { insertEvent, openStateDatabase, readStateEvents, withStateDb } from "./state-db.js";
31
+ import { openStateDatabase, withStateDb } from "./state-db.js";
31
32
  import { error } from "./warn.js";
32
33
  /**
33
34
  * Legacy events.jsonl path — used only by the migration script
@@ -37,11 +37,9 @@
37
37
  *
38
38
  * @module logs-db
39
39
  */
40
- import fs from "node:fs";
41
40
  import path from "node:path";
42
- import { openDatabase } from "../storage/database.js";
43
41
  import { runMigrations as runSqliteMigrations } from "../storage/engines/sqlite-migrations.js";
44
- import { applyStandardPragmas } from "../storage/sqlite-pragmas.js";
42
+ import { openManagedDatabase } from "../storage/managed-db.js";
45
43
  import { getDataDir } from "./paths.js";
46
44
  // ── Path helper ──────────────────────────────────────────────────────────────
47
45
  /**
@@ -72,16 +70,13 @@ export function getLogsDbPath() {
72
70
  */
73
71
  export function openLogsDatabase(dbPath) {
74
72
  const resolvedPath = dbPath ?? getLogsDbPath();
75
- const dir = path.dirname(resolvedPath);
76
- if (!fs.existsSync(dir)) {
77
- fs.mkdirSync(dir, { recursive: true });
78
- }
79
- const db = openDatabase(resolvedPath);
80
- // PRAGMAs must run before any DDL or DML. foreignKeys:false preserves this
81
- // opener's historical behaviour — logs.db has never enforced foreign keys.
82
- applyStandardPragmas(db, { dataDir: dir, foreignKeys: false });
83
- runMigrations(db);
84
- return db;
73
+ // foreignKeys:false preserves this opener's historical behaviour — logs.db
74
+ // has never enforced foreign keys.
75
+ return openManagedDatabase({
76
+ path: resolvedPath,
77
+ pragmas: { dataDir: path.dirname(resolvedPath), foreignKeys: false },
78
+ init: runMigrations,
79
+ });
85
80
  }
86
81
  // ── Migrations ───────────────────────────────────────────────────────────────
87
82
  /**
@@ -115,8 +115,8 @@ export function getConfigPath() {
115
115
  return path.join(getConfigDir(), "config.json");
116
116
  }
117
117
  // ── Cache directory ──────────────────────────────────────────────────────────
118
- export function getCacheDir() {
119
- const override = process.env.AKM_CACHE_DIR?.trim();
118
+ export function getCacheDir(env = process.env) {
119
+ const override = env.AKM_CACHE_DIR?.trim();
120
120
  if (override)
121
121
  return override;
122
122
  // Explicit XDG/platform overrides win before the transient-stash isolation
@@ -125,13 +125,13 @@ export function getCacheDir() {
125
125
  // as set, so the AKM_STASH_DIR transient rule does not silently move cache
126
126
  // writes away from where they pointed them.
127
127
  if (IS_WINDOWS) {
128
- const localAppData = process.env.LOCALAPPDATA?.trim();
128
+ const localAppData = env.LOCALAPPDATA?.trim();
129
129
  if (localAppData)
130
130
  return path.join(localAppData, "akm");
131
- const userProfile = process.env.USERPROFILE?.trim();
131
+ const userProfile = env.USERPROFILE?.trim();
132
132
  if (userProfile)
133
133
  return path.join(userProfile, "AppData", "Local", "akm");
134
- const appData = process.env.APPDATA?.trim();
134
+ const appData = env.APPDATA?.trim();
135
135
  if (appData) {
136
136
  // Heuristic fallback: APPDATA points to %APPDATA% (Roaming), so
137
137
  // navigate to the sibling "Local" directory. This is typically
@@ -141,7 +141,7 @@ export function getCacheDir() {
141
141
  }
142
142
  }
143
143
  else {
144
- const xdgCacheHome = process.env.XDG_CACHE_HOME?.trim();
144
+ const xdgCacheHome = env.XDG_CACHE_HOME?.trim();
145
145
  if (xdgCacheHome)
146
146
  return path.join(xdgCacheHome, "akm");
147
147
  }
@@ -150,7 +150,7 @@ export function getCacheDir() {
150
150
  // into `${AKM_STASH_DIR}/.akm/cache` so that config backups, registry-index
151
151
  // cache, and other regenerable artifacts do not pollute the user's host
152
152
  // ~/.cache/akm directory.
153
- const stashOverride = process.env.AKM_STASH_DIR?.trim();
153
+ const stashOverride = env.AKM_STASH_DIR?.trim();
154
154
  if (stashOverride && isTransientStashPath(stashOverride)) {
155
155
  return path.join(stashOverride, ".akm", "cache");
156
156
  }
@@ -158,7 +158,7 @@ export function getCacheDir() {
158
158
  // None of LOCALAPPDATA / USERPROFILE / APPDATA were set above.
159
159
  throw new ConfigError("Unable to determine cache directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
160
160
  }
161
- const home = process.env.HOME?.trim();
161
+ const home = env.HOME?.trim();
162
162
  if (!home)
163
163
  return path.join("/tmp", "akm-cache");
164
164
  return path.join(home, ".cache", "akm");
@@ -257,17 +257,17 @@ export function getTaskHistoryDir() {
257
257
  return path.join(getCacheDir(), "tasks", "history");
258
258
  }
259
259
  // ── Default stash directory ──────────────────────────────────────────────────
260
- export function getDefaultStashDir() {
261
- const override = process.env.AKM_STASH_DIR?.trim();
260
+ export function getDefaultStashDir(env = process.env) {
261
+ const override = env.AKM_STASH_DIR?.trim();
262
262
  if (override)
263
263
  return override;
264
264
  if (IS_WINDOWS) {
265
- const userProfile = process.env.USERPROFILE?.trim();
265
+ const userProfile = env.USERPROFILE?.trim();
266
266
  if (userProfile)
267
267
  return path.join(userProfile, "Documents", "akm");
268
268
  return path.join("C:\\", "akm");
269
269
  }
270
- const home = process.env.HOME?.trim();
270
+ const home = env.HOME?.trim();
271
271
  if (!home) {
272
272
  throw new ConfigError("Unable to determine default stash directory. Set HOME.", "STASH_DIR_NOT_FOUND");
273
273
  }
@@ -294,7 +294,7 @@ export function getDefaultStashDir() {
294
294
  * is fine even though `~/.local` is refused). This catches fat-finger
295
295
  * `--dir /` or `--dir ~` without preventing legitimate nested use.
296
296
  */
297
- export function assertSafeStashDir(stashDir) {
297
+ export function assertSafeStashDir(stashDir, env = process.env) {
298
298
  const resolved = path.resolve(stashDir);
299
299
  // Filesystem root — POSIX and Windows drive roots.
300
300
  if (resolved === "/" || /^[A-Za-z]:[\\/]?$/.test(resolved)) {
@@ -334,7 +334,7 @@ export function assertSafeStashDir(stashDir) {
334
334
  // under bun test (which isolates HOME to a tempdir while os.homedir()
335
335
  // still returns the real user's home).
336
336
  const candidateHomes = new Set();
337
- const envHome = (process.env.HOME ?? process.env.USERPROFILE)?.trim();
337
+ const envHome = (env.HOME ?? env.USERPROFILE)?.trim();
338
338
  if (envHome)
339
339
  candidateHomes.add(path.resolve(envHome));
340
340
  try {