akm-cli 0.9.14 → 0.9.15-beta.1

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 (110) hide show
  1. package/CHANGELOG.md +397 -0
  2. package/STABILITY.md +6 -3
  3. package/dist/assets/prompts/reflect-feedback-framing.md +1 -0
  4. package/dist/assets/prompts/reflect-llm-framed-contract.md +2 -0
  5. package/dist/assets/prompts/reflect-llm-schema-contract.md +2 -0
  6. package/dist/assets/tasks/core/improve.yml +1 -1
  7. package/dist/assets/tasks/core/index-refresh.yml +1 -1
  8. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +1 -1
  9. package/dist/assets/tasks/improve/akm-improve-catchup.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-frequent.yml +1 -1
  12. package/dist/assets/tasks/improve/akm-improve-nightly.yml +1 -1
  13. package/dist/cli/retired-commands.js +0 -1
  14. package/dist/cli/shared.js +9 -0
  15. package/dist/cli/unknown-flags.js +1 -0
  16. package/dist/cli.js +3 -2
  17. package/dist/commands/config-cli.js +85 -3
  18. package/dist/commands/env/env-cli.js +1 -42
  19. package/dist/commands/env/env.js +1 -1
  20. package/dist/commands/env/secret-cli.js +1 -2
  21. package/dist/commands/health/checks.js +357 -63
  22. package/dist/commands/health/engine-usage.js +45 -0
  23. package/dist/commands/health/improve-metrics.js +18 -0
  24. package/dist/commands/health/llm-usage.js +41 -1
  25. package/dist/commands/health/plugin-staleness.js +7 -3
  26. package/dist/commands/health/version-drift.js +93 -0
  27. package/dist/commands/health/windows.js +3 -1
  28. package/dist/commands/health.js +44 -9
  29. package/dist/commands/improve/consolidate/chunking.js +4 -2
  30. package/dist/commands/improve/improve-cli.js +99 -5
  31. package/dist/commands/improve/improve-report.js +154 -0
  32. package/dist/commands/improve/improve-result-file.js +45 -33
  33. package/dist/commands/improve/improve-strategies.js +133 -3
  34. package/dist/commands/improve/improve-usage-report.js +182 -0
  35. package/dist/commands/improve/improve.js +40 -3
  36. package/dist/commands/improve/locks.js +27 -78
  37. package/dist/commands/improve/planner.js +1 -0
  38. package/dist/commands/improve/preparation.js +9 -1
  39. package/dist/commands/improve/reflect.js +44 -4
  40. package/dist/commands/models-cli.js +50 -1
  41. package/dist/commands/proposal/repository.js +8 -3
  42. package/dist/commands/proposal/validators/proposal-quality-validators.js +41 -6
  43. package/dist/commands/proposal/validators/proposal-validators.js +24 -0
  44. package/dist/commands/read/search-cli.js +38 -2
  45. package/dist/commands/read/show.js +103 -4
  46. package/dist/commands/sources/info.js +5 -1
  47. package/dist/commands/sources/self-update.js +2 -2
  48. package/dist/commands/sources/stash-cli.js +31 -0
  49. package/dist/commands/tasks/tasks-cli.js +49 -2
  50. package/dist/commands/workflow-cli.js +86 -12
  51. package/dist/core/asset/markdown-fragments.js +35 -0
  52. package/dist/core/config/config-schema.js +14 -0
  53. package/dist/core/config/config.js +302 -24
  54. package/dist/core/env-secret-ref.js +58 -5
  55. package/dist/core/errors.js +30 -0
  56. package/dist/core/improve-result.js +51 -0
  57. package/dist/core/loopback.js +17 -0
  58. package/dist/core/paths.js +11 -0
  59. package/dist/core/run-lock.js +96 -0
  60. package/dist/core/sensitive-marker-path.js +19 -0
  61. package/dist/core/state-db.js +74 -14
  62. package/dist/indexer/index-rebuild-lock.js +73 -0
  63. package/dist/indexer/index-writer-lock.js +40 -1
  64. package/dist/indexer/index-written-assets.js +21 -1
  65. package/dist/indexer/indexer.js +18 -17
  66. package/dist/indexer/materialize-embeddings.js +282 -32
  67. package/dist/indexer/search/db-search.js +49 -2
  68. package/dist/integrations/agent/engine-resolution.js +96 -6
  69. package/dist/integrations/agent/execution-definitions.js +6 -15
  70. package/dist/integrations/agent/execution-lowering.js +6 -1
  71. package/dist/integrations/agent/execution-preparation.js +1 -1
  72. package/dist/integrations/agent/model-map.js +123 -20
  73. package/dist/integrations/agent/prompts.js +40 -8
  74. package/dist/integrations/agent/runner-dispatch.js +9 -3
  75. package/dist/integrations/agent/runner.js +2 -0
  76. package/dist/llm/client.js +8 -3
  77. package/dist/llm/embedder.js +20 -8
  78. package/dist/llm/embedders/local.js +10 -2
  79. package/dist/llm/embedders/remote.js +188 -21
  80. package/dist/output/shapes/helpers.js +38 -2
  81. package/dist/output/shapes/models-list.js +16 -0
  82. package/dist/output/shapes/passthrough.js +2 -0
  83. package/dist/output/shapes.js +4 -0
  84. package/dist/output/text/command-format.js +29 -0
  85. package/dist/output/text/helpers.js +1 -1
  86. package/dist/output/text/improve-report.js +27 -0
  87. package/dist/{commands/env/marker-path.js → output/text/models.js} +4 -3
  88. package/dist/output/text/show-format.js +4 -0
  89. package/dist/output/text.js +4 -0
  90. package/dist/scripts/akm-migrate-node.js +24798 -21732
  91. package/dist/scripts/akm-migrate.js +23408 -20343
  92. package/dist/storage/repositories/improve-runs-repository.js +34 -0
  93. package/dist/storage/repositories/index-fts-repository.js +49 -6
  94. package/dist/storage/repositories/index-vec-repository.js +30 -0
  95. package/dist/storage/repositories/workflow-runs-repository.js +55 -18
  96. package/dist/tasks/backends/cron.js +14 -7
  97. package/dist/tasks/run/run-workflow-task.js +16 -0
  98. package/dist/workflows/exec/child-workflow.js +2 -2
  99. package/dist/workflows/exec/dispatch-redaction.js +21 -9
  100. package/dist/workflows/exec/run-workflow.js +6 -5
  101. package/dist/workflows/runtime/runs.js +33 -5
  102. package/docs/migration/release-notes/0.9.15.md +52 -0
  103. package/docs/migration/release-notes/README.md +4 -0
  104. package/docs/reference/cli.md +245 -29
  105. package/docs/reference/configuration.md +180 -19
  106. package/docs/reference/data-and-telemetry.md +8 -0
  107. package/docs/reference/tasks.md +16 -1
  108. package/docs/reference/workflow-schema.md +5 -1
  109. package/package.json +1 -1
  110. package/schemas/akm-config.json +8 -0
@@ -12,10 +12,12 @@
12
12
  * settings use their canonical engine/strategy paths; retired aliases are not
13
13
  * rewritten at this boundary.
14
14
  */
15
+ import { isDeepStrictEqual } from "node:util";
15
16
  import { defineGroupCommand, defineJsonCommand, output } from "../cli/shared.js";
16
- import { resolveStashDir } from "../core/common.js";
17
- import { DEFAULT_CONFIG, loadConfig, mutateConfig } from "../core/config/config.js";
17
+ import { isRecord, resolveStashDir } from "../core/common.js";
18
+ import { DEFAULT_CONFIG, getConfigValueSource, loadConfig, mutateConfig, parseAndValidateConfigText, resolveConfigRefSource, } from "../core/config/config.js";
18
19
  import { configGet, configSet, configUnset, unknownKeyHint } from "../core/config/config-walker.js";
20
+ import { UsageError } from "../core/errors.js";
19
21
  import { getCacheDir, getConfigPath, getDbPath, getDefaultStashDir } from "../core/paths.js";
20
22
  import { formatRegistryUrl } from "../core/registry-url.js";
21
23
  // ── Public API ──────────────────────────────────────────────────────────────
@@ -53,6 +55,55 @@ function isRegistryUrlPath(path) {
53
55
  return path[0] === "registries" && path.at(-1) === "url";
54
56
  }
55
57
  export { unknownKeyHint };
58
+ /**
59
+ * Flatten a (redacted) config object down to `{dottedPath: leafValue}`
60
+ * entries. A plain object descends; an array or scalar is a leaf — matching
61
+ * `deepMergeConfig`'s own "objects merge, arrays replace wholesale" rule, so
62
+ * an array difference reports as one row rather than per-index noise.
63
+ */
64
+ function flattenConfigLeaves(value, prefix, out) {
65
+ if (isRecord(value) && Object.keys(value).length > 0) {
66
+ for (const [key, child] of Object.entries(value))
67
+ flattenConfigLeaves(child, [...prefix, key], out);
68
+ return;
69
+ }
70
+ out.set(prefix.join("."), value);
71
+ }
72
+ /**
73
+ * Diff two (already redacted) effective config objects into sorted
74
+ * `{path, local, other}` rows for every leaf that differs — including a leaf
75
+ * present on only one side (the other's value reads `undefined`).
76
+ */
77
+ function diffConfigs(local, other) {
78
+ const localLeaves = new Map();
79
+ const otherLeaves = new Map();
80
+ flattenConfigLeaves(local, [], localLeaves);
81
+ flattenConfigLeaves(other, [], otherLeaves);
82
+ const paths = new Set([...localLeaves.keys(), ...otherLeaves.keys()]);
83
+ const rows = [];
84
+ for (const path of paths) {
85
+ const localValue = localLeaves.get(path);
86
+ const otherValue = otherLeaves.get(path);
87
+ if (!isDeepStrictEqual(localValue, otherValue))
88
+ rows.push({ path, local: localValue, other: otherValue });
89
+ }
90
+ rows.sort((a, b) => a.path.localeCompare(b.path));
91
+ return rows;
92
+ }
93
+ /**
94
+ * `akm config diff <path|bundle//path>`: the current effective config
95
+ * (this instance's `extends` already applied) against another config file or
96
+ * bundle-relative file (loaded through the same loader, its own `extends`
97
+ * honoured), secrets redacted on both sides before comparison so a differing
98
+ * secret never round-trips into the diff.
99
+ */
100
+ export function akmConfigDiff(ref) {
101
+ const current = loadConfig();
102
+ const { text, resolvedPath } = resolveConfigRefSource(ref, current, getConfigPath());
103
+ const other = parseAndValidateConfigText(text, resolvedPath);
104
+ const rows = diffConfigs(redactConfigValue(current), redactConfigValue(other));
105
+ return { rows };
106
+ }
56
107
  // ── `akm config` command surface ────────────────────────────────────────────
57
108
  // Extracted verbatim from src/cli.ts (WS6). The `main.subCommands.config` key
58
109
  // and every config subcommand's args/output shape are byte-identical. Leaf
@@ -105,9 +156,16 @@ export const configCommand = defineGroupCommand({
105
156
  meta: { name: "get", description: "Get a configuration value by key" },
106
157
  args: {
107
158
  key: { type: "positional", required: true, description: "Config key (for example: embedding, defaultBundle)" },
159
+ "show-source": {
160
+ type: "boolean",
161
+ description: 'Wrap the value as { value, source }, where source is "local", "extends:<ref>" (the nearest ' +
162
+ 'extends chain member that sets it), or "default".',
163
+ default: false,
164
+ },
108
165
  },
109
166
  run({ args }) {
110
- output("config", getConfigValue(loadConfig(), args.key));
167
+ const value = getConfigValue(loadConfig(), args.key);
168
+ output("config", args["show-source"] ? { value, source: getConfigValueSource(args.key) } : value);
111
169
  },
112
170
  }),
113
171
  set: defineJsonCommand({
@@ -152,6 +210,14 @@ export const configCommand = defineGroupCommand({
152
210
  },
153
211
  },
154
212
  run({ args }) {
213
+ // A key only an `extends` base supplies has nothing local to remove:
214
+ // `unsetConfigValue` would silently no-op and the value comes right
215
+ // back on the next load. Refuse before mutating rather than pretend
216
+ // it worked.
217
+ const source = getConfigValueSource(args.key);
218
+ if (source.startsWith("extends:")) {
219
+ throw new UsageError(`Config key "${args.key}" is inherited from ${source} and cannot be unset here.`, "TARGET_NOT_UPDATABLE", `Override it locally with "akm config set ${args.key} <value>", or edit the base file directly.`);
220
+ }
155
221
  const result = mutateConfig((current) => unsetConfigValue(current, args.key), { absentNoop: true });
156
222
  const updated = result.config;
157
223
  if (!args.silent) {
@@ -159,6 +225,22 @@ export const configCommand = defineGroupCommand({
159
225
  }
160
226
  },
161
227
  }),
228
+ diff: defineJsonCommand({
229
+ meta: {
230
+ name: "diff",
231
+ description: "Show effective-config differences against another config file or bundle-relative file, secrets redacted",
232
+ },
233
+ args: {
234
+ ref: {
235
+ type: "positional",
236
+ required: true,
237
+ description: "Other config: a file path or bundle//path (relative to the bundle's content root)",
238
+ },
239
+ },
240
+ run({ args }) {
241
+ output("config-diff", akmConfigDiff(args.ref));
242
+ },
243
+ }),
162
244
  },
163
245
  // The bare `akm config` invocation (and `akm config --list`) dumps the
164
246
  // current config. defineGroupCommand short-circuits this body when a
@@ -22,52 +22,11 @@ import path from "node:path";
22
22
  import { getParsedInvocation } from "../../cli/invocation.js";
23
23
  import { getStringArg } from "../../cli/parse-args.js";
24
24
  import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.js";
25
- import { deriveCanonicalAssetName } from "../../core/asset/asset-placement.js";
26
25
  import { writeFileAtomic } from "../../core/common.js";
27
- import { loadConfig } from "../../core/config/config.js";
28
- import { makeEnvRef, resolveEnvPath, resolveEnvWriteTarget, withEnvSecretWrite } from "../../core/env-secret-ref.js";
26
+ import { listEnvsRecursive, makeEnvRef, resolveEnvPath, resolveEnvWriteTarget, sensitiveMarkerPath, withEnvSecretWrite, } from "../../core/env-secret-ref.js";
29
27
  import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
30
- import { resolveSourceEntries } from "../../indexer/search/search-source.js";
31
28
  import { readStdin } from "../../runtime.js";
32
29
  import { buildChildEnv } from "./child-env.js";
33
- import { sensitiveMarkerPath } from "./marker-path.js";
34
- /**
35
- * Walk each stash's env files and return one entry per `.env` file, using the
36
- * env asset spec's canonical-name logic (e.g. `env/team/prod.env` →
37
- * `env/team/prod`, `env/team/.env` → `env/team/default`).
38
- */
39
- function listEnvsRecursive(listKeysFn) {
40
- const result = [];
41
- for (const source of resolveSourceEntries(undefined, loadConfig())) {
42
- const root = path.join(source.path, "env");
43
- if (!fs.existsSync(root))
44
- continue;
45
- const walk = (dir) => {
46
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
47
- const full = path.join(dir, entry.name);
48
- if (entry.isDirectory()) {
49
- walk(full);
50
- continue;
51
- }
52
- if (!entry.isFile())
53
- continue;
54
- if (entry.name !== ".env" && !entry.name.endsWith(".env"))
55
- continue;
56
- const canonical = deriveCanonicalAssetName("env", root, full);
57
- if (!canonical)
58
- continue;
59
- // Skip sensitive envs: a sibling .sensitive marker file suppresses listing.
60
- const markerPath = sensitiveMarkerPath(full, "env");
61
- if (fs.existsSync(markerPath))
62
- continue;
63
- const { keys } = listKeysFn(full);
64
- result.push({ ref: makeEnvRef(canonical, source), path: full, keys });
65
- }
66
- };
67
- walk(root);
68
- }
69
- return result;
70
- }
71
30
  const envListCommand = defineJsonCommand({
72
31
  meta: { name: "list", description: "List all env files across all bundles with their key names (no values)" },
73
32
  async run() {
@@ -49,7 +49,7 @@ import fs from "node:fs";
49
49
  import path from "node:path";
50
50
  import dotenv from "dotenv";
51
51
  import { scanEnvKeyNames, writeFileAtomic } from "../../core/common.js";
52
- import { sensitiveMarkerPath } from "./marker-path.js";
52
+ import { sensitiveMarkerPath } from "../../core/sensitive-marker-path.js";
53
53
  export { scanEnvKeyNames };
54
54
  /**
55
55
  * Read and return ONLY non-secret metadata: key names.
@@ -35,14 +35,13 @@ import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.
35
35
  import { decideDangerousEnvInjection } from "../../core/activation-policy.js";
36
36
  import { deriveCanonicalAssetName } from "../../core/asset/asset-placement.js";
37
37
  import { loadConfig } from "../../core/config/config.js";
38
- import { makeSecretRef, resolveSecretPath, resolveSecretWriteTarget, withEnvSecretWrite, } from "../../core/env-secret-ref.js";
38
+ import { makeSecretRef, resolveSecretPath, resolveSecretWriteTarget, sensitiveMarkerPath, withEnvSecretWrite, } from "../../core/env-secret-ref.js";
39
39
  import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
40
40
  import { appendEvent } from "../../core/events.js";
41
41
  import { warn } from "../../core/warn.js";
42
42
  import { resolveSourceEntries } from "../../indexer/search/search-source.js";
43
43
  import { readStdin } from "../../runtime.js";
44
44
  import { buildChildEnv } from "./child-env.js";
45
- import { sensitiveMarkerPath } from "./marker-path.js";
46
45
  function parseKeyListFlag(raw) {
47
46
  if (raw === undefined)
48
47
  return undefined;