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
|
Binary file
|
|
@@ -24,26 +24,28 @@
|
|
|
24
24
|
import fs from "node:fs";
|
|
25
25
|
import os from "node:os";
|
|
26
26
|
import path from "node:path";
|
|
27
|
-
import { assertNever } from "../../core/assert.js";
|
|
28
27
|
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
29
28
|
import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
|
|
30
29
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
31
30
|
import { stripMarkdownFences } from "../../core/asset/markdown.js";
|
|
31
|
+
import { DESCRIPTION_MAX_CHARS, requiresDescription } from "../../core/authoring-rules.js";
|
|
32
32
|
import { resolveStashDir } from "../../core/common.js";
|
|
33
33
|
import { loadConfig } from "../../core/config/config.js";
|
|
34
34
|
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
35
35
|
import { appendEvent, readEvents } from "../../core/events.js";
|
|
36
36
|
import { lintLessonContent } from "../../core/lesson-lint.js";
|
|
37
|
+
import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
|
|
37
38
|
import { lookup } from "../../indexer/indexer.js";
|
|
38
39
|
import { runAgent, } from "../../integrations/agent/index.js";
|
|
39
40
|
import { resolveProcessAgentProfile } from "../../integrations/agent/config.js";
|
|
40
41
|
import { buildReflectPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "../../integrations/agent/prompts.js";
|
|
41
42
|
import { resolveImproveProcessRunnerFromProfile, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
|
|
43
|
+
import { executeRunner } from "../../integrations/agent/runner-dispatch.js";
|
|
42
44
|
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
43
45
|
import { chatCompletion } from "../../llm/client.js";
|
|
44
46
|
import { isLlmFeatureEnabled } from "../../llm/feature-gate.js";
|
|
45
47
|
import { baseFailureFields, enoentHintMessage, isEnoentFailure, loadAgentConfigFromDisk, resolveAgentProfile, } from "../agent/agent-support.js";
|
|
46
|
-
import { checkReflectSize } from "../proposal/validators/proposal-quality-validators.js";
|
|
48
|
+
import { checkReflectSize, isValidDescription } from "../proposal/validators/proposal-quality-validators.js";
|
|
47
49
|
import { createProposal, isProposalSkipped, listProposals, } from "../proposal/validators/proposals.js";
|
|
48
50
|
import { deriveLessonRef, runLessonQualityJudge } from "./distill.js";
|
|
49
51
|
import { classifyReflectChange } from "./reflect-noise.js";
|
|
@@ -383,6 +385,101 @@ function splitFrontmatter(raw) {
|
|
|
383
385
|
return { fmText: null, body: raw };
|
|
384
386
|
return { fmText: m[1], body: m[2] };
|
|
385
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Strip an LLM-appended duplicate frontmatter block from a body string.
|
|
390
|
+
*
|
|
391
|
+
* When the LLM echoes the original source file verbatim after its rewrite,
|
|
392
|
+
* the resulting body contains a second `---...---` YAML block. We detect it
|
|
393
|
+
* by requiring BOTH a balanced fence (opening + closing `---`) AND YAML-like
|
|
394
|
+
* `key: value` content inside, so legitimate Markdown thematic breaks and
|
|
395
|
+
* code-fence examples are never truncated.
|
|
396
|
+
*/
|
|
397
|
+
function stripAppendedFrontmatter(body) {
|
|
398
|
+
const fencePattern = /\n---\r?\n([\s\S]*?)\n---\r?\n/;
|
|
399
|
+
const match = body.match(fencePattern);
|
|
400
|
+
if (!match)
|
|
401
|
+
return body;
|
|
402
|
+
// Only strip when the captured block looks like YAML frontmatter.
|
|
403
|
+
if (!/^\w[\w-]*:/m.test(match[1]))
|
|
404
|
+
return body;
|
|
405
|
+
return body.slice(0, body.indexOf(match[0])).replace(/\s+$/, "");
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* #636 — deterministically derive a valid `description` from an asset's existing
|
|
409
|
+
* metadata when one is missing. Sources, in priority order: the `title:`
|
|
410
|
+
* frontmatter field, the first `# Heading` in the (proposed or source) body, and
|
|
411
|
+
* the first sentence of the opening body paragraph. The candidate is normalized
|
|
412
|
+
* (whitespace collapsed, trailing punctuation/markdown stripped, clamped to the
|
|
413
|
+
* description max) and only returned if it PASSES `isValidDescription` — so this
|
|
414
|
+
* never produces a heading-fragment, truncated, or otherwise gate-failing value.
|
|
415
|
+
* Returns `undefined` when nothing usable can be derived (caller leaves the
|
|
416
|
+
* proposal as-is rather than fabricating prose).
|
|
417
|
+
*
|
|
418
|
+
* This is intentionally deterministic and lives in the reflect proposal-build
|
|
419
|
+
* path — it does NOT touch the validators or the promote-time repair.
|
|
420
|
+
*/
|
|
421
|
+
function deriveDescriptionFromAsset(title, proposedBody, sourceBody, targetRef) {
|
|
422
|
+
// Each candidate is tagged with its kind. A title or `# Heading` is a bare
|
|
423
|
+
// fragment ("Paged.js — Named Page") that reads poorly as a description even
|
|
424
|
+
// when it is long enough to pass the length gate, so for those we prefer the
|
|
425
|
+
// padded sentence form. A prose sentence is already a sentence, so it is used
|
|
426
|
+
// as-is (padding it would double-wrap an already-complete sentence).
|
|
427
|
+
const candidates = [];
|
|
428
|
+
// 1. title: frontmatter
|
|
429
|
+
if (typeof title === "string" && title.trim())
|
|
430
|
+
candidates.push({ text: title.trim(), kind: "fragment" });
|
|
431
|
+
// 2. first `# Heading` (proposed body first, then source body)
|
|
432
|
+
for (const body of [proposedBody, sourceBody]) {
|
|
433
|
+
const headingMatch = body.match(/^#{1,6}\s+(.+?)\s*$/m);
|
|
434
|
+
if (headingMatch?.[1])
|
|
435
|
+
candidates.push({ text: headingMatch[1].trim(), kind: "fragment" });
|
|
436
|
+
}
|
|
437
|
+
// 3. first sentence of the opening prose paragraph (skip headings, fences,
|
|
438
|
+
// list markers, blockquotes — those are not prose).
|
|
439
|
+
for (const body of [proposedBody, sourceBody]) {
|
|
440
|
+
const firstSentence = firstProseSentence(body);
|
|
441
|
+
if (firstSentence)
|
|
442
|
+
candidates.push({ text: firstSentence, kind: "prose" });
|
|
443
|
+
}
|
|
444
|
+
for (const { text, kind } of candidates) {
|
|
445
|
+
const normalized = normalizeDescriptionCandidate(text);
|
|
446
|
+
if (!normalized)
|
|
447
|
+
continue;
|
|
448
|
+
// For a title/heading fragment, try the padded sentence form FIRST so the
|
|
449
|
+
// result reads as a sentence rather than a bare fragment — a short but valid
|
|
450
|
+
// title like "Paged.js — Named Page" (21 chars) would otherwise be returned
|
|
451
|
+
// verbatim. Fall back to the bare form only if the padded form fails the
|
|
452
|
+
// gate. A prose candidate is already a sentence, so it is used as-is.
|
|
453
|
+
const variants = kind === "fragment" ? [`Reference notes on ${normalized}.`, normalized] : [normalized];
|
|
454
|
+
for (const v of variants) {
|
|
455
|
+
const clamped = v.length > DESCRIPTION_MAX_CHARS ? v.slice(0, DESCRIPTION_MAX_CHARS).trimEnd() : v;
|
|
456
|
+
if (isValidDescription(clamped, targetRef, { skipRefTailCheck: true }).ok)
|
|
457
|
+
return clamped;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
/** Extract the first prose sentence from a markdown body, or `""` if none. */
|
|
463
|
+
function firstProseSentence(body) {
|
|
464
|
+
for (const rawLine of body.split(/\r?\n/)) {
|
|
465
|
+
const line = rawLine.trim();
|
|
466
|
+
if (!line)
|
|
467
|
+
continue;
|
|
468
|
+
if (/^(#{1,6}\s|```|~~~|[-*+]\s|\d+\.\s|>|\||<!--)/.test(line))
|
|
469
|
+
continue;
|
|
470
|
+
const sentenceMatch = line.match(/^(.+?[.!?])(\s|$)/);
|
|
471
|
+
return (sentenceMatch?.[1] ?? line).trim();
|
|
472
|
+
}
|
|
473
|
+
return "";
|
|
474
|
+
}
|
|
475
|
+
/** Normalize a description candidate: strip markdown markers, collapse space. */
|
|
476
|
+
function normalizeDescriptionCandidate(raw) {
|
|
477
|
+
return raw
|
|
478
|
+
.replace(/`/g, "")
|
|
479
|
+
.replace(/^[#>*\-\s]+/, "")
|
|
480
|
+
.replace(/\s+/g, " ")
|
|
481
|
+
.trim();
|
|
482
|
+
}
|
|
386
483
|
/**
|
|
387
484
|
* Reflect post-processor — enforces the safety rails described at the top of
|
|
388
485
|
* this file:
|
|
@@ -408,7 +505,7 @@ function splitFrontmatter(raw) {
|
|
|
408
505
|
* from `payload.frontmatter` so identity fields can be enforced. Size guard
|
|
409
506
|
* is skipped because there is no source to compare against.
|
|
410
507
|
*/
|
|
411
|
-
function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
508
|
+
export function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
412
509
|
const warnings = [];
|
|
413
510
|
const { fmText: sourceFmText, body: sourceBody } = sourceContent
|
|
414
511
|
? splitFrontmatter(sourceContent)
|
|
@@ -449,7 +546,35 @@ function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
|
449
546
|
mergedFm[field] = sourceFm[field];
|
|
450
547
|
}
|
|
451
548
|
}
|
|
452
|
-
const cleanedBody = rawLlmBody.replace(/^\s+/, "");
|
|
549
|
+
const cleanedBody = stripAppendedFrontmatter(rawLlmBody.replace(/^\s+/, ""));
|
|
550
|
+
// #636 — deterministic description fallback (reflect-side belt-and-suspenders).
|
|
551
|
+
// If the type requires a `description` and the merged frontmatter is still
|
|
552
|
+
// MISSING one (source had none AND the model didn't author one), derive a
|
|
553
|
+
// description DETERMINISTICALLY from the existing `title:` frontmatter or the
|
|
554
|
+
// first `# Heading` / opening body sentence — never free-form invention. This
|
|
555
|
+
// runs in the reflect proposal-build path, BEFORE the proposal is created, so
|
|
556
|
+
// the validator/promote path is left untouched (no gate fabricates content).
|
|
557
|
+
//
|
|
558
|
+
// Scope is the issue's target: a source asset that ALREADY carries frontmatter
|
|
559
|
+
// (e.g. scraped docs: `source`/`title`/`scraped`) but has a MISSING/empty
|
|
560
|
+
// `description`. We deliberately do NOT fire when:
|
|
561
|
+
// - the source has no frontmatter block at all (injecting one would be a
|
|
562
|
+
// structural change and would defeat the #580 no-op/cosmetic noise gate
|
|
563
|
+
// for a pure body echo), or
|
|
564
|
+
// - a present-but-otherwise-invalid description exists (too short, a heading
|
|
565
|
+
// fragment) — overwriting authored content is out of scope; the prompt
|
|
566
|
+
// instruction handles improving it instead.
|
|
567
|
+
const refType = targetRef.includes(":") ? (targetRef.split(":")[0] ?? "") : "";
|
|
568
|
+
const mergedDesc = mergedFm.description;
|
|
569
|
+
const descIsMissing = typeof mergedDesc !== "string" || mergedDesc.trim().length === 0;
|
|
570
|
+
const sourceHadFrontmatter = sourceFmText !== null && Object.keys(sourceFm).length > 0;
|
|
571
|
+
if (refType && requiresDescription(refType) && descIsMissing && sourceHadFrontmatter) {
|
|
572
|
+
const derived = deriveDescriptionFromAsset(mergedFm.title, cleanedBody, sourceBody, targetRef);
|
|
573
|
+
if (derived) {
|
|
574
|
+
mergedFm.description = derived;
|
|
575
|
+
warnings.push("Synthesized a deterministic `description` from title/heading (#636) — source and proposal lacked one.");
|
|
576
|
+
}
|
|
577
|
+
}
|
|
453
578
|
// Size guard — only when source body is meaningfully large. The pure
|
|
454
579
|
// predicate lives in `core/proposal-quality-validators` so the same check
|
|
455
580
|
// also runs inside `runProposalValidators` on `proposal accept`.
|
|
@@ -585,6 +710,9 @@ export async function akmReflect(options = {}) {
|
|
|
585
710
|
metadata: {
|
|
586
711
|
...(options.task ? { task: options.task } : {}),
|
|
587
712
|
...(options.profile ? { profile: options.profile } : {}),
|
|
713
|
+
// Attribution tagging: stamp the eligibility lane so reflect_invoked can be
|
|
714
|
+
// sliced by lane downstream. See EligibilitySource.
|
|
715
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
588
716
|
},
|
|
589
717
|
});
|
|
590
718
|
// Fix #3 (observability 0.8.0): every failure path below MUST emit
|
|
@@ -723,6 +851,9 @@ export async function akmReflect(options = {}) {
|
|
|
723
851
|
// Reflexion-style verbal-RL: inject rejected proposals so the agent avoids
|
|
724
852
|
// reproducing proposals that have already been reviewed and refused.
|
|
725
853
|
const rejectedProposals = readRejectedProposals(stash, options.ref);
|
|
854
|
+
// Standards "rulebook" for this target — wiki schema (wiki page) or stash
|
|
855
|
+
// convention/meta facts (non-wiki asset); empty when neither fires.
|
|
856
|
+
const standardsContext = resolveStandardsContext(options.ref, stash);
|
|
726
857
|
// 5. Spawn the agent — with optional Self-Refine loop (R-1 / #372).
|
|
727
858
|
//
|
|
728
859
|
// maxRefineIters controls how many agent invocations are made:
|
|
@@ -791,6 +922,7 @@ export async function akmReflect(options = {}) {
|
|
|
791
922
|
...(schemaHints.length > 0 ? { schemaHints } : {}),
|
|
792
923
|
...(relatedLessons.length > 0 ? { relatedLessons } : {}),
|
|
793
924
|
...(options.task ? { task: options.task } : {}),
|
|
925
|
+
...(standardsContext.trim() ? { standardsContext } : {}),
|
|
794
926
|
...(options.avoidPatterns && options.avoidPatterns.length > 0 ? { avoidPatterns: options.avoidPatterns } : {}),
|
|
795
927
|
...(rejectedProposals.length > 0 ? { rejectedProposals } : {}),
|
|
796
928
|
// R-1: inject prior draft as self-critique target on iterations > 0
|
|
@@ -822,44 +954,39 @@ export async function akmReflect(options = {}) {
|
|
|
822
954
|
iterResult = await runAgent(resolvedProfile, prompt, runOptions);
|
|
823
955
|
}
|
|
824
956
|
else if (runnerSpec) {
|
|
825
|
-
// v2: dispatch through unified RunnerSpec
|
|
957
|
+
// v2: dispatch through the unified RunnerSpec seam (X3). The `agent` /
|
|
958
|
+
// `sdk` arms route to the default profile runners; the `llm` arm is
|
|
959
|
+
// reflect-specific (wraps `runReflectViaLlm` — its bespoke iteration
|
|
960
|
+
// shape) so it is supplied as the `llm` handler.
|
|
826
961
|
const runOptions = {
|
|
827
962
|
stdio: "captured",
|
|
828
963
|
parseOutput: "text",
|
|
829
964
|
...(Object.keys(agentEnv).length > 0 ? { env: agentEnv } : {}),
|
|
830
965
|
};
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
...(runnerSpec.timeoutMs !== undefined ? { timeoutMs: runnerSpec.timeoutMs } : {}),
|
|
856
|
-
});
|
|
857
|
-
break;
|
|
858
|
-
default:
|
|
859
|
-
// Exhaustiveness arm (H1): a 4th RunnerSpec kind becomes a compile
|
|
860
|
-
// error here instead of leaving `iterResult` unassigned at runtime.
|
|
861
|
-
assertNever(runnerSpec);
|
|
862
|
-
}
|
|
966
|
+
iterResult = await executeRunner(runnerSpec, prompt ?? "", runOptions, {
|
|
967
|
+
llm: async (spec) =>
|
|
968
|
+
// LLM HTTP path — `draftFilePath` is accepted for type symmetry
|
|
969
|
+
// (see `RunReflectViaLlmOptions.draftFilePath` docstring) but is
|
|
970
|
+
// intentionally a no-op. The prompt builder above also did not
|
|
971
|
+
// include the file-write contract for this kind, so the LLM is
|
|
972
|
+
// still asked for JSON via stdout.
|
|
973
|
+
runReflectViaLlm({
|
|
974
|
+
prompt,
|
|
975
|
+
connection: spec.connection,
|
|
976
|
+
timeoutMs: spec.timeoutMs ?? (typeof resolvedTimeoutMs === "number" ? resolvedTimeoutMs : undefined),
|
|
977
|
+
priorDraft,
|
|
978
|
+
iteration: iter,
|
|
979
|
+
responseSchema: REFLECT_JSON_SCHEMA,
|
|
980
|
+
chat: options.chat,
|
|
981
|
+
...(maxTokensForLlm !== undefined ? { maxTokens: maxTokensForLlm } : {}),
|
|
982
|
+
}),
|
|
983
|
+
// The `agent` arm (and only the agent arm — preserving prior behavior)
|
|
984
|
+
// overlays `spec.timeoutMs` onto the base run options.
|
|
985
|
+
runAgent: (profile, p, opts) => runAgent(profile, p, {
|
|
986
|
+
...opts,
|
|
987
|
+
...(runnerSpec.timeoutMs !== undefined ? { timeoutMs: runnerSpec.timeoutMs } : {}),
|
|
988
|
+
}),
|
|
989
|
+
});
|
|
863
990
|
}
|
|
864
991
|
else {
|
|
865
992
|
// Production path (v1): dispatch directly to the appropriate runner.
|
|
@@ -1148,8 +1275,19 @@ export async function akmReflect(options = {}) {
|
|
|
1148
1275
|
// (new-asset proposals have nothing to diff against).
|
|
1149
1276
|
if (assetContent !== undefined) {
|
|
1150
1277
|
const changeKind = classifyReflectChange(assetContent, payload.content);
|
|
1151
|
-
|
|
1152
|
-
|
|
1278
|
+
// 'low-value' is config-gated (#639). DEFAULT OFF — absent = byte-identical
|
|
1279
|
+
// pre-#639 behaviour (low-value treated the same as substantive). Resolved
|
|
1280
|
+
// by the caller from the ACTIVE improve profile's
|
|
1281
|
+
// `processes.reflect.lowValueFilter.enabled` and passed via options, so the
|
|
1282
|
+
// running profile (not a hardcoded `profiles.improve.default`) decides.
|
|
1283
|
+
const lowValueFilterEnabled = options.lowValueFilter === true;
|
|
1284
|
+
const isDeferred = changeKind === "noop" || changeKind === "cosmetic" || (changeKind === "low-value" && lowValueFilterEnabled);
|
|
1285
|
+
if (isDeferred) {
|
|
1286
|
+
const subreason = changeKind === "noop"
|
|
1287
|
+
? "reflect_skipped_noop"
|
|
1288
|
+
: changeKind === "low-value"
|
|
1289
|
+
? "reflect_skipped_low_value"
|
|
1290
|
+
: "reflect_skipped_cosmetic";
|
|
1153
1291
|
emitReflectFailed("no_change", subreason, options.ref, { changeKind });
|
|
1154
1292
|
return {
|
|
1155
1293
|
schemaVersion: 1,
|
|
@@ -1157,7 +1295,9 @@ export async function akmReflect(options = {}) {
|
|
|
1157
1295
|
reason: "no_change",
|
|
1158
1296
|
error: changeKind === "noop"
|
|
1159
1297
|
? `Reflect skipped: proposed content for ${payload.ref} is identical to the current asset (empty diff); no proposal created.`
|
|
1160
|
-
:
|
|
1298
|
+
: changeKind === "low-value"
|
|
1299
|
+
? `Reflect skipped: proposed content for ${payload.ref} is a low-value prose micro-rewrite (few changed tokens, no structural changes); no proposal created.`
|
|
1300
|
+
: `Reflect skipped: proposed content for ${payload.ref} is a cosmetic-only reformat of the current asset (whitespace/fence/YAML-folding changes); no proposal created.`,
|
|
1161
1301
|
...(options.ref ? { ref: options.ref } : {}),
|
|
1162
1302
|
exitCode: result.exitCode,
|
|
1163
1303
|
};
|
|
@@ -1228,6 +1368,9 @@ export async function akmReflect(options = {}) {
|
|
|
1228
1368
|
// `parseAgentProposalPayload` already clamps to [0, 1] and drops non-
|
|
1229
1369
|
// finite values; `createProposal` runs its own sanitizer as a safety net.
|
|
1230
1370
|
...(typeof payload.confidence === "number" ? { confidence: payload.confidence } : {}),
|
|
1371
|
+
// Attribution tagging: persist the eligibility lane on the proposal so it
|
|
1372
|
+
// survives to accept/reject/revert time even across runs. See EligibilitySource.
|
|
1373
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
1231
1374
|
};
|
|
1232
1375
|
const proposalResult = createProposal(stash, createInput, options.ctx);
|
|
1233
1376
|
if (isProposalSkipped(proposalResult)) {
|