akm-cli 0.9.0-beta.5 → 0.9.0-beta.51
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/CHANGELOG.md +711 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +6 -2
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +38 -10
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +27 -11
- package/dist/commands/agent/agent-dispatch.js +2 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +17 -4
- package/dist/commands/config-cli.js +18 -2
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +33 -26
- package/dist/commands/env/secret-cli.js +36 -22
- package/dist/commands/feedback-cli.js +15 -6
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/checks.js +49 -1
- package/dist/commands/health/html-report.js +422 -80
- package/dist/commands/health.js +386 -9
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +81 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +635 -660
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill.js +159 -69
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +124 -2
- package/dist/commands/improve/extract-prompt.js +39 -2
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +389 -40
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/homeostatic.js +467 -0
- package/dist/commands/improve/improve-auto-accept.js +138 -7
- package/dist/commands/improve/improve-cli.js +36 -61
- package/dist/commands/improve/improve-profiles.js +14 -0
- package/dist/commands/improve/improve-result-file.js +14 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +485 -2498
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1083 -0
- package/dist/commands/improve/memory/memory-contradiction-detect.js +23 -28
- package/dist/commands/improve/outcome-loop.js +256 -0
- package/dist/commands/improve/preparation.js +1966 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +418 -0
- package/dist/commands/improve/recombine.js +850 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +183 -40
- package/dist/commands/improve/salience.js +438 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/proposal/drain-policies.js +5 -0
- package/dist/commands/proposal/drain.js +43 -50
- package/dist/commands/proposal/proposal-cli.js +21 -31
- package/dist/commands/proposal/proposal.js +5 -0
- package/dist/commands/proposal/propose.js +7 -2
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +189 -63
- package/dist/commands/read/curate.js +414 -94
- package/dist/commands/read/knowledge.js +6 -3
- package/dist/commands/read/search-cli.js +9 -4
- package/dist/commands/read/search.js +10 -6
- package/dist/commands/read/show.js +86 -7
- package/dist/commands/sources/init.js +49 -17
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +43 -45
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/stash-cli.js +28 -40
- package/dist/commands/sources/stash-skeleton.js +23 -8
- package/dist/commands/tasks/tasks-cli.js +19 -27
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +21 -35
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +18 -2
- package/dist/core/asset/frontmatter.js +166 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +0 -5
- package/dist/core/config/config-migration.js +12 -11
- package/dist/core/config/config-schema.js +340 -56
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +28 -7
- package/dist/core/events.js +3 -7
- package/dist/core/improve-types.js +11 -8
- package/dist/core/logs-db.js +10 -66
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +3 -0
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +714 -0
- package/dist/core/state-db.js +525 -474
- package/dist/indexer/db/db.js +439 -247
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/ensure-index.js +152 -17
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +218 -4
- package/dist/indexer/index-writer-lock.js +99 -0
- package/dist/indexer/indexer.js +123 -221
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/staleness-detect.js +2 -5
- package/dist/indexer/search/db-search.js +19 -6
- package/dist/indexer/search/ranking-contributors.js +22 -0
- package/dist/indexer/search/ranking.js +4 -0
- package/dist/indexer/search/search-source.js +17 -18
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/integrations/agent/config.js +6 -53
- package/dist/integrations/agent/index.js +2 -18
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -2
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/client.js +45 -15
- package/dist/llm/embedder.js +42 -3
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +66 -2
- package/dist/llm/feature-gate.js +8 -4
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +74 -2
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/text/helpers.js +16 -1
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +22 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2617 -1961
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +759 -510
- package/dist/setup/setup.js +29 -8
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/registry-cache.js +92 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +5 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +37 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +1 -117
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/data-and-telemetry.md +3 -2
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +13 -11
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
|
@@ -2,6 +2,7 @@
|
|
|
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 fs from "node:fs";
|
|
5
|
+
import { parseWorkflow } from "../../workflows/parser.js";
|
|
5
6
|
import { BaseLinter } from "./base-linter.js";
|
|
6
7
|
const PLACEHOLDER_STRINGS = ["Describe what this workflow accomplishes", "Example Workflow"];
|
|
7
8
|
/**
|
|
@@ -32,7 +33,7 @@ export class WorkflowLinter extends BaseLinter {
|
|
|
32
33
|
file: ctx.relPath,
|
|
33
34
|
issue: "placeholder-stub",
|
|
34
35
|
detail: `could not delete: ${e instanceof Error ? e.message : String(e)}`,
|
|
35
|
-
fixed:
|
|
36
|
+
fixed: "failed",
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
return issues;
|
|
@@ -44,6 +45,30 @@ export class WorkflowLinter extends BaseLinter {
|
|
|
44
45
|
fixed: false,
|
|
45
46
|
});
|
|
46
47
|
}
|
|
48
|
+
const isReadOnly = ctx.filePath.includes("/.cache/") || ctx.filePath.includes("/registry/");
|
|
49
|
+
if (!isReadOnly) {
|
|
50
|
+
try {
|
|
51
|
+
const result = parseWorkflow(ctx.raw, { path: ctx.filePath });
|
|
52
|
+
if (!result.ok) {
|
|
53
|
+
for (const err of result.errors ?? []) {
|
|
54
|
+
issues.push({
|
|
55
|
+
file: ctx.relPath,
|
|
56
|
+
issue: "invalid-workflow-structure",
|
|
57
|
+
detail: err.message ?? String(err),
|
|
58
|
+
fixed: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
issues.push({
|
|
65
|
+
file: ctx.relPath,
|
|
66
|
+
issue: "invalid-workflow-structure",
|
|
67
|
+
detail: `workflow parser error: ${e instanceof Error ? e.message : String(e)}`,
|
|
68
|
+
fixed: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
47
72
|
return issues;
|
|
48
73
|
}
|
|
49
74
|
#checkPlaceholderStub(body) {
|
|
@@ -45,6 +45,10 @@ export const PERSONAL_STASH = {
|
|
|
45
45
|
{ generator: "reflect", maxDiffLines: 80 },
|
|
46
46
|
// Consolidate within the diff band; mid-band lands in `defer` below.
|
|
47
47
|
{ generator: "consolidate", maxDiffLines: 200 },
|
|
48
|
+
// Recombine: accept only confirmed type:lesson proposals (promoted by the
|
|
49
|
+
// recombine confidence gate) within the diff band. type:hypothesis proposals
|
|
50
|
+
// have no matching rule here and stay pending for manual review.
|
|
51
|
+
{ generator: "recombine", requireType: "lesson", maxDiffLines: 200 },
|
|
48
52
|
],
|
|
49
53
|
rejectEmpty: true,
|
|
50
54
|
// Mid-band consolidate, distill duplicates, and contradiction escalations are
|
|
@@ -83,6 +87,7 @@ const DrainAcceptRuleSchema = z
|
|
|
83
87
|
generator: GeneratorSchema,
|
|
84
88
|
maxDiffLines: z.number().int().positive().optional(),
|
|
85
89
|
minContentLines: z.number().int().nonnegative().optional(),
|
|
90
|
+
requireType: z.string().optional(),
|
|
86
91
|
})
|
|
87
92
|
.strict();
|
|
88
93
|
const DrainPolicySchema = z
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the engine behind `akm proposal drain` and (later) the `triage` improve
|
|
10
10
|
* pre-pass.
|
|
11
11
|
*
|
|
12
|
-
* Design (see docs/
|
|
12
|
+
* Design (see docs/archive/proposal-triage-implementation-plan.md):
|
|
13
13
|
* - Reuses `listProposals` (no source filter — generator filtering is
|
|
14
14
|
* in-memory) and the `akmProposalAccept` / `akmProposalReject` wrappers from
|
|
15
15
|
* `proposal.ts` so the standard `promoted` / `rejected` events are emitted.
|
|
@@ -36,14 +36,12 @@
|
|
|
36
36
|
*/
|
|
37
37
|
import fs from "node:fs";
|
|
38
38
|
import path from "node:path";
|
|
39
|
-
import { assertNever } from "../../core/assert.js";
|
|
40
39
|
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
41
40
|
import { resolveAssetPathFromName, TYPE_DIRS } from "../../core/asset/asset-spec.js";
|
|
42
41
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
43
42
|
import { appendEvent } from "../../core/events.js";
|
|
44
43
|
import { info, warn } from "../../core/warn.js";
|
|
45
|
-
import {
|
|
46
|
-
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
44
|
+
import { executeRunner } from "../../integrations/agent/runner-dispatch.js";
|
|
47
45
|
import { chatCompletion, stripJsonFences } from "../../llm/client.js";
|
|
48
46
|
import { akmProposalAccept, akmProposalReject } from "./proposal.js";
|
|
49
47
|
import { listProposals, recordGateDecision } from "./validators/proposals.js";
|
|
@@ -80,7 +78,16 @@ export function classifyProposal(proposal, policy, maxDiffLines) {
|
|
|
80
78
|
if (policy.rejectEmpty && isEmptyDiff(proposal)) {
|
|
81
79
|
return { verdict: "reject", reason: "empty diff", gate: { reason: "empty-diff" } };
|
|
82
80
|
}
|
|
83
|
-
const rule = policy.accept.find((r) =>
|
|
81
|
+
const rule = policy.accept.find((r) => {
|
|
82
|
+
if (r.generator !== proposal.source)
|
|
83
|
+
return false;
|
|
84
|
+
if (r.requireType !== undefined) {
|
|
85
|
+
const fm = parseFrontmatter(proposal.payload.content ?? "").data;
|
|
86
|
+
if (typeof fm.type !== "string" || fm.type !== r.requireType)
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
});
|
|
84
91
|
if (rule) {
|
|
85
92
|
const lines = contentLineCount(content);
|
|
86
93
|
const body = contentBodyLineCount(content);
|
|
@@ -200,59 +207,38 @@ export function parseJudgmentVerdict(raw) {
|
|
|
200
207
|
return { decision, reason: typeof reason === "string" ? reason : "" };
|
|
201
208
|
}
|
|
202
209
|
/**
|
|
203
|
-
* Dispatch a single judgment prompt to the resolved runner
|
|
204
|
-
*
|
|
205
|
-
*
|
|
210
|
+
* Dispatch a single judgment prompt to the resolved runner via the unified
|
|
211
|
+
* {@link executeRunner} seam (X3). The `llm` arm is drain-specific (wraps
|
|
212
|
+
* `chatCompletion` — no filesystem) so it is supplied as the `llm` handler; the
|
|
213
|
+
* byte-identical `agent` / `sdk` arms route to the default profile runners (or
|
|
214
|
+
* the injected {@link JudgmentSeams} test fakes). A failed spawn warns and
|
|
215
|
+
* yields `null`, matching the prior per-arm behavior.
|
|
206
216
|
*/
|
|
207
217
|
async function dispatchJudgment(runner, prompt, seams) {
|
|
208
|
-
|
|
209
|
-
switch (runner.kind) {
|
|
210
|
-
case "llm": {
|
|
211
|
-
const messages = [{ role: "user", content: prompt }];
|
|
212
|
-
raw = seams.chat
|
|
213
|
-
? await seams.chat(runner, messages)
|
|
214
|
-
: await chatCompletion(runner.connection, messages, {
|
|
215
|
-
...(runner.timeoutMs !== undefined ? { timeoutMs: runner.timeoutMs } : {}),
|
|
216
|
-
});
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
case "agent": {
|
|
220
|
-
const stdout = await runProfileJudgment(seams.runAgentFn ?? runAgent, runner.profile, prompt, "agent", runner.timeoutMs);
|
|
221
|
-
if (stdout === null)
|
|
222
|
-
return null;
|
|
223
|
-
raw = stdout;
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "sdk": {
|
|
227
|
-
const stdout = await runProfileJudgment(seams.runSdkFn ?? runOpencodeSdk, runner.profile, prompt, "sdk", runner.timeoutMs);
|
|
228
|
-
if (stdout === null)
|
|
229
|
-
return null;
|
|
230
|
-
raw = stdout;
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
default:
|
|
234
|
-
// Exhaustiveness arm (H1): a 4th RunnerSpec kind becomes a compile error
|
|
235
|
-
// here instead of leaving `raw` undefined at runtime.
|
|
236
|
-
return assertNever(runner);
|
|
237
|
-
}
|
|
238
|
-
return parseJudgmentVerdict(raw);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Shared spawn-runner dispatch for the byte-identical `agent` / `sdk` arms: run
|
|
242
|
-
* the profile-based runner, log a labelled warning on failure, and return the
|
|
243
|
-
* captured stdout (or `null` on failure). `label` only changes the warn prefix.
|
|
244
|
-
*/
|
|
245
|
-
async function runProfileJudgment(run, profile, prompt, label, timeoutMs) {
|
|
246
|
-
const result = await run(profile, prompt, {
|
|
218
|
+
const runOptions = {
|
|
247
219
|
stdio: "captured",
|
|
248
220
|
parseOutput: "text",
|
|
249
|
-
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
221
|
+
...(runner.timeoutMs !== undefined ? { timeoutMs: runner.timeoutMs } : {}),
|
|
222
|
+
};
|
|
223
|
+
const result = await executeRunner(runner, prompt, runOptions, {
|
|
224
|
+
llm: async (spec, p) => {
|
|
225
|
+
const messages = [{ role: "user", content: p }];
|
|
226
|
+
const raw = seams.chat
|
|
227
|
+
? await seams.chat(spec, messages)
|
|
228
|
+
: await chatCompletion(spec.connection, messages, {
|
|
229
|
+
...(spec.timeoutMs !== undefined ? { timeoutMs: spec.timeoutMs } : {}),
|
|
230
|
+
});
|
|
231
|
+
// chatCompletion has no failure envelope — a returned string is success.
|
|
232
|
+
return { ok: true, exitCode: 0, stdout: raw, stderr: "", durationMs: 0 };
|
|
233
|
+
},
|
|
234
|
+
...(seams.runAgentFn ? { runAgent: seams.runAgentFn } : {}),
|
|
235
|
+
...(seams.runSdkFn ? { runSdk: seams.runSdkFn } : {}),
|
|
250
236
|
});
|
|
251
237
|
if (!result.ok) {
|
|
252
|
-
warn(`[triage] judgment ${
|
|
238
|
+
warn(`[triage] judgment ${runner.kind} failed: ${result.error ?? result.reason ?? "unknown error"}`);
|
|
253
239
|
return null;
|
|
254
240
|
}
|
|
255
|
-
return result.stdout;
|
|
241
|
+
return parseJudgmentVerdict(result.stdout);
|
|
256
242
|
}
|
|
257
243
|
/**
|
|
258
244
|
* Run the judgment tier over the deferred items. The runner only *judges*; the
|
|
@@ -361,6 +347,13 @@ export async function drainProposals(opts, promoteFn = akmProposalAccept, reject
|
|
|
361
347
|
// — these are re-stamped `no-judge-configured` when no runner resolves them.
|
|
362
348
|
const needsJudge = new Set();
|
|
363
349
|
for (const proposal of pending) {
|
|
350
|
+
// Do NOT reclassify a proposal that was already conclusively stamped
|
|
351
|
+
// `auto-rejected` by a prior gate run (e.g. the improve confidence gate).
|
|
352
|
+
// Overwriting an authoritative rejection with `auto-accepted` would corrupt
|
|
353
|
+
// the audit trail and silently promote content the gate explicitly rejected.
|
|
354
|
+
// Such proposals remain pending for manual review (or TTL expiry).
|
|
355
|
+
if (proposal.gateDecision?.outcome === "auto-rejected")
|
|
356
|
+
continue;
|
|
364
357
|
const decision = classifyProposal(proposal, opts.policy, opts.maxDiffLines);
|
|
365
358
|
if (decision === null)
|
|
366
359
|
continue;
|
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
* and emits the same JSON envelope (stdout/stderr/exit-code) as the inline
|
|
10
10
|
* `runWithJsonErrors` form it replaces.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
|
|
12
|
+
import { parsePositiveIntFlag } from "../../cli/parse-args.js";
|
|
13
|
+
import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.js";
|
|
15
14
|
import { resolveStashDir } from "../../core/common.js";
|
|
16
15
|
import { loadConfig } from "../../core/config/config.js";
|
|
17
16
|
import { UsageError } from "../../core/errors.js";
|
|
@@ -448,19 +447,7 @@ const proposalDrainCommand = defineJsonCommand({
|
|
|
448
447
|
// (`proposals`/`accept`/`reject`/`diff`/`revert`) remain as deprecated aliases
|
|
449
448
|
// that warn to stderr and delegate to the same command bodies; they are removed
|
|
450
449
|
// in 0.9.0. Bare `akm proposal` behaves as `proposal list` (mirrors `akm env`).
|
|
451
|
-
|
|
452
|
-
// (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
|
|
453
|
-
const proposalSubCommands = {
|
|
454
|
-
list: proposalListCommand,
|
|
455
|
-
show: proposalShowCommand,
|
|
456
|
-
diff: proposalDiffCommand,
|
|
457
|
-
accept: proposalAcceptCommand,
|
|
458
|
-
reject: proposalRejectCommand,
|
|
459
|
-
revert: proposalRevertCommand,
|
|
460
|
-
drain: proposalDrainCommand,
|
|
461
|
-
};
|
|
462
|
-
const PROPOSAL_SUBCOMMAND_SET = new Set(Object.keys(proposalSubCommands));
|
|
463
|
-
export const proposalCommand = defineCommand({
|
|
450
|
+
export const proposalCommand = defineGroupCommand({
|
|
464
451
|
meta: { name: "proposal", description: "Manage the proposal queue: list, show, diff, accept, reject, revert" },
|
|
465
452
|
args: {
|
|
466
453
|
status: {
|
|
@@ -470,21 +457,24 @@ export const proposalCommand = defineCommand({
|
|
|
470
457
|
ref: { type: "string", description: "Filter by asset ref (type:name)" },
|
|
471
458
|
type: { type: "string", description: "Filter by asset type" },
|
|
472
459
|
},
|
|
473
|
-
subCommands:
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
460
|
+
subCommands: {
|
|
461
|
+
list: proposalListCommand,
|
|
462
|
+
show: proposalShowCommand,
|
|
463
|
+
diff: proposalDiffCommand,
|
|
464
|
+
accept: proposalAcceptCommand,
|
|
465
|
+
reject: proposalRejectCommand,
|
|
466
|
+
revert: proposalRevertCommand,
|
|
467
|
+
drain: proposalDrainCommand,
|
|
468
|
+
},
|
|
469
|
+
// Default body fires only for bare `akm proposal [--status …]`.
|
|
470
|
+
defaultRun({ args }) {
|
|
471
|
+
const status = parseProposalStatus(args.status);
|
|
472
|
+
const result = akmProposalList({
|
|
473
|
+
status,
|
|
474
|
+
ref: args.ref,
|
|
475
|
+
type: args.type,
|
|
476
|
+
includeArchive: status === "accepted" || status === "rejected" || status === "reverted",
|
|
488
477
|
});
|
|
478
|
+
output("proposal-list", result);
|
|
489
479
|
},
|
|
490
480
|
});
|
|
@@ -75,6 +75,11 @@ export async function akmProposalAccept(options) {
|
|
|
75
75
|
source: result.proposal.source,
|
|
76
76
|
...(result.proposal.sourceRun !== undefined ? { sourceRun: result.proposal.sourceRun } : {}),
|
|
77
77
|
assetPath: result.assetPath,
|
|
78
|
+
// Attribution tagging: carry the eligibility lane from the proposal record
|
|
79
|
+
// onto the promoted event so accept outcomes can be sliced by lane.
|
|
80
|
+
...(result.proposal.eligibilitySource !== undefined
|
|
81
|
+
? { eligibilitySource: result.proposal.eligibilitySource }
|
|
82
|
+
: {}),
|
|
78
83
|
},
|
|
79
84
|
});
|
|
80
85
|
return {
|
|
@@ -18,10 +18,11 @@ import { TYPE_DIRS } from "../../core/asset/asset-spec.js";
|
|
|
18
18
|
import { resolveStashDir } from "../../core/common.js";
|
|
19
19
|
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
20
20
|
import { appendEvent } from "../../core/events.js";
|
|
21
|
+
import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
|
|
21
22
|
import { runAgent, } from "../../integrations/agent/index.js";
|
|
22
23
|
import { resolveProcessAgentProfile } from "../../integrations/agent/config.js";
|
|
23
24
|
import { buildProposePrompt, parseAgentProposalPayload } from "../../integrations/agent/prompts.js";
|
|
24
|
-
import {
|
|
25
|
+
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
25
26
|
import { baseFailureFields, enoentHintMessage, isEnoentFailure, loadAgentConfigFromDisk, resolveAgentProfile, } from "../agent/agent-support.js";
|
|
26
27
|
import { createProposal, isProposalSkipped, } from "./validators/proposals.js";
|
|
27
28
|
function failureEnvelope(result, type, name, fallbackReason = "non_zero_exit") {
|
|
@@ -93,10 +94,14 @@ export async function akmPropose(options) {
|
|
|
93
94
|
// directly using its file tools rather than returning JSON via stdout.
|
|
94
95
|
const draftFilePath = import("node:os").then((os) => import("node:path").then((path) => path.join(os.tmpdir(), `akm-propose-${options.type}-${options.name.replace(/[^a-z0-9_-]/gi, "_")}-${Date.now()}.md`)));
|
|
95
96
|
const resolvedDraftPath = await draftFilePath;
|
|
97
|
+
// Standards "rulebook" for this target — wiki schema (wiki page) or stash
|
|
98
|
+
// convention/meta facts (non-wiki asset); empty when neither fires.
|
|
99
|
+
const standardsContext = resolveStandardsContext(`${options.type}:${options.name}`, stash);
|
|
96
100
|
const prompt = buildProposePrompt({
|
|
97
101
|
type: options.type,
|
|
98
102
|
name: options.name,
|
|
99
103
|
task: options.task,
|
|
104
|
+
...(standardsContext.trim() ? { standardsContext } : {}),
|
|
100
105
|
draftFilePath: resolvedDraftPath,
|
|
101
106
|
});
|
|
102
107
|
// 4. Spawn the agent.
|
|
@@ -123,7 +128,7 @@ export async function akmPropose(options) {
|
|
|
123
128
|
...(resolvedTimeoutMs !== undefined ? { timeoutMs: resolvedTimeoutMs } : {}),
|
|
124
129
|
};
|
|
125
130
|
result = profile.sdkMode
|
|
126
|
-
? await
|
|
131
|
+
? await runOpencodeSdk(profile, prompt ?? "", runOptions)
|
|
127
132
|
: await runAgent(profile, prompt, runOptions);
|
|
128
133
|
}
|
|
129
134
|
if (!result.ok) {
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
*/
|
|
60
60
|
// ── Reflect-size guard ───────────────────────────────────────────────────────
|
|
61
61
|
import { parseFrontmatter } from "../../../core/asset/frontmatter.js";
|
|
62
|
+
import { DESCRIPTION_MAX_CHARS, DESCRIPTION_MIN_CHARS, WHEN_TO_USE_MAX_CHARS, WHEN_TO_USE_MIN_CHARS, } from "../../../core/authoring-rules.js";
|
|
62
63
|
import { detectTruncatedDescription, TRUNCATION_TRAILING_WORDS } from "../../../core/text-truncation.js";
|
|
63
64
|
// ── Description / when_to_use shape ─────────────────────────────────────────
|
|
64
65
|
export const HEADING_FRAGMENT_PATTERNS = [
|
|
@@ -80,10 +81,10 @@ export function isValidDescription(value, inputRef, options = {}) {
|
|
|
80
81
|
const v = value.trim();
|
|
81
82
|
if (!v)
|
|
82
83
|
return { ok: false, reason: "description is empty" };
|
|
83
|
-
if (v.length <
|
|
84
|
-
return { ok: false, reason: `description is too short (${v.length} chars; need
|
|
85
|
-
if (v.length >
|
|
86
|
-
return { ok: false, reason: `description is too long (${v.length} chars; max
|
|
84
|
+
if (v.length < DESCRIPTION_MIN_CHARS)
|
|
85
|
+
return { ok: false, reason: `description is too short (${v.length} chars; need ≥${DESCRIPTION_MIN_CHARS})` };
|
|
86
|
+
if (v.length > DESCRIPTION_MAX_CHARS)
|
|
87
|
+
return { ok: false, reason: `description is too long (${v.length} chars; max ${DESCRIPTION_MAX_CHARS})` };
|
|
87
88
|
if (/^\s*[\d#*\->`]/.test(v))
|
|
88
89
|
return { ok: false, reason: "description starts with a digit or markdown marker" };
|
|
89
90
|
const last = v.slice(-1);
|
|
@@ -133,10 +134,10 @@ export function isValidWhenToUse(value, inputRef) {
|
|
|
133
134
|
const v = value.trim();
|
|
134
135
|
if (!v)
|
|
135
136
|
return { ok: false, reason: "when_to_use is empty" };
|
|
136
|
-
if (v.length <
|
|
137
|
-
return { ok: false, reason: `when_to_use is too short (${v.length} chars; need
|
|
138
|
-
if (v.length >
|
|
139
|
-
return { ok: false, reason: `when_to_use is too long (${v.length} chars; max
|
|
137
|
+
if (v.length < WHEN_TO_USE_MIN_CHARS)
|
|
138
|
+
return { ok: false, reason: `when_to_use is too short (${v.length} chars; need ≥${WHEN_TO_USE_MIN_CHARS})` };
|
|
139
|
+
if (v.length > WHEN_TO_USE_MAX_CHARS)
|
|
140
|
+
return { ok: false, reason: `when_to_use is too long (${v.length} chars; max ${WHEN_TO_USE_MAX_CHARS})` };
|
|
140
141
|
if (/^when working with\b/i.test(v))
|
|
141
142
|
return { ok: false, reason: "when_to_use is the circular 'When working with ...' fallback" };
|
|
142
143
|
const refTail = inputRef.split(":").pop()?.toLowerCase() ?? "";
|