akm-cli 0.9.0 → 0.9.1-beta.2

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 (140) hide show
  1. package/CHANGELOG.md +724 -0
  2. package/README.md +28 -63
  3. package/STABILITY.md +4 -2
  4. package/dist/cli/parse-args.js +7 -1
  5. package/dist/commands/agent/contribute-cli.js +1 -1
  6. package/dist/commands/env/child-env.js +14 -0
  7. package/dist/commands/feedback-cli.js +7 -1
  8. package/dist/commands/health/llm-usage.js +2 -1
  9. package/dist/commands/health/surfaces.js +4 -77
  10. package/dist/commands/health.js +65 -11
  11. package/dist/commands/improve/distill/quality-gate.js +6 -1
  12. package/dist/commands/improve/eligibility.js +7 -1
  13. package/dist/commands/improve/eval-cases.js +2 -0
  14. package/dist/commands/improve/improve.js +126 -10
  15. package/dist/commands/improve/locks.js +7 -0
  16. package/dist/commands/improve/memory/memory-improve.js +9 -0
  17. package/dist/commands/improve/run-context.js +5 -0
  18. package/dist/commands/improve/session-asset.js +4 -0
  19. package/dist/commands/lint/base-linter.js +31 -7
  20. package/dist/commands/lint/index.js +205 -51
  21. package/dist/commands/lint/types.js +22 -1
  22. package/dist/commands/proposal/repository.js +17 -1
  23. package/dist/commands/sources/add-cli.js +8 -2
  24. package/dist/commands/sources/info.js +12 -2
  25. package/dist/commands/sources/installed-stashes.js +6 -1
  26. package/dist/commands/sources/migration-help.js +12 -3
  27. package/dist/commands/sources/self-update.js +9 -1
  28. package/dist/commands/tasks/tasks.js +8 -2
  29. package/dist/commands/workflow-cli.js +17 -11
  30. package/dist/core/abort-deadline.js +28 -0
  31. package/dist/core/adapter/adapters/agent-skills-adapter.js +83 -5
  32. package/dist/core/adapter/adapters/akm-adapter.js +13 -10
  33. package/dist/core/adapter/adapters/akm-lint.js +78 -22
  34. package/dist/core/adapter/adapters/akm-task-adapter.js +43 -20
  35. package/dist/core/adapter/adapters/dotenv-adapter.js +21 -0
  36. package/dist/core/adapter/adapters/tool-dir-shared.js +5 -3
  37. package/dist/core/asset/frontmatter.js +10 -1
  38. package/dist/core/common.js +147 -9
  39. package/dist/core/concurrent.js +32 -0
  40. package/dist/core/config/config-io.js +5 -45
  41. package/dist/core/config/schema/engines.js +14 -3
  42. package/dist/core/config/schema/workflow.js +11 -0
  43. package/dist/core/errors.js +25 -0
  44. package/dist/core/events.js +30 -24
  45. package/dist/core/extra-params.js +11 -0
  46. package/dist/core/file-lock.js +7 -1
  47. package/dist/core/fs-txn.js +15 -2
  48. package/dist/core/improve-result.js +5 -0
  49. package/dist/core/json-schema.js +344 -9
  50. package/dist/core/loopback.js +89 -0
  51. package/dist/core/migration-operation.js +17 -2
  52. package/dist/core/path-access.js +107 -0
  53. package/dist/core/paths.js +16 -2
  54. package/dist/core/redaction.js +86 -18
  55. package/dist/core/spawn-env.js +234 -0
  56. package/dist/core/state-db-scope.js +134 -0
  57. package/dist/core/state-db.js +1 -0
  58. package/dist/core/subprocess.js +181 -37
  59. package/dist/core/write-provenance.js +85 -0
  60. package/dist/core/write-source.js +33 -2
  61. package/dist/indexer/db/graph-db.js +17 -6
  62. package/dist/indexer/ensure-index.js +10 -3
  63. package/dist/indexer/index-written-assets.js +17 -2
  64. package/dist/indexer/indexer.js +86 -21
  65. package/dist/indexer/passes/memory-inference.js +4 -0
  66. package/dist/indexer/search/db-search.js +25 -17
  67. package/dist/indexer/walk/walker.js +6 -1
  68. package/dist/integrations/agent/detect.js +13 -1
  69. package/dist/integrations/agent/engine-resolution.js +24 -11
  70. package/dist/integrations/agent/model-aliases.js +1 -1
  71. package/dist/integrations/agent/profiles.js +9 -1
  72. package/dist/integrations/agent/spawn.js +15 -87
  73. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +21 -0
  74. package/dist/integrations/lockfile.js +55 -2
  75. package/dist/llm/client.js +14 -19
  76. package/dist/llm/embedder.js +23 -3
  77. package/dist/llm/embedders/remote.js +27 -2
  78. package/dist/output/html-render.js +40 -1
  79. package/dist/output/text/lint-format.js +17 -4
  80. package/dist/runtime.js +23 -1
  81. package/dist/scripts/akm-migrate-node.js +1714 -836
  82. package/dist/scripts/akm-migrate.js +1682 -804
  83. package/dist/setup/setup.js +22 -7
  84. package/dist/sources/providers/git-install.js +25 -2
  85. package/dist/sources/providers/git-stash.js +19 -0
  86. package/dist/sources/providers/git.js +1 -1
  87. package/dist/sources/snapshot-fetchers/content-extract.js +63 -1
  88. package/dist/sources/snapshot-fetchers/website-ingest.js +126 -20
  89. package/dist/storage/database.js +71 -7
  90. package/dist/storage/engines/sqlite-migrations.js +61 -2
  91. package/dist/storage/managed-db.js +19 -0
  92. package/dist/storage/repositories/index-connection.js +39 -4
  93. package/dist/storage/repositories/index-entries-repository.js +6 -1
  94. package/dist/storage/repositories/index-meta-repository.js +11 -0
  95. package/dist/storage/repositories/index-schema.js +17 -2
  96. package/dist/storage/repositories/index-vec-repository.js +43 -5
  97. package/dist/storage/repositories/workflow-runs-repository.js +66 -13
  98. package/dist/storage/sqlite-pragmas.js +12 -1
  99. package/dist/tasks/log-redaction.js +156 -0
  100. package/dist/tasks/parser.js +82 -5
  101. package/dist/tasks/runner.js +222 -17
  102. package/dist/tasks/scheduler-invocation.js +19 -0
  103. package/dist/tasks/schema.js +86 -1
  104. package/dist/text-import-hook.mjs +1 -1
  105. package/dist/workflows/concurrency-policy.js +95 -1
  106. package/dist/workflows/exec/dispatch-redaction.js +114 -0
  107. package/dist/workflows/exec/exec-unit.js +542 -0
  108. package/dist/workflows/exec/frozen-judge.js +114 -42
  109. package/dist/workflows/exec/native-executor.js +465 -238
  110. package/dist/workflows/exec/param-secrets.js +4 -3
  111. package/dist/workflows/exec/run-workflow.js +424 -219
  112. package/dist/workflows/exec/step-work.js +506 -167
  113. package/dist/workflows/exec/unit-dispatch.js +31 -1
  114. package/dist/workflows/exec/unit-writer.js +53 -13
  115. package/dist/workflows/exec/worktree.js +454 -41
  116. package/dist/workflows/ir/compile.js +26 -2
  117. package/dist/workflows/ir/freeze.js +82 -15
  118. package/dist/workflows/ir/schema.js +105 -20
  119. package/dist/workflows/parser.js +242 -19
  120. package/dist/workflows/program/schema.js +24 -0
  121. package/dist/workflows/renderer.js +32 -4
  122. package/dist/workflows/resource-limits.js +182 -0
  123. package/dist/workflows/runtime/runs.js +146 -6
  124. package/dist/workflows/validate-summary.js +17 -2
  125. package/docs/README.md +74 -32
  126. package/docs/migration/release-notes/0.9.0.md +2 -1
  127. package/docs/migration/v0.7-to-v0.8.md +2 -1
  128. package/docs/migration/v0.8-to-v0.9.md +3 -1
  129. package/docs/reference/README.md +11 -4
  130. package/docs/reference/bundle-types.md +19 -0
  131. package/docs/reference/cli.md +105 -16
  132. package/docs/reference/configuration.md +15 -2
  133. package/docs/reference/data-and-telemetry.md +30 -10
  134. package/docs/reference/supported-formats.md +50 -0
  135. package/docs/reference/workflow-schema.md +1014 -0
  136. package/docs/reference/workflows.md +37 -633
  137. package/package.json +13 -6
  138. package/schemas/akm-config.json +18 -5
  139. package/schemas/akm-task.json +27 -5
  140. package/schemas/akm-workflow.json +92 -13
@@ -1,10 +1,57 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
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
- import { deepMergeConfig } from "../../core/config/deep-merge.js";
4
+ /**
5
+ * The gate judge built from a frozen v3 engine catalog.
6
+ *
7
+ * Two contracts this module owns, both of which the rest of the engine already
8
+ * enforces for ordinary units and neither of which the judge may opt out of:
9
+ *
10
+ * 1. **Redaction.** A judge response IS journaled — `journalGateEvaluationFinish`
11
+ * (exec/step-work.ts) writes the parsed verdict into the gate row's
12
+ * `result_json`, and a judge failure's message becomes the blocked step's
13
+ * notes. So the judge outcome goes through the SAME scrub every unit outcome
14
+ * goes through: {@link collectWorkflowDispatchSensitiveValues} +
15
+ * {@link withDispatchRedaction} (exec/dispatch-redaction.ts). Nothing about
16
+ * a judge call reaches durable state before that scrub. BOTH branches below
17
+ * state it that way — the agent branch wrapping the injected dispatcher, the
18
+ * llm branch wrapping its own chatCompletion call — so a change to that one
19
+ * contract cannot reach only one of the two judge paths.
20
+ *
21
+ * 2. **Identity.** The dispatch request carries the REAL run/step and the gate's
22
+ * real node/unit ids — the same ids `journalGateEvaluationStart/Finish` write
23
+ * (`<stepId>.gate` / `<stepId>.gate:l<loop>`) — so per-dispatch telemetry and
24
+ * harness-side correlation describe the same thing the gate row describes.
25
+ * The identity is threaded in from the caller that writes the row
26
+ * ({@link SummaryJudge}'s `identity` argument); it is never synthesized here.
27
+ *
28
+ * A judge dispatch carries NO `env` bindings: a gate judge is an
29
+ * {@link IrInvocation} (`IrGateNode.judge`), which has no `env` key, so there is
30
+ * nothing authored to thread — and a step's unit `env` is scoped to the WORK,
31
+ * not to the verifier. Redaction is unaffected: the sensitive-value set below
32
+ * still covers the judge engine's credential and unsafe passthrough values.
33
+ *
34
+ * @module workflows/exec/frozen-judge
35
+ */
5
36
  import { ConfigError } from "../../core/errors.js";
37
+ import { collectWorkflowDispatchSensitiveValues, withDispatchRedaction } from "./dispatch-redaction.js";
38
+ import { materializeFrozenLlm } from "./unit-dispatch.js";
39
+ /** The gate's node id — identical to what `journalGateEvaluationStart` writes. */
40
+ export function gateNodeId(stepId) {
41
+ return `${stepId}.gate`;
42
+ }
43
+ /**
44
+ * Identity for one judge dispatch: the journaling caller's exact row identity
45
+ * when it supplied one, else the owning run/step with the gate's node id as the
46
+ * unit id. Either way the request names the REAL run — never a synthetic
47
+ * `"gate"` placeholder, which made every judge dispatch indistinguishable from
48
+ * every other one.
49
+ */
50
+ function dispatchIdentity(owner, identity) {
51
+ return identity ?? { ...owner, unitId: gateNodeId(owner.stepId) };
52
+ }
6
53
  /** Build a gate judge from a v3 catalog entry without consulting live config. */
7
- export function frozenSummaryJudge(plan, invocation, signal, dispatcher) {
54
+ export function frozenSummaryJudge(plan, invocation, signal, dispatcher, owner) {
8
55
  if (!invocation)
9
56
  return null;
10
57
  const engine = plan.execution?.engines[invocation.engine];
@@ -14,60 +61,85 @@ export function frozenSummaryJudge(plan, invocation, signal, dispatcher) {
14
61
  if (!dispatcher) {
15
62
  throw new ConfigError(`Frozen agent gate engine "${invocation.engine}" has no unit dispatcher.`, "INVALID_CONFIG_FILE");
16
63
  }
17
- return async ({ system, user }) => {
18
- const fallbackEngine = engine.fallbackLlmEngine ? plan.execution.engines[engine.fallbackLlmEngine] : undefined;
19
- const result = await dispatcher({
20
- runId: "gate",
21
- stepId: "gate",
22
- unitId: "gate",
23
- nodeId: "gate",
64
+ const fallbackEngine = engine.fallbackLlmEngine ? plan.execution.engines[engine.fallbackLlmEngine] : undefined;
65
+ const fallback = fallbackEngine?.kind === "llm" ? fallbackEngine : undefined;
66
+ // Scrub at the seam: every outcome this judge's dispatcher returns — and
67
+ // every error it throws — is redacted BEFORE the verdict (or the failure
68
+ // message) can reach the gate row / the blocked step's notes. Identical
69
+ // contract to the llm branch below and to the unit path, including the
70
+ // failureReason downgrade when redaction altered it.
71
+ const dispatch = withDispatchRedaction(dispatcher);
72
+ return async ({ system, user }, identity) => {
73
+ const id = dispatchIdentity(owner, identity);
74
+ // Collected per dispatch, not once per judge: the engine PAIR is fixed at
75
+ // build time but its secrets are not — they are read from `process.env`,
76
+ // which the dispatch itself re-reads, so a build-time set would miss a
77
+ // credential set or rotated between the two reads. Same collector the unit
78
+ // path uses; see the module doc on why `env` is absent here but the
79
+ // credential/passthrough values are still collected.
80
+ const sensitiveValues = collectWorkflowDispatchSensitiveValues({ engine, ...(fallback ? { fallbackEngine: fallback } : {}) }, undefined);
81
+ const outcome = await dispatch({
82
+ runId: id.runId,
83
+ stepId: id.stepId,
84
+ unitId: id.unitId,
85
+ nodeId: gateNodeId(id.stepId),
24
86
  prompt: user,
25
87
  systemPrompt: system,
26
88
  engine,
27
- ...(fallbackEngine?.kind === "llm" ? { fallbackEngine } : {}),
89
+ ...(fallback ? { fallbackEngine: fallback } : {}),
28
90
  invocation,
29
91
  timeoutMs: invocation.timeoutMs,
92
+ ...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
30
93
  ...(signal ? { signal } : {}),
31
94
  });
32
- if (!result.ok) {
33
- throw new Error(result.error || `Verification engine "${invocation.engine}" failed.`);
95
+ if (!outcome.ok) {
96
+ throw new Error(outcome.error || `Verification engine "${invocation.engine}" failed.`);
34
97
  }
35
- return result.text;
98
+ return outcome.text ?? "";
36
99
  };
37
100
  }
38
- return async ({ system, user }) => {
101
+ // The llm judge's ONE call, shaped as a {@link UnitDispatcher} so this branch
102
+ // states its redaction through the SAME {@link withDispatchRedaction} contract
103
+ // the agent branch above uses — including the throw, which a transport error
104
+ // takes and which becomes the blocked step's notes (`judgeFailure` in
105
+ // step-work.ts).
106
+ //
107
+ // Inline chatCompletion rather than the injected unit dispatcher ON PURPOSE:
108
+ // the manual completion path (`runtime/runs.ts`) builds an llm judge with no
109
+ // dispatcher, and a static runs → native-executor edge would close an import
110
+ // cycle. The materialization itself is the shared {@link materializeFrozenLlm},
111
+ // so the two llm dispatch paths cannot drift.
112
+ const dispatch = withDispatchRedaction(async (request) => {
39
113
  const { chatCompletion } = await import("../../llm/client.js");
40
- return chatCompletion(materialize(engine, invocation), [
41
- { role: "system", content: system },
42
- { role: "user", content: user },
114
+ const text = await chatCompletion(materializeFrozenLlm(engine, invocation), [
115
+ { role: "system", content: request.systemPrompt ?? "" },
116
+ { role: "user", content: request.prompt },
43
117
  ], {
118
+ timeoutMs: request.timeoutMs,
119
+ ...(signal ? { signal } : {}),
120
+ });
121
+ return { ok: true, text };
122
+ });
123
+ return async ({ system, user }, identity) => {
124
+ const id = dispatchIdentity(owner, identity);
125
+ // An llm judge's only secret is its own credential, which
126
+ // `materializeFrozenLlm` resolves out of `process.env` inside the dispatch
127
+ // below — so the set is collected here, per dispatch, and cannot predate the
128
+ // value the call actually authenticates with.
129
+ const sensitiveValues = collectWorkflowDispatchSensitiveValues({ engine }, undefined);
130
+ const outcome = await dispatch({
131
+ runId: id.runId,
132
+ stepId: id.stepId,
133
+ unitId: id.unitId,
134
+ nodeId: gateNodeId(id.stepId),
135
+ prompt: user,
136
+ systemPrompt: system,
137
+ engine,
138
+ invocation,
44
139
  timeoutMs: invocation.timeoutMs,
140
+ ...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
45
141
  ...(signal ? { signal } : {}),
46
142
  });
143
+ return outcome.text;
47
144
  };
48
145
  }
49
- function materialize(engine, invocation) {
50
- let apiKey;
51
- for (const name of engine.credential?.names ?? []) {
52
- const value = process.env[name]?.trim();
53
- if (value) {
54
- apiKey = value;
55
- break;
56
- }
57
- }
58
- if (engine.credential?.required && !apiKey)
59
- throw new ConfigError(`Required engine credential ${engine.credential.names[0]} is not set.`, "INVALID_CONFIG_FILE");
60
- const base = {
61
- provider: engine.provider,
62
- endpoint: engine.endpoint,
63
- model: invocation.model ?? engine.model,
64
- ...(engine.temperature !== undefined ? { temperature: engine.temperature } : {}),
65
- ...(engine.maxTokens !== undefined ? { maxTokens: engine.maxTokens } : {}),
66
- ...(engine.supportsJsonSchema !== undefined ? { supportsJsonSchema: engine.supportsJsonSchema } : {}),
67
- ...(engine.extraParams ? { extraParams: engine.extraParams } : {}),
68
- ...(engine.contextLength !== undefined ? { contextLength: engine.contextLength } : {}),
69
- ...(engine.enableThinking !== undefined ? { enableThinking: engine.enableThinking } : {}),
70
- ...(apiKey ? { apiKey } : {}),
71
- };
72
- return (invocation.llm ? deepMergeConfig(base, invocation.llm) : base);
73
- }