akm-cli 0.9.0-beta.6 → 0.9.0-rc.0
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 +663 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/help/help-improve.md +9 -6
- package/dist/assets/hints/cli-hints-full.md +6 -5
- 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/proactive-maintenance.json +25 -0
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/recombine-only.json +21 -0
- package/dist/assets/profiles/reflect-distill.json +30 -0
- 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 +11 -3
- 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 +45 -16
- package/dist/assets/wiki/schema-template.md +4 -4
- package/dist/cli/clack.js +56 -0
- package/dist/cli/config-migrate.js +7 -1
- package/dist/cli/confirm.js +1 -1
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +25 -14
- package/dist/commands/agent/agent-dispatch.js +3 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +26 -7
- package/dist/commands/config-cli.js +26 -13
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +220 -227
- package/dist/commands/env/env.js +14 -67
- package/dist/commands/env/secret-cli.js +140 -138
- package/dist/commands/feedback-cli.js +153 -147
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/advisories.js +151 -0
- package/dist/commands/health/checks.js +103 -16
- package/dist/commands/health/html-report.js +447 -81
- package/dist/commands/health/improve-metrics.js +771 -0
- package/dist/commands/health/llm-usage.js +65 -0
- package/dist/commands/health/md-report.js +103 -0
- package/dist/commands/health/metrics.js +278 -0
- package/dist/commands/health/stash-exposure.js +46 -0
- package/dist/commands/health/surfaces.js +216 -0
- package/dist/commands/health/task-runs.js +135 -0
- package/dist/commands/health/types.js +26 -0
- package/dist/commands/health/windows.js +195 -0
- package/dist/commands/health.js +91 -1083
- package/dist/commands/improve/anti-collapse.js +170 -0
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/collapse-detector.js +421 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +64 -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 +1313 -1278
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill/content-repair.js +202 -0
- package/dist/commands/improve/distill/promote-memory.js +229 -0
- package/dist/commands/improve/distill/quality-gate.js +236 -0
- package/dist/commands/improve/distill-guards.js +127 -0
- package/dist/commands/improve/distill-promotion-policy.js +826 -167
- package/dist/commands/improve/distill.js +243 -599
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +179 -59
- package/dist/commands/improve/extract-prompt.js +55 -4
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +409 -43
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/hot-probation.js +45 -0
- package/dist/commands/improve/improve-auto-accept.js +160 -7
- package/dist/commands/improve/improve-cli.js +115 -73
- package/dist/commands/improve/improve-profiles.js +32 -8
- package/dist/commands/improve/improve-result-file.js +15 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +510 -2537
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1100 -0
- package/dist/commands/improve/memory/memory-belief.js +14 -15
- package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
- package/dist/commands/improve/memory/memory-improve.js +27 -27
- package/dist/commands/improve/outcome-loop.js +270 -0
- package/dist/commands/improve/preparation.js +2002 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +398 -0
- package/dist/commands/improve/recombine.js +818 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +212 -45
- package/dist/commands/improve/salience.js +455 -0
- package/dist/commands/improve/schema-similarity-gate.js +168 -0
- package/dist/commands/improve/shared.js +51 -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/observability-cli.js +4 -4
- package/dist/commands/proposal/drain-policies.js +13 -4
- package/dist/commands/proposal/drain.js +45 -51
- package/dist/commands/proposal/legacy-import.js +115 -0
- package/dist/commands/proposal/proposal-cli.js +24 -34
- package/dist/commands/proposal/proposal.js +7 -1
- package/dist/commands/proposal/propose.js +8 -3
- package/dist/commands/proposal/repository.js +829 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +93 -882
- package/dist/commands/read/curate.js +419 -103
- package/dist/commands/read/knowledge.js +10 -3
- package/dist/commands/read/remember-cli.js +133 -138
- package/dist/commands/read/search-cli.js +15 -8
- package/dist/commands/read/search.js +22 -11
- package/dist/commands/read/show.js +106 -14
- package/dist/commands/registry-cli.js +76 -87
- package/dist/commands/remember.js +11 -12
- package/dist/commands/sources/add-cli.js +91 -95
- package/dist/commands/sources/history.js +1 -1
- package/dist/commands/sources/init.js +66 -18
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +44 -46
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/sources-cli.js +3 -3
- package/dist/commands/sources/stash-cli.js +29 -41
- package/dist/commands/sources/stash-skeleton.js +57 -8
- package/dist/commands/tasks/default-tasks.js +15 -2
- package/dist/commands/tasks/tasks-cli.js +20 -29
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +23 -38
- package/dist/commands/workflow-cli.js +15 -1
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +21 -4
- package/dist/core/asset/frontmatter.js +188 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +4 -23
- package/dist/core/concurrent.js +10 -1
- package/dist/core/config/config-io.js +10 -1
- package/dist/core/config/config-migration.js +18 -40
- package/dist/core/config/config-schema.js +389 -58
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +67 -22
- package/dist/core/deep-merge.js +38 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/eval/rank-metrics.js +113 -0
- package/dist/core/events.js +4 -7
- package/dist/core/improve-types.js +47 -8
- package/dist/core/logs-db.js +14 -75
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +21 -18
- 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 +770 -0
- package/dist/core/state-db.js +142 -1091
- package/dist/core/structured.js +69 -0
- package/dist/core/time.js +53 -0
- package/dist/core/warn.js +21 -0
- package/dist/core/write-source.js +37 -0
- package/dist/indexer/db/db.js +356 -780
- package/dist/indexer/db/entry-mapper.js +41 -0
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/db/schema.js +516 -0
- package/dist/indexer/ensure-index.js +103 -24
- package/dist/indexer/feedback/utility-policy.js +75 -0
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +207 -4
- package/dist/indexer/index-writer-lock.js +106 -0
- package/dist/indexer/index-written-assets.js +105 -0
- package/dist/indexer/indexer.js +291 -310
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/metadata.js +20 -0
- package/dist/indexer/read-preflight.js +23 -0
- package/dist/indexer/search/db-search.js +89 -13
- package/dist/indexer/search/fts-query.js +51 -0
- package/dist/indexer/search/ranking-contributors.js +95 -9
- package/dist/indexer/search/ranking.js +79 -3
- package/dist/indexer/search/search-fields.js +6 -0
- package/dist/indexer/search/search-source.js +32 -21
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/indexer/walk/walker.js +21 -13
- package/dist/integrations/agent/builders.js +39 -13
- package/dist/integrations/agent/config.js +20 -59
- package/dist/integrations/agent/detect.js +9 -0
- package/dist/integrations/agent/index.js +3 -19
- package/dist/integrations/agent/model-aliases.js +7 -2
- package/dist/integrations/agent/profiles.js +7 -1
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/agent/runner.js +13 -9
- package/dist/integrations/agent/spawn.js +69 -67
- package/dist/integrations/harnesses/claude/agent-builder.js +1 -1
- package/dist/integrations/harnesses/claude/index.js +2 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
- package/dist/integrations/harnesses/opencode/index.js +2 -0
- 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 +98 -17
- package/dist/integrations/harnesses/types.js +1 -0
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/call-ai.js +2 -2
- package/dist/llm/client.js +57 -15
- package/dist/llm/embedder.js +67 -4
- package/dist/llm/embedders/cache.js +3 -1
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +73 -3
- package/dist/llm/feature-gate.js +16 -15
- 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 +85 -14
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/helpers.js +0 -3
- package/dist/output/shapes/passthrough.js +2 -1
- package/dist/output/text/helpers.js +29 -1
- package/dist/output/text/workflow.js +1 -0
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +27 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2718 -2354
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +891 -597
- package/dist/setup/detect.js +9 -0
- package/dist/setup/legacy-config.js +106 -0
- package/dist/setup/prompt.js +57 -0
- package/dist/setup/providers.js +14 -0
- package/dist/setup/registry-stash-loader.js +12 -0
- package/dist/setup/semantic-assets.js +124 -0
- package/dist/setup/setup.js +52 -1614
- package/dist/setup/steps/connection.js +734 -0
- package/dist/setup/steps/output.js +31 -0
- package/dist/setup/steps/platforms.js +124 -0
- package/dist/setup/steps/semantic.js +27 -0
- package/dist/setup/steps/sources.js +222 -0
- package/dist/setup/steps/stashdir.js +42 -0
- package/dist/setup/steps/tasks.js +152 -0
- 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/canaries-repository.js +107 -0
- package/dist/storage/repositories/consolidation-repository.js +38 -0
- package/dist/storage/repositories/embeddings-repository.js +72 -0
- package/dist/storage/repositories/events-repository.js +187 -0
- package/dist/storage/repositories/extract-sessions-repository.js +96 -0
- package/dist/storage/repositories/improve-runs-repository.js +146 -0
- package/dist/storage/repositories/index-db.js +14 -8
- package/dist/storage/repositories/proposals-repository.js +220 -0
- package/dist/storage/repositories/recombine-repository.js +213 -0
- package/dist/storage/repositories/registry-cache.js +93 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
- package/dist/storage/repositories/task-history-repository.js +93 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/index.js +9 -0
- 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 +15 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +52 -11
- package/dist/workflows/cli.js +1 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +43 -118
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/README.md +69 -18
- package/docs/data-and-telemetry.md +5 -4
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +10 -10
- package/dist/assets/tasks/core/update-stashes.yml +0 -4
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
- package/dist/indexer/passes/staleness-detect.js +0 -488
|
Binary file
|
|
@@ -24,27 +24,30 @@
|
|
|
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
|
-
import { loadConfig } from "../../core/config/config.js";
|
|
33
|
+
import { getImproveProcessConfig, 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";
|
|
38
|
+
import { warn } from "../../core/warn.js";
|
|
37
39
|
import { lookup } from "../../indexer/indexer.js";
|
|
38
40
|
import { runAgent, } from "../../integrations/agent/index.js";
|
|
39
41
|
import { resolveProcessAgentProfile } from "../../integrations/agent/config.js";
|
|
40
42
|
import { buildReflectPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "../../integrations/agent/prompts.js";
|
|
41
|
-
import { resolveImproveProcessRunnerFromProfile, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
|
|
43
|
+
import { resolveDefaultLlmRunner, resolveImproveProcessRunnerFromProfile, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
|
|
44
|
+
import { executeRunner } from "../../integrations/agent/runner-dispatch.js";
|
|
42
45
|
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
43
46
|
import { chatCompletion } from "../../llm/client.js";
|
|
44
47
|
import { isLlmFeatureEnabled } from "../../llm/feature-gate.js";
|
|
45
48
|
import { baseFailureFields, enoentHintMessage, isEnoentFailure, loadAgentConfigFromDisk, resolveAgentProfile, } from "../agent/agent-support.js";
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
49
|
+
import { createProposal, isProposalSkipped, listProposals, } from "../proposal/repository.js";
|
|
50
|
+
import { checkReflectSize, isValidDescription } from "../proposal/validators/proposal-quality-validators.js";
|
|
48
51
|
import { deriveLessonRef, runLessonQualityJudge } from "./distill.js";
|
|
49
52
|
import { classifyReflectChange } from "./reflect-noise.js";
|
|
50
53
|
const MAX_FEEDBACK_LINES = 10;
|
|
@@ -383,6 +386,101 @@ function splitFrontmatter(raw) {
|
|
|
383
386
|
return { fmText: null, body: raw };
|
|
384
387
|
return { fmText: m[1], body: m[2] };
|
|
385
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Strip an LLM-appended duplicate frontmatter block from a body string.
|
|
391
|
+
*
|
|
392
|
+
* When the LLM echoes the original source file verbatim after its rewrite,
|
|
393
|
+
* the resulting body contains a second `---...---` YAML block. We detect it
|
|
394
|
+
* by requiring BOTH a balanced fence (opening + closing `---`) AND YAML-like
|
|
395
|
+
* `key: value` content inside, so legitimate Markdown thematic breaks and
|
|
396
|
+
* code-fence examples are never truncated.
|
|
397
|
+
*/
|
|
398
|
+
function stripAppendedFrontmatter(body) {
|
|
399
|
+
const fencePattern = /\n---\r?\n([\s\S]*?)\n---\r?\n/;
|
|
400
|
+
const match = body.match(fencePattern);
|
|
401
|
+
if (!match)
|
|
402
|
+
return body;
|
|
403
|
+
// Only strip when the captured block looks like YAML frontmatter.
|
|
404
|
+
if (!/^\w[\w-]*:/m.test(match[1]))
|
|
405
|
+
return body;
|
|
406
|
+
return body.slice(0, body.indexOf(match[0])).replace(/\s+$/, "");
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* #636 — deterministically derive a valid `description` from an asset's existing
|
|
410
|
+
* metadata when one is missing. Sources, in priority order: the `title:`
|
|
411
|
+
* frontmatter field, the first `# Heading` in the (proposed or source) body, and
|
|
412
|
+
* the first sentence of the opening body paragraph. The candidate is normalized
|
|
413
|
+
* (whitespace collapsed, trailing punctuation/markdown stripped, clamped to the
|
|
414
|
+
* description max) and only returned if it PASSES `isValidDescription` — so this
|
|
415
|
+
* never produces a heading-fragment, truncated, or otherwise gate-failing value.
|
|
416
|
+
* Returns `undefined` when nothing usable can be derived (caller leaves the
|
|
417
|
+
* proposal as-is rather than fabricating prose).
|
|
418
|
+
*
|
|
419
|
+
* This is intentionally deterministic and lives in the reflect proposal-build
|
|
420
|
+
* path — it does NOT touch the validators or the promote-time repair.
|
|
421
|
+
*/
|
|
422
|
+
function deriveDescriptionFromAsset(title, proposedBody, sourceBody, targetRef) {
|
|
423
|
+
// Each candidate is tagged with its kind. A title or `# Heading` is a bare
|
|
424
|
+
// fragment ("Paged.js — Named Page") that reads poorly as a description even
|
|
425
|
+
// when it is long enough to pass the length gate, so for those we prefer the
|
|
426
|
+
// padded sentence form. A prose sentence is already a sentence, so it is used
|
|
427
|
+
// as-is (padding it would double-wrap an already-complete sentence).
|
|
428
|
+
const candidates = [];
|
|
429
|
+
// 1. title: frontmatter
|
|
430
|
+
if (typeof title === "string" && title.trim())
|
|
431
|
+
candidates.push({ text: title.trim(), kind: "fragment" });
|
|
432
|
+
// 2. first `# Heading` (proposed body first, then source body)
|
|
433
|
+
for (const body of [proposedBody, sourceBody]) {
|
|
434
|
+
const headingMatch = body.match(/^#{1,6}\s+(.+?)\s*$/m);
|
|
435
|
+
if (headingMatch?.[1])
|
|
436
|
+
candidates.push({ text: headingMatch[1].trim(), kind: "fragment" });
|
|
437
|
+
}
|
|
438
|
+
// 3. first sentence of the opening prose paragraph (skip headings, fences,
|
|
439
|
+
// list markers, blockquotes — those are not prose).
|
|
440
|
+
for (const body of [proposedBody, sourceBody]) {
|
|
441
|
+
const firstSentence = firstProseSentence(body);
|
|
442
|
+
if (firstSentence)
|
|
443
|
+
candidates.push({ text: firstSentence, kind: "prose" });
|
|
444
|
+
}
|
|
445
|
+
for (const { text, kind } of candidates) {
|
|
446
|
+
const normalized = normalizeDescriptionCandidate(text);
|
|
447
|
+
if (!normalized)
|
|
448
|
+
continue;
|
|
449
|
+
// For a title/heading fragment, try the padded sentence form FIRST so the
|
|
450
|
+
// result reads as a sentence rather than a bare fragment — a short but valid
|
|
451
|
+
// title like "Paged.js — Named Page" (21 chars) would otherwise be returned
|
|
452
|
+
// verbatim. Fall back to the bare form only if the padded form fails the
|
|
453
|
+
// gate. A prose candidate is already a sentence, so it is used as-is.
|
|
454
|
+
const variants = kind === "fragment" ? [`Reference notes on ${normalized}.`, normalized] : [normalized];
|
|
455
|
+
for (const v of variants) {
|
|
456
|
+
const clamped = v.length > DESCRIPTION_MAX_CHARS ? v.slice(0, DESCRIPTION_MAX_CHARS).trimEnd() : v;
|
|
457
|
+
if (isValidDescription(clamped, targetRef, { skipRefTailCheck: true }).ok)
|
|
458
|
+
return clamped;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
/** Extract the first prose sentence from a markdown body, or `""` if none. */
|
|
464
|
+
function firstProseSentence(body) {
|
|
465
|
+
for (const rawLine of body.split(/\r?\n/)) {
|
|
466
|
+
const line = rawLine.trim();
|
|
467
|
+
if (!line)
|
|
468
|
+
continue;
|
|
469
|
+
if (/^(#{1,6}\s|```|~~~|[-*+]\s|\d+\.\s|>|\||<!--)/.test(line))
|
|
470
|
+
continue;
|
|
471
|
+
const sentenceMatch = line.match(/^(.+?[.!?])(\s|$)/);
|
|
472
|
+
return (sentenceMatch?.[1] ?? line).trim();
|
|
473
|
+
}
|
|
474
|
+
return "";
|
|
475
|
+
}
|
|
476
|
+
/** Normalize a description candidate: strip markdown markers, collapse space. */
|
|
477
|
+
function normalizeDescriptionCandidate(raw) {
|
|
478
|
+
return raw
|
|
479
|
+
.replace(/`/g, "")
|
|
480
|
+
.replace(/^[#>*\-\s]+/, "")
|
|
481
|
+
.replace(/\s+/g, " ")
|
|
482
|
+
.trim();
|
|
483
|
+
}
|
|
386
484
|
/**
|
|
387
485
|
* Reflect post-processor — enforces the safety rails described at the top of
|
|
388
486
|
* this file:
|
|
@@ -408,7 +506,7 @@ function splitFrontmatter(raw) {
|
|
|
408
506
|
* from `payload.frontmatter` so identity fields can be enforced. Size guard
|
|
409
507
|
* is skipped because there is no source to compare against.
|
|
410
508
|
*/
|
|
411
|
-
function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
509
|
+
export function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
412
510
|
const warnings = [];
|
|
413
511
|
const { fmText: sourceFmText, body: sourceBody } = sourceContent
|
|
414
512
|
? splitFrontmatter(sourceContent)
|
|
@@ -449,7 +547,35 @@ function sanitizeReflectPayload(payload, sourceContent, targetRef) {
|
|
|
449
547
|
mergedFm[field] = sourceFm[field];
|
|
450
548
|
}
|
|
451
549
|
}
|
|
452
|
-
const cleanedBody = rawLlmBody.replace(/^\s+/, "");
|
|
550
|
+
const cleanedBody = stripAppendedFrontmatter(rawLlmBody.replace(/^\s+/, ""));
|
|
551
|
+
// #636 — deterministic description fallback (reflect-side belt-and-suspenders).
|
|
552
|
+
// If the type requires a `description` and the merged frontmatter is still
|
|
553
|
+
// MISSING one (source had none AND the model didn't author one), derive a
|
|
554
|
+
// description DETERMINISTICALLY from the existing `title:` frontmatter or the
|
|
555
|
+
// first `# Heading` / opening body sentence — never free-form invention. This
|
|
556
|
+
// runs in the reflect proposal-build path, BEFORE the proposal is created, so
|
|
557
|
+
// the validator/promote path is left untouched (no gate fabricates content).
|
|
558
|
+
//
|
|
559
|
+
// Scope is the issue's target: a source asset that ALREADY carries frontmatter
|
|
560
|
+
// (e.g. scraped docs: `source`/`title`/`scraped`) but has a MISSING/empty
|
|
561
|
+
// `description`. We deliberately do NOT fire when:
|
|
562
|
+
// - the source has no frontmatter block at all (injecting one would be a
|
|
563
|
+
// structural change and would defeat the #580 no-op/cosmetic noise gate
|
|
564
|
+
// for a pure body echo), or
|
|
565
|
+
// - a present-but-otherwise-invalid description exists (too short, a heading
|
|
566
|
+
// fragment) — overwriting authored content is out of scope; the prompt
|
|
567
|
+
// instruction handles improving it instead.
|
|
568
|
+
const refType = targetRef.includes(":") ? (targetRef.split(":")[0] ?? "") : "";
|
|
569
|
+
const mergedDesc = mergedFm.description;
|
|
570
|
+
const descIsMissing = typeof mergedDesc !== "string" || mergedDesc.trim().length === 0;
|
|
571
|
+
const sourceHadFrontmatter = sourceFmText !== null && Object.keys(sourceFm).length > 0;
|
|
572
|
+
if (refType && requiresDescription(refType) && descIsMissing && sourceHadFrontmatter) {
|
|
573
|
+
const derived = deriveDescriptionFromAsset(mergedFm.title, cleanedBody, sourceBody, targetRef);
|
|
574
|
+
if (derived) {
|
|
575
|
+
mergedFm.description = derived;
|
|
576
|
+
warnings.push("Synthesized a deterministic `description` from title/heading (#636) — source and proposal lacked one.");
|
|
577
|
+
}
|
|
578
|
+
}
|
|
453
579
|
// Size guard — only when source body is meaningfully large. The pure
|
|
454
580
|
// predicate lives in `core/proposal-quality-validators` so the same check
|
|
455
581
|
// also runs inside `runProposalValidators` on `proposal accept`.
|
|
@@ -585,6 +711,9 @@ export async function akmReflect(options = {}) {
|
|
|
585
711
|
metadata: {
|
|
586
712
|
...(options.task ? { task: options.task } : {}),
|
|
587
713
|
...(options.profile ? { profile: options.profile } : {}),
|
|
714
|
+
// Attribution tagging: stamp the eligibility lane so reflect_invoked can be
|
|
715
|
+
// sliced by lane downstream. See EligibilitySource.
|
|
716
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
588
717
|
},
|
|
589
718
|
});
|
|
590
719
|
// Fix #3 (observability 0.8.0): every failure path below MUST emit
|
|
@@ -670,7 +799,7 @@ export async function akmReflect(options = {}) {
|
|
|
670
799
|
}
|
|
671
800
|
else {
|
|
672
801
|
const cfg = options.config ?? loadConfig();
|
|
673
|
-
const reflectProcess = cfg.
|
|
802
|
+
const reflectProcess = getImproveProcessConfig(cfg, "reflect", options.improveProfile);
|
|
674
803
|
// Resolve the runner from the improve profile's reflect entry when present.
|
|
675
804
|
runnerSpec = resolveImproveProcessRunnerFromProfile(reflectProcess, cfg) ?? undefined;
|
|
676
805
|
if (runnerSpec) {
|
|
@@ -702,6 +831,28 @@ export async function akmReflect(options = {}) {
|
|
|
702
831
|
throw err;
|
|
703
832
|
throw err;
|
|
704
833
|
}
|
|
834
|
+
// P1.3 (meta-review 07, Chain G): unattended `akm improve` must never hand
|
|
835
|
+
// reflect a tool-capable runner. Agent-CLI/SDK runners have filesystem
|
|
836
|
+
// access, so a poisoned asset body flowing through the scheduled reflect
|
|
837
|
+
// prompt could steer an agent with tools; the tool-less LLM HTTP runner
|
|
838
|
+
// corrupts output text at worst (src/llm/call-ai.ts). An llm RunnerSpec
|
|
839
|
+
// resolved from the process block is honored; anything else — an agent/sdk
|
|
840
|
+
// spec, a resolved agent profile, or the default-agent fallback below — is
|
|
841
|
+
// pinned to `defaults.llm`, failing CLOSED when that is unset.
|
|
842
|
+
// `options.agentProfile` stays exempt: it is a direct-injection test seam
|
|
843
|
+
// the cron path (loop-stages) never sets.
|
|
844
|
+
if (options.eventSource === "improve" && !options.agentProfile && (!runnerSpec || !runnerIsLlm(runnerSpec))) {
|
|
845
|
+
const cfg = options.config ?? loadConfig();
|
|
846
|
+
const pinned = resolveDefaultLlmRunner(cfg, resolvedTimeoutMs);
|
|
847
|
+
if (!pinned) {
|
|
848
|
+
throw new ConfigError("Unattended improve pins reflect to the tool-less LLM runner, but the config resolves a tool-capable runner and no defaults.llm profile exists to pin to.", "LLM_NOT_CONFIGURED", 'Set processes.reflect.mode to "llm" on the active improve profile, or configure defaults.llm.');
|
|
849
|
+
}
|
|
850
|
+
warn(runnerSpec
|
|
851
|
+
? `[akm] reflect: unattended improve resolved a tool-capable "${runnerSpec.kind}" runner — pinned to the tool-less LLM runner (07 Chain-G).`
|
|
852
|
+
: "[akm] reflect: unattended improve would have fallen back to an agent profile — pinned to the tool-less LLM runner (07 Chain-G).");
|
|
853
|
+
runnerSpec = pinned;
|
|
854
|
+
profile = undefined;
|
|
855
|
+
}
|
|
705
856
|
// Ensure profile is set for agent/sdk runners that don't use runnerSpec
|
|
706
857
|
if (!runnerSpec && !profile) {
|
|
707
858
|
const agent = options.agentConfig ?? loadAgentConfigFromDisk();
|
|
@@ -723,6 +874,9 @@ export async function akmReflect(options = {}) {
|
|
|
723
874
|
// Reflexion-style verbal-RL: inject rejected proposals so the agent avoids
|
|
724
875
|
// reproducing proposals that have already been reviewed and refused.
|
|
725
876
|
const rejectedProposals = readRejectedProposals(stash, options.ref);
|
|
877
|
+
// Standards "rulebook" for this target — wiki schema (wiki page) or stash
|
|
878
|
+
// convention/meta facts (non-wiki asset); empty when neither fires.
|
|
879
|
+
const standardsContext = resolveStandardsContext(options.ref, stash);
|
|
726
880
|
// 5. Spawn the agent — with optional Self-Refine loop (R-1 / #372).
|
|
727
881
|
//
|
|
728
882
|
// maxRefineIters controls how many agent invocations are made:
|
|
@@ -791,6 +945,7 @@ export async function akmReflect(options = {}) {
|
|
|
791
945
|
...(schemaHints.length > 0 ? { schemaHints } : {}),
|
|
792
946
|
...(relatedLessons.length > 0 ? { relatedLessons } : {}),
|
|
793
947
|
...(options.task ? { task: options.task } : {}),
|
|
948
|
+
...(standardsContext.trim() ? { standardsContext } : {}),
|
|
794
949
|
...(options.avoidPatterns && options.avoidPatterns.length > 0 ? { avoidPatterns: options.avoidPatterns } : {}),
|
|
795
950
|
...(rejectedProposals.length > 0 ? { rejectedProposals } : {}),
|
|
796
951
|
// R-1: inject prior draft as self-critique target on iterations > 0
|
|
@@ -822,44 +977,39 @@ export async function akmReflect(options = {}) {
|
|
|
822
977
|
iterResult = await runAgent(resolvedProfile, prompt, runOptions);
|
|
823
978
|
}
|
|
824
979
|
else if (runnerSpec) {
|
|
825
|
-
// v2: dispatch through unified RunnerSpec
|
|
980
|
+
// v2: dispatch through the unified RunnerSpec seam (X3). The `agent` /
|
|
981
|
+
// `sdk` arms route to the default profile runners; the `llm` arm is
|
|
982
|
+
// reflect-specific (wraps `runReflectViaLlm` — its bespoke iteration
|
|
983
|
+
// shape) so it is supplied as the `llm` handler.
|
|
826
984
|
const runOptions = {
|
|
827
985
|
stdio: "captured",
|
|
828
986
|
parseOutput: "text",
|
|
829
987
|
...(Object.keys(agentEnv).length > 0 ? { env: agentEnv } : {}),
|
|
830
988
|
};
|
|
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
|
-
}
|
|
989
|
+
iterResult = await executeRunner(runnerSpec, prompt ?? "", runOptions, {
|
|
990
|
+
llm: async (spec) =>
|
|
991
|
+
// LLM HTTP path — `draftFilePath` is accepted for type symmetry
|
|
992
|
+
// (see `RunReflectViaLlmOptions.draftFilePath` docstring) but is
|
|
993
|
+
// intentionally a no-op. The prompt builder above also did not
|
|
994
|
+
// include the file-write contract for this kind, so the LLM is
|
|
995
|
+
// still asked for JSON via stdout.
|
|
996
|
+
runReflectViaLlm({
|
|
997
|
+
prompt,
|
|
998
|
+
connection: spec.connection,
|
|
999
|
+
timeoutMs: spec.timeoutMs ?? (typeof resolvedTimeoutMs === "number" ? resolvedTimeoutMs : undefined),
|
|
1000
|
+
priorDraft,
|
|
1001
|
+
iteration: iter,
|
|
1002
|
+
responseSchema: REFLECT_JSON_SCHEMA,
|
|
1003
|
+
chat: options.chat,
|
|
1004
|
+
...(maxTokensForLlm !== undefined ? { maxTokens: maxTokensForLlm } : {}),
|
|
1005
|
+
}),
|
|
1006
|
+
// The `agent` arm (and only the agent arm — preserving prior behavior)
|
|
1007
|
+
// overlays `spec.timeoutMs` onto the base run options.
|
|
1008
|
+
runAgent: (profile, p, opts) => runAgent(profile, p, {
|
|
1009
|
+
...opts,
|
|
1010
|
+
...(runnerSpec.timeoutMs !== undefined ? { timeoutMs: runnerSpec.timeoutMs } : {}),
|
|
1011
|
+
}),
|
|
1012
|
+
});
|
|
863
1013
|
}
|
|
864
1014
|
else {
|
|
865
1015
|
// Production path (v1): dispatch directly to the appropriate runner.
|
|
@@ -1044,7 +1194,8 @@ export async function akmReflect(options = {}) {
|
|
|
1044
1194
|
// `profiles.improve.default.processes.reflect.qualityGate.enabled` or
|
|
1045
1195
|
// `profiles.improve.default.processes.distill.qualityGate.enabled` (the
|
|
1046
1196
|
// `lesson_quality_gate` flag name is the legacy alias still accepted by
|
|
1047
|
-
// `isLlmFeatureEnabled`). Fail-
|
|
1197
|
+
// `isLlmFeatureEnabled`). Fail-CLOSED (07 P0-2): a judge error / no-LLM /
|
|
1198
|
+
// parse failure rejects the proposal rather than passing it through.
|
|
1048
1199
|
// G-Eval (arXiv:2303.16634) — quality judgment before admission.
|
|
1049
1200
|
const runtimeConfig = options.config ??
|
|
1050
1201
|
(() => {
|
|
@@ -1148,8 +1299,19 @@ export async function akmReflect(options = {}) {
|
|
|
1148
1299
|
// (new-asset proposals have nothing to diff against).
|
|
1149
1300
|
if (assetContent !== undefined) {
|
|
1150
1301
|
const changeKind = classifyReflectChange(assetContent, payload.content);
|
|
1151
|
-
|
|
1152
|
-
|
|
1302
|
+
// 'low-value' is config-gated (#639). DEFAULT OFF — absent = byte-identical
|
|
1303
|
+
// pre-#639 behaviour (low-value treated the same as substantive). Resolved
|
|
1304
|
+
// by the caller from the ACTIVE improve profile's
|
|
1305
|
+
// `processes.reflect.lowValueFilter.enabled` and passed via options, so the
|
|
1306
|
+
// running profile (not a hardcoded `profiles.improve.default`) decides.
|
|
1307
|
+
const lowValueFilterEnabled = options.lowValueFilter === true;
|
|
1308
|
+
const isDeferred = changeKind === "noop" || changeKind === "cosmetic" || (changeKind === "low-value" && lowValueFilterEnabled);
|
|
1309
|
+
if (isDeferred) {
|
|
1310
|
+
const subreason = changeKind === "noop"
|
|
1311
|
+
? "reflect_skipped_noop"
|
|
1312
|
+
: changeKind === "low-value"
|
|
1313
|
+
? "reflect_skipped_low_value"
|
|
1314
|
+
: "reflect_skipped_cosmetic";
|
|
1153
1315
|
emitReflectFailed("no_change", subreason, options.ref, { changeKind });
|
|
1154
1316
|
return {
|
|
1155
1317
|
schemaVersion: 1,
|
|
@@ -1157,7 +1319,9 @@ export async function akmReflect(options = {}) {
|
|
|
1157
1319
|
reason: "no_change",
|
|
1158
1320
|
error: changeKind === "noop"
|
|
1159
1321
|
? `Reflect skipped: proposed content for ${payload.ref} is identical to the current asset (empty diff); no proposal created.`
|
|
1160
|
-
:
|
|
1322
|
+
: changeKind === "low-value"
|
|
1323
|
+
? `Reflect skipped: proposed content for ${payload.ref} is a low-value prose micro-rewrite (few changed tokens, no structural changes); no proposal created.`
|
|
1324
|
+
: `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
1325
|
...(options.ref ? { ref: options.ref } : {}),
|
|
1162
1326
|
exitCode: result.exitCode,
|
|
1163
1327
|
};
|
|
@@ -1228,6 +1392,9 @@ export async function akmReflect(options = {}) {
|
|
|
1228
1392
|
// `parseAgentProposalPayload` already clamps to [0, 1] and drops non-
|
|
1229
1393
|
// finite values; `createProposal` runs its own sanitizer as a safety net.
|
|
1230
1394
|
...(typeof payload.confidence === "number" ? { confidence: payload.confidence } : {}),
|
|
1395
|
+
// Attribution tagging: persist the eligibility lane on the proposal so it
|
|
1396
|
+
// survives to accept/reject/revert time even across runs. See EligibilitySource.
|
|
1397
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
1231
1398
|
};
|
|
1232
1399
|
const proposalResult = createProposal(stash, createInput, options.ctx);
|
|
1233
1400
|
if (isProposalSkipped(proposalResult)) {
|