akm-cli 0.8.6 → 0.8.14
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 +442 -0
- package/dist/assets/help/help-proposals.md +1 -2
- package/dist/assets/hints/cli-hints-full.md +34 -19
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/profiles/catchup.json +13 -0
- package/dist/assets/profiles/consolidate.json +13 -0
- package/dist/assets/profiles/frequent.json +13 -0
- package/dist/assets/tasks/core/backup.yml +4 -0
- package/dist/assets/tasks/core/extract.yml +4 -0
- package/dist/assets/tasks/core/improve.yml +4 -0
- package/dist/assets/tasks/core/index-refresh.yml +4 -0
- package/dist/assets/tasks/core/sync.yml +4 -0
- package/dist/assets/tasks/core/update-stashes.yml +4 -0
- package/dist/assets/tasks/core/version-check.yml +4 -0
- package/dist/assets/templates/html/default.html +78 -0
- package/dist/assets/templates/html/health.html +560 -0
- package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
- package/dist/cli/config-migrate.js +6 -6
- package/dist/cli/config-validate.js +4 -4
- package/dist/cli/confirm.js +3 -3
- package/dist/cli/parse-args.js +1 -1
- package/dist/cli/shared.js +72 -19
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +206 -3866
- package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
- package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
- package/dist/commands/agent/contribute-cli.js +200 -0
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +230 -3
- package/dist/commands/db-cli.js +2 -2
- package/dist/commands/env/env-cli.js +529 -0
- package/dist/commands/env/env.js +410 -0
- package/dist/commands/env/secret-cli.js +259 -0
- package/dist/commands/{secret.js → env/secret.js} +6 -47
- package/dist/commands/events.js +4 -4
- package/dist/commands/feedback-cli.js +18 -34
- package/dist/commands/graph/graph-cli.js +132 -0
- package/dist/commands/{graph.js → graph/graph.js} +22 -16
- package/dist/commands/health/checks.js +279 -0
- package/dist/commands/health/html-report.js +448 -0
- package/dist/commands/health.js +189 -266
- package/dist/commands/{consolidate.js → improve/consolidate.js} +63 -38
- package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
- package/dist/commands/{distill.js → improve/distill.js} +39 -18
- package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
- package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
- package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
- package/dist/commands/{extract.js → improve/extract.js} +221 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
- package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
- package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
- package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
- package/dist/commands/{improve.js → improve/improve.js} +672 -292
- package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
- package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
- package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
- package/dist/commands/improve/session-asset.js +248 -0
- package/dist/commands/lint/agent-linter.js +1 -1
- package/dist/commands/lint/base-linter.js +55 -37
- package/dist/commands/lint/command-linter.js +1 -1
- package/dist/commands/lint/default-linter.js +1 -1
- package/dist/commands/lint/env-key-rules.js +1 -1
- package/dist/commands/lint/index.js +19 -25
- package/dist/commands/lint/knowledge-linter.js +1 -1
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +8 -8
- package/dist/commands/lint/skill-linter.js +1 -1
- package/dist/commands/lint/task-linter.js +1 -1
- package/dist/commands/lint/workflow-linter.js +1 -1
- package/dist/commands/lint.js +1 -1
- package/dist/commands/observability-cli.js +244 -0
- package/dist/commands/proposal/drain-policies.js +3 -3
- package/dist/commands/proposal/drain.js +87 -15
- package/dist/commands/proposal/proposal-cli.js +490 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
- package/dist/commands/{propose.js → proposal/propose.js} +11 -11
- package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
- package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
- package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
- package/dist/commands/{curate.js → read/curate.js} +7 -7
- package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
- package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
- package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
- package/dist/commands/read/search-cli.js +207 -0
- package/dist/commands/{search.js → read/search.js} +22 -27
- package/dist/commands/{show.js → read/show.js} +31 -45
- package/dist/commands/registry-cli.js +8 -8
- package/dist/commands/remember.js +14 -10
- package/dist/commands/sources/add-cli.js +293 -0
- package/dist/commands/{history.js → sources/history.js} +27 -25
- package/dist/commands/{info.js → sources/info.js} +6 -6
- package/dist/commands/{init.js → sources/init.js} +6 -6
- package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
- package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
- package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
- package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
- package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
- package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
- package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
- package/dist/commands/sources/sources-cli.js +305 -0
- package/dist/commands/sources/stash-cli.js +219 -0
- package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
- package/dist/commands/tasks/default-tasks.js +173 -0
- package/dist/commands/tasks/tasks-cli.js +210 -0
- package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
- package/dist/commands/wiki-cli.js +307 -0
- package/dist/commands/workflow-cli.js +329 -0
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/assert.js +40 -0
- package/dist/core/asset/asset-create.js +54 -0
- package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
- package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
- package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
- package/dist/core/{markdown.js → asset/markdown.js} +1 -1
- package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
- package/dist/core/best-effort.js +64 -0
- package/dist/core/common.js +32 -18
- package/dist/core/{config-io.js → config/config-io.js} +29 -19
- package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
- package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
- package/dist/core/config/config-types.js +16 -0
- package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
- package/dist/core/{config.js → config/config.js} +10 -8
- package/dist/core/env-secret-ref.js +90 -0
- package/dist/core/errors.js +13 -3
- package/dist/core/events.js +27 -4
- package/dist/core/file-lock.js +1 -1
- package/dist/core/improve-types.js +48 -0
- package/dist/core/lesson-lint.js +2 -2
- package/dist/core/logs-db.js +304 -0
- package/dist/core/paths.js +2 -2
- package/dist/core/ripgrep/install.js +2 -2
- package/dist/core/ripgrep/resolve.js +2 -2
- package/dist/core/state-db.js +195 -60
- package/dist/core/text-truncation.js +148 -0
- package/dist/core/time.js +1 -1
- package/dist/core/write-source.js +98 -85
- package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
- package/dist/indexer/{db.js → db/db.js} +128 -118
- package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
- package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
- package/dist/indexer/ensure-index.js +4 -4
- package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
- package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
- package/dist/indexer/indexer.js +37 -30
- package/dist/indexer/init.js +54 -0
- package/dist/indexer/manifest.js +10 -10
- package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
- package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
- package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
- package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
- package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
- package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
- package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
- package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
- package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
- package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
- package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
- package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
- package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
- package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
- package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
- package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
- package/dist/indexer/{walker.js → walk/walker.js} +4 -3
- package/dist/integrations/agent/builder-shared.js +39 -0
- package/dist/integrations/agent/builders.js +14 -81
- package/dist/integrations/agent/config.js +6 -4
- package/dist/integrations/agent/detect.js +1 -1
- package/dist/integrations/agent/index.js +23 -8
- package/dist/integrations/agent/prompts.js +2 -3
- package/dist/integrations/agent/runner.js +22 -3
- package/dist/integrations/agent/spawn.js +9 -10
- package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
- package/dist/integrations/harnesses/claude/config-import.js +70 -0
- package/dist/integrations/harnesses/claude/index.js +64 -0
- package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
- package/dist/integrations/harnesses/index.js +144 -0
- package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
- package/dist/integrations/harnesses/opencode/config-import.js +82 -0
- package/dist/integrations/harnesses/opencode/index.js +59 -0
- package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
- package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
- package/dist/integrations/harnesses/types.js +43 -0
- package/dist/integrations/lockfile.js +7 -16
- package/dist/integrations/session-logs/index.js +82 -9
- package/dist/llm/call-ai.js +4 -4
- package/dist/llm/client.js +146 -6
- package/dist/llm/embedder.js +6 -6
- package/dist/llm/embedders/local.js +9 -22
- package/dist/llm/embedders/remote.js +2 -2
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +31 -12
- package/dist/llm/index-passes.js +1 -1
- package/dist/llm/memory-infer.js +12 -5
- package/dist/llm/metadata-enhance.js +2 -2
- package/dist/llm/usage-persist.js +77 -0
- package/dist/llm/usage-telemetry.js +103 -0
- package/dist/output/context.js +9 -46
- package/dist/output/html-render.js +73 -0
- package/dist/output/renderers.js +88 -58
- package/dist/output/shapes/curate.js +7 -3
- package/dist/output/shapes/distill.js +7 -3
- package/dist/output/shapes/env-list.js +18 -16
- package/dist/output/shapes/events.js +5 -4
- package/dist/output/shapes/helpers.js +19 -5
- package/dist/output/shapes/history.js +7 -3
- package/dist/output/shapes/passthrough.js +8 -11
- package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
- package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
- package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
- package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
- package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
- package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
- package/dist/output/shapes/registry-search.js +7 -3
- package/dist/output/shapes/registry.js +12 -0
- package/dist/output/shapes/search.js +7 -3
- package/dist/output/shapes/secret-list.js +18 -16
- package/dist/output/shapes/show.js +7 -3
- package/dist/output/shapes.js +55 -30
- package/dist/output/text/add.js +2 -3
- package/dist/output/text/clone.js +2 -3
- package/dist/output/text/config.js +2 -3
- package/dist/output/text/curate.js +4 -3
- package/dist/output/text/distill.js +2 -3
- package/dist/output/text/enable-disable.js +5 -4
- package/dist/output/text/env.js +13 -0
- package/dist/output/text/events.js +5 -4
- package/dist/output/text/feedback.js +4 -3
- package/dist/output/text/helpers.js +123 -40
- package/dist/output/text/history.js +2 -3
- package/dist/output/text/import.js +2 -3
- package/dist/output/text/index.js +2 -3
- package/dist/output/text/info.js +2 -3
- package/dist/output/text/init.js +2 -3
- package/dist/output/text/list.js +2 -3
- package/dist/output/text/proposal/producer.js +9 -0
- package/dist/output/text/proposal/proposal.js +13 -0
- package/dist/output/text/registry-commands.js +8 -7
- package/dist/output/text/registry.js +12 -0
- package/dist/output/text/remember.js +4 -3
- package/dist/output/text/remove.js +2 -3
- package/dist/output/text/save.js +2 -3
- package/dist/output/text/search.js +4 -3
- package/dist/output/text/show.js +4 -3
- package/dist/output/text/update.js +2 -3
- package/dist/output/text/upgrade.js +2 -3
- package/dist/output/text/wiki.js +12 -11
- package/dist/output/text/workflow.js +12 -10
- package/dist/output/text.js +66 -32
- package/dist/registry/build-index.js +11 -10
- package/dist/registry/factory.js +1 -1
- package/dist/registry/origin-resolve.js +1 -1
- package/dist/registry/providers/index.js +2 -2
- package/dist/registry/providers/skills-sh.js +91 -72
- package/dist/registry/providers/static-index.js +75 -52
- package/dist/registry/resolve.js +3 -3
- package/dist/runtime.js +242 -0
- package/dist/scripts/migrate-storage.js +1654 -683
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
- package/dist/setup/detect.js +311 -9
- package/dist/setup/harness-config-import.js +6 -120
- package/dist/setup/setup.js +454 -43
- package/dist/sources/include.js +1 -1
- package/dist/sources/provider-factory.js +2 -2
- package/dist/sources/providers/filesystem.js +3 -3
- package/dist/sources/providers/git.js +9 -9
- package/dist/sources/providers/index.js +4 -4
- package/dist/sources/providers/npm.js +6 -6
- package/dist/sources/providers/provider-utils.js +13 -20
- package/dist/sources/providers/sync-from-ref.js +5 -5
- package/dist/sources/providers/tar-utils.js +2 -2
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +5 -5
- package/dist/sources/website-ingest.js +5 -5
- package/dist/storage/database.js +102 -0
- package/dist/storage/engines/sqlite-migrations.js +42 -0
- package/dist/storage/locations.js +25 -0
- package/dist/storage/repositories/index-db.js +43 -0
- package/dist/storage/repositories/workflow-runs-repository.js +141 -0
- package/dist/tasks/backends/cron.js +4 -4
- package/dist/tasks/backends/exec-utils.js +32 -0
- package/dist/tasks/backends/index.js +3 -3
- package/dist/tasks/backends/launchd.js +7 -14
- package/dist/tasks/backends/schtasks.js +7 -16
- package/dist/tasks/embedded.js +71 -0
- package/dist/tasks/parser.js +2 -2
- package/dist/tasks/resolveAkmBin.js +1 -1
- package/dist/tasks/runner.js +127 -31
- package/dist/tasks/schedule.js +1 -1
- package/dist/tasks/validator.js +7 -7
- package/dist/text-import-hook.mjs +51 -0
- package/dist/version.js +2 -1
- package/dist/wiki/wiki.js +7 -7
- package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
- package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
- package/dist/workflows/cli.js +1 -1
- package/dist/workflows/db.js +54 -32
- package/dist/workflows/parser.js +4 -4
- package/dist/workflows/renderer.js +5 -5
- package/dist/workflows/runtime/agent-identity.js +56 -0
- package/dist/workflows/runtime/checkin.js +57 -0
- package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
- package/dist/workflows/validate-summary.js +82 -0
- package/docs/README.md +1 -1
- package/docs/data-and-telemetry.md +6 -6
- package/package.json +17 -8
- package/dist/commands/add-cli.js +0 -279
- package/dist/commands/env.js +0 -213
- package/dist/integrations/agent/sdk-runner.js +0 -126
- package/dist/output/shapes/vault-list.js +0 -19
- package/dist/output/text/proposal-producer.js +0 -8
- package/dist/output/text/proposal.js +0 -12
- package/dist/output/text/vault.js +0 -16
- /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
- /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
- /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
- /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
- /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
- /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
- /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
- /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
* Values are stored as raw bytes (no quoting, multi-line allowed) so they
|
|
25
25
|
* round-trip byte-exact, unlike env values which forbid literal newlines.
|
|
26
26
|
*/
|
|
27
|
-
import crypto from "node:crypto";
|
|
28
27
|
import fs from "node:fs";
|
|
29
28
|
import path from "node:path";
|
|
30
|
-
import {
|
|
29
|
+
import { writeFileAtomic } from "../../core/common.js";
|
|
30
|
+
import { probeLock, releaseLock, tryAcquireLockSync } from "../../core/file-lock.js";
|
|
31
|
+
import { sleepSync } from "../../runtime.js";
|
|
31
32
|
// ── Write-lock helper ─────────────────────────────────────────────────────────
|
|
32
33
|
/**
|
|
33
34
|
* Acquire an exclusive lock for the given secret path, run `fn`, then release.
|
|
@@ -50,16 +51,7 @@ export function withSecretLock(secretPath, fn) {
|
|
|
50
51
|
: ` Lock file ${lockPath} could not be inspected.`;
|
|
51
52
|
throw new Error(`Could not acquire secret lock for ${secretPath} after 5s.${holderHint} Retry once any other akm secret operation finishes, or remove the stale lock file.`);
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
"function") {
|
|
55
|
-
globalThis.Bun.sleepSync(10);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
let spin = 0;
|
|
59
|
-
while (spin++ < 100_000) {
|
|
60
|
-
/* yield */
|
|
61
|
-
}
|
|
62
|
-
}
|
|
54
|
+
sleepSync(10);
|
|
63
55
|
}
|
|
64
56
|
try {
|
|
65
57
|
return fn();
|
|
@@ -69,40 +61,6 @@ export function withSecretLock(secretPath, fn) {
|
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
63
|
// ── Atomic byte write ──────────────────────────────────────────────────────────
|
|
72
|
-
/**
|
|
73
|
-
* Atomically write `data` to `target` at mode 0600. Unlike `writeFileAtomic`
|
|
74
|
-
* in core/common (string content), this accepts a Buffer so secret bytes
|
|
75
|
-
* round-trip exactly — binary certs and CRLF/LF line endings are preserved.
|
|
76
|
-
*/
|
|
77
|
-
function writeSecretAtomic(target, data) {
|
|
78
|
-
const tmp = `${target}.tmp.${process.pid}.${crypto.randomBytes(8).toString("hex")}`;
|
|
79
|
-
const fd = fs.openSync(tmp, "w", 0o600);
|
|
80
|
-
try {
|
|
81
|
-
fs.writeSync(fd, data);
|
|
82
|
-
try {
|
|
83
|
-
fs.fdatasyncSync(fd);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// Best-effort durability; some pseudo-filesystems lack fdatasync.
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
finally {
|
|
90
|
-
fs.closeSync(fd);
|
|
91
|
-
}
|
|
92
|
-
fs.renameSync(tmp, target);
|
|
93
|
-
try {
|
|
94
|
-
const dirFd = fs.openSync(path.dirname(target), "r");
|
|
95
|
-
try {
|
|
96
|
-
fs.fsyncSync(dirFd);
|
|
97
|
-
}
|
|
98
|
-
finally {
|
|
99
|
-
fs.closeSync(dirFd);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// Directory fsync is unsupported on FAT / some FUSE mounts / Windows.
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
64
|
function ensureParentDir(filePath) {
|
|
107
65
|
const dir = path.dirname(filePath);
|
|
108
66
|
if (!fs.existsSync(dir))
|
|
@@ -153,7 +111,8 @@ export function readValue(secretPath) {
|
|
|
153
111
|
export function setSecret(secretPath, value) {
|
|
154
112
|
ensureParentDir(secretPath);
|
|
155
113
|
withSecretLock(secretPath, () => {
|
|
156
|
-
|
|
114
|
+
// Mode 0600: secrets must never be world-readable, even transiently.
|
|
115
|
+
writeFileAtomic(secretPath, value, 0o600);
|
|
157
116
|
});
|
|
158
117
|
}
|
|
159
118
|
/**
|
package/dist/commands/events.js
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* text-renderer pipeline as the rest of the CLI (no silent
|
|
11
11
|
* `JSON.stringify` fallback).
|
|
12
12
|
*/
|
|
13
|
-
import { parseAssetRef } from "../core/asset-ref";
|
|
14
|
-
import { UsageError } from "../core/errors";
|
|
15
|
-
import { readEvents, tailEvents } from "../core/events";
|
|
16
|
-
import { parseSinceToIso } from "../core/time";
|
|
13
|
+
import { parseAssetRef } from "../core/asset/asset-ref.js";
|
|
14
|
+
import { UsageError } from "../core/errors.js";
|
|
15
|
+
import { readEvents, tailEvents } from "../core/events.js";
|
|
16
|
+
import { parseSinceToIso } from "../core/time.js";
|
|
17
17
|
/**
|
|
18
18
|
* Parse `--since` accepting either a byte-offset cursor (`@offset:<int>`) for
|
|
19
19
|
* cross-process resumption, or a timestamp / epoch-ms (the existing form).
|
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
|
-
import { output, parseAllFlagValues, runWithJsonErrors } from "../cli/shared";
|
|
7
|
-
import { parseAssetRef } from "../core/asset-ref";
|
|
8
|
-
import { assembleAsset } from "../core/asset-serialize";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { warn } from "../core/warn";
|
|
15
|
-
import { applyFeedbackToUtilityScore, closeDatabase, findEntryIdByRef, openExistingDatabase } from "../indexer/db";
|
|
16
|
-
import { ensureIndex } from "../indexer/ensure-index";
|
|
17
|
-
import { resolveSourceEntries } from "../indexer/search-source";
|
|
18
|
-
import { insertUsageEvent } from "../indexer/usage-events";
|
|
6
|
+
import { output, parseAllFlagValues, runWithJsonErrors } from "../cli/shared.js";
|
|
7
|
+
import { parseAssetRef } from "../core/asset/asset-ref.js";
|
|
8
|
+
import { assembleAsset } from "../core/asset/asset-serialize.js";
|
|
9
|
+
import { parseFrontmatter, parseFrontmatterBlock } from "../core/asset/frontmatter.js";
|
|
10
|
+
import { writeFileAtomic } from "../core/common.js";
|
|
11
|
+
import { FEEDBACK_FAILURE_MODES, loadConfig } from "../core/config/config.js";
|
|
12
|
+
import { UsageError } from "../core/errors.js";
|
|
13
|
+
import { appendEvent } from "../core/events.js";
|
|
14
|
+
import { warn } from "../core/warn.js";
|
|
15
|
+
import { applyFeedbackToUtilityScore, closeDatabase, findEntryIdByRef, getEntryFilePathById, openExistingDatabase, } from "../indexer/db/db.js";
|
|
16
|
+
import { ensureIndex } from "../indexer/ensure-index.js";
|
|
17
|
+
import { resolveSourceEntries } from "../indexer/search/search-source.js";
|
|
18
|
+
import { countFeedbackSignals, insertUsageEvent } from "../indexer/usage/usage-events.js";
|
|
19
19
|
// ── Tag validation ────────────────────────────────────────────────────────────
|
|
20
20
|
const TAG_KEY_RE = /^[a-z_][a-z0-9_]*$/;
|
|
21
21
|
const MAX_FEEDBACK_TAGS = 10;
|
|
@@ -64,12 +64,12 @@ function appendLessonStrength(type, name, feedbackRef) {
|
|
|
64
64
|
warn(`[feedback] --applied-to: lesson ${ref} is not in the index.`);
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
|
-
const
|
|
68
|
-
if (!
|
|
67
|
+
const resolvedPath = getEntryFilePathById(db, entryId);
|
|
68
|
+
if (!resolvedPath) {
|
|
69
69
|
warn(`[feedback] --applied-to: cannot resolve file path for ${ref}.`);
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
|
-
filePath =
|
|
72
|
+
filePath = resolvedPath;
|
|
73
73
|
}
|
|
74
74
|
finally {
|
|
75
75
|
closeDatabase(db);
|
|
@@ -136,7 +136,6 @@ export const feedbackCommand = defineCommand({
|
|
|
136
136
|
type: "string",
|
|
137
137
|
description: "Reason for the feedback (required for negative feedback by default; used by distillation)",
|
|
138
138
|
},
|
|
139
|
-
note: { type: "string", description: "Alias for --reason (backward-compatible, prefer --reason)" },
|
|
140
139
|
"failure-mode": {
|
|
141
140
|
type: "string",
|
|
142
141
|
description: `Structured failure-mode taxonomy for negative feedback (F-3 / #384). ` +
|
|
@@ -168,14 +167,7 @@ export const feedbackCommand = defineCommand({
|
|
|
168
167
|
throw new UsageError("Specify --positive or --negative.");
|
|
169
168
|
}
|
|
170
169
|
const signal = args.positive ? "positive" : "negative";
|
|
171
|
-
|
|
172
|
-
// 0.9.0). Warn on stderr when it is used as the sole source (i.e. without
|
|
173
|
-
// an explicit `--reason`). Warnings go to stderr only so JSON stdout
|
|
174
|
-
// consumers are unaffected.
|
|
175
|
-
if (args.note !== undefined && args.reason === undefined) {
|
|
176
|
-
warn("warning: '--note' is deprecated for 'akm feedback'; use '--reason'. Removed in 0.9.0.");
|
|
177
|
-
}
|
|
178
|
-
const reason = args.reason ?? args.note;
|
|
170
|
+
const reason = args.reason;
|
|
179
171
|
// F-3 / #384: Validate --failure-mode against the curated enum.
|
|
180
172
|
const failureMode = args["failure-mode"]?.trim() || undefined;
|
|
181
173
|
if (failureMode) {
|
|
@@ -242,15 +234,7 @@ export const feedbackCommand = defineCommand({
|
|
|
242
234
|
// usage_events so the delta reflects the entire signal history.
|
|
243
235
|
// Uses MemRL bounded-step EMA (F-5 / #386, arXiv:2601.03192).
|
|
244
236
|
try {
|
|
245
|
-
const
|
|
246
|
-
.prepare(`SELECT
|
|
247
|
-
SUM(CASE WHEN signal = 'positive' THEN 1 ELSE 0 END) AS pos,
|
|
248
|
-
SUM(CASE WHEN signal = 'negative' THEN 1 ELSE 0 END) AS neg
|
|
249
|
-
FROM usage_events
|
|
250
|
-
WHERE event_type = 'feedback' AND entry_id = ?`)
|
|
251
|
-
.get(entryId);
|
|
252
|
-
const pos = counts?.pos ?? 0;
|
|
253
|
-
const neg = counts?.neg ?? 0;
|
|
237
|
+
const { pos, neg } = countFeedbackSignals(db, entryId);
|
|
254
238
|
utilityResult = applyFeedbackToUtilityScore(db, entryId, pos, neg);
|
|
255
239
|
}
|
|
256
240
|
catch {
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* `akm graph` command family. Extracted verbatim from src/cli.ts (WS6) so the
|
|
6
|
+
* God Module shrinks; the `main.subCommands.graph` key and every subcommand's
|
|
7
|
+
* args/output shape are byte-identical. Each handler is migrated to
|
|
8
|
+
* `defineJsonCommand`, which wraps the body in `runWithJsonErrors` and emits the
|
|
9
|
+
* same JSON envelope (stdout/stderr/exit-code) as the inline `runWithJsonErrors`
|
|
10
|
+
* form it replaces.
|
|
11
|
+
*/
|
|
12
|
+
import { defineCommand } from "citty";
|
|
13
|
+
import { hasSubcommand, parsePositiveIntFlag } from "../../cli/parse-args.js";
|
|
14
|
+
import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
|
|
15
|
+
import { akmGraphEntities, akmGraphEntity, akmGraphExport, akmGraphOrphans, akmGraphRelated, akmGraphRelations, akmGraphSummary, akmGraphUpdate, } from "./graph.js";
|
|
16
|
+
// Single source of truth: the routing set is derived from the subCommands keys
|
|
17
|
+
// (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
|
|
18
|
+
const graphSubCommands = {
|
|
19
|
+
summary: defineJsonCommand({
|
|
20
|
+
meta: { name: "summary", description: "Show entity-graph counts and quality telemetry" },
|
|
21
|
+
args: {
|
|
22
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
23
|
+
},
|
|
24
|
+
run({ args }) {
|
|
25
|
+
output("graph-summary", akmGraphSummary({ source: args.source }));
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
entities: defineJsonCommand({
|
|
29
|
+
meta: { name: "entities", description: "List entities with per-file occurrence counts" },
|
|
30
|
+
args: {
|
|
31
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
32
|
+
limit: { type: "string", description: "Maximum entities to return" },
|
|
33
|
+
},
|
|
34
|
+
run({ args }) {
|
|
35
|
+
output("graph-entities", akmGraphEntities({ source: args.source, limit: parsePositiveIntFlag(args.limit ?? undefined) }));
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
relations: defineJsonCommand({
|
|
39
|
+
meta: { name: "relations", description: "List relations with occurrence counts" },
|
|
40
|
+
args: {
|
|
41
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
42
|
+
limit: { type: "string", description: "Maximum relations to return" },
|
|
43
|
+
},
|
|
44
|
+
run({ args }) {
|
|
45
|
+
output("graph-relations", akmGraphRelations({ source: args.source, limit: parsePositiveIntFlag(args.limit ?? undefined) }));
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
related: defineJsonCommand({
|
|
49
|
+
meta: { name: "related", description: "Show graph-related neighboring assets for a ref" },
|
|
50
|
+
args: {
|
|
51
|
+
ref: { type: "positional", description: "Asset ref", required: true },
|
|
52
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
53
|
+
limit: { type: "string", description: "Maximum related assets to return" },
|
|
54
|
+
},
|
|
55
|
+
async run({ args }) {
|
|
56
|
+
output("graph-related", await akmGraphRelated({
|
|
57
|
+
ref: args.ref ?? "",
|
|
58
|
+
source: args.source,
|
|
59
|
+
limit: parsePositiveIntFlag(args.limit ?? undefined),
|
|
60
|
+
}));
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
entity: defineJsonCommand({
|
|
64
|
+
meta: { name: "entity", description: "List assets that contain the given entity" },
|
|
65
|
+
args: {
|
|
66
|
+
name: { type: "positional", description: "Entity name", required: true },
|
|
67
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
68
|
+
limit: { type: "string", description: "Maximum matches to return" },
|
|
69
|
+
},
|
|
70
|
+
run({ args }) {
|
|
71
|
+
output("graph-entity", akmGraphEntity({
|
|
72
|
+
name: args.name ?? "",
|
|
73
|
+
source: args.source,
|
|
74
|
+
limit: parsePositiveIntFlag(args.limit ?? undefined),
|
|
75
|
+
}));
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
orphans: defineJsonCommand({
|
|
79
|
+
meta: { name: "orphans", description: "List assets with no extracted graph entities" },
|
|
80
|
+
args: {
|
|
81
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
82
|
+
limit: { type: "string", description: "Maximum orphans to return" },
|
|
83
|
+
},
|
|
84
|
+
run({ args }) {
|
|
85
|
+
output("graph-orphans", akmGraphOrphans({ source: args.source, limit: parsePositiveIntFlag(args.limit ?? undefined) }));
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
export: defineJsonCommand({
|
|
89
|
+
meta: { name: "export", description: "Export graph artifact as JSON or JSONL" },
|
|
90
|
+
args: {
|
|
91
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
92
|
+
out: { type: "string", description: "Output path" },
|
|
93
|
+
format: { type: "string", description: "Export format (json|jsonl)", default: "json" },
|
|
94
|
+
},
|
|
95
|
+
run({ args }) {
|
|
96
|
+
output("graph-export", akmGraphExport({
|
|
97
|
+
source: args.source,
|
|
98
|
+
out: args.out ?? "",
|
|
99
|
+
format: args.format,
|
|
100
|
+
}));
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
update: defineJsonCommand({
|
|
104
|
+
meta: { name: "update", description: "Re-run graph extraction, optionally scoped to specific asset refs" },
|
|
105
|
+
args: {
|
|
106
|
+
refs: {
|
|
107
|
+
type: "positional",
|
|
108
|
+
description: "Zero or more asset refs to scope extraction (omit for a full re-extract)",
|
|
109
|
+
required: false,
|
|
110
|
+
default: "",
|
|
111
|
+
},
|
|
112
|
+
source: { type: "string", description: "Source name/path (default: primary stash source)" },
|
|
113
|
+
},
|
|
114
|
+
async run({ args }) {
|
|
115
|
+
// `refs` is a single positional; collect remaining argv tokens as well.
|
|
116
|
+
const rawRefs = [args.refs, ...(Array.isArray(args._) ? args._ : [])].filter((r) => typeof r === "string" && r.trim().length > 0);
|
|
117
|
+
output("graph-update", await akmGraphUpdate({ refs: rawRefs.length > 0 ? rawRefs : undefined, source: args.source }));
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
const GRAPH_SUBCOMMAND_SET = new Set(Object.keys(graphSubCommands));
|
|
122
|
+
export const graphCommand = defineCommand({
|
|
123
|
+
meta: { name: "graph", description: "Inspect the indexed entity graph stored in SQLite" },
|
|
124
|
+
subCommands: graphSubCommands,
|
|
125
|
+
run({ args }) {
|
|
126
|
+
return runWithJsonErrors(() => {
|
|
127
|
+
if (hasSubcommand(args, GRAPH_SUBCOMMAND_SET))
|
|
128
|
+
return;
|
|
129
|
+
output("graph-summary", akmGraphSummary());
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
});
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { parseAssetRef } from "
|
|
7
|
-
import { loadConfig } from "
|
|
8
|
-
import { NotFoundError, UsageError } from "
|
|
9
|
-
import { getDbPath } from "
|
|
10
|
-
import { warn } from "
|
|
11
|
-
import { closeDatabase, findEntryIdByRef, getEntryById, openDatabase, openExistingDatabase } from "
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { runGraphExtractionPass } from "
|
|
15
|
-
import { lookup } from "
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
6
|
+
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
7
|
+
import { loadConfig } from "../../core/config/config.js";
|
|
8
|
+
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
9
|
+
import { getDbPath } from "../../core/paths.js";
|
|
10
|
+
import { warn } from "../../core/warn.js";
|
|
11
|
+
import { closeDatabase, findEntryIdByRef, getEntryById, getEntryRefRowsForStashRoot, openDatabase, openExistingDatabase, } from "../../indexer/db/db.js";
|
|
12
|
+
import { loadStoredGraphSnapshot } from "../../indexer/db/graph-db.js";
|
|
13
|
+
import { listRelatedPathsForFile } from "../../indexer/graph/graph-boost.js";
|
|
14
|
+
import { runGraphExtractionPass } from "../../indexer/graph/graph-extraction.js";
|
|
15
|
+
import { lookup } from "../../indexer/indexer.js";
|
|
16
|
+
import { findSourceForPath, resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
17
|
+
import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
|
|
18
18
|
function resolveGraphStashPath(source) {
|
|
19
19
|
const sources = resolveSourceEntries(undefined, loadConfig());
|
|
20
20
|
if (sources.length === 0) {
|
|
@@ -243,9 +243,7 @@ function normalizeGraphName(value) {
|
|
|
243
243
|
return value.trim().toLowerCase();
|
|
244
244
|
}
|
|
245
245
|
function buildRefByPath(stashRoot, db) {
|
|
246
|
-
const rows = db
|
|
247
|
-
.prepare("SELECT file_path, entry_json FROM entries WHERE stash_dir = ? OR file_path LIKE ?")
|
|
248
|
-
.all(stashRoot, `${stashRoot}%`);
|
|
246
|
+
const rows = getEntryRefRowsForStashRoot(db, stashRoot);
|
|
249
247
|
const map = new Map();
|
|
250
248
|
for (const row of rows) {
|
|
251
249
|
if (map.has(row.file_path))
|
|
@@ -432,7 +430,15 @@ export async function akmGraphUpdate(options) {
|
|
|
432
430
|
const file = path.basename(event.currentPath);
|
|
433
431
|
warn(`[graph] extracting ${event.processed}/${event.total} ${file}`);
|
|
434
432
|
};
|
|
435
|
-
const result = await extractionFn(
|
|
433
|
+
const result = await extractionFn({
|
|
434
|
+
config,
|
|
435
|
+
sources,
|
|
436
|
+
signal: undefined,
|
|
437
|
+
db,
|
|
438
|
+
reEnrich: false,
|
|
439
|
+
onProgress,
|
|
440
|
+
options: passOptions,
|
|
441
|
+
});
|
|
436
442
|
const durationMs = Date.now() - startMs;
|
|
437
443
|
return {
|
|
438
444
|
shape: "graph-update",
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { loadConfig } from "../../core/config/config.js";
|
|
6
|
+
import { detectAgentCliProfiles, requireAgentProfile } from "../../integrations/agent/index.js";
|
|
7
|
+
const ACTIVE_RUN_WARN_MS = 15 * 60 * 1000;
|
|
8
|
+
/**
|
|
9
|
+
* Probe the configured agent profile. Self-contained (reads config + PATH); the
|
|
10
|
+
* only check that performs IO at dispatch time, preserving the original inline
|
|
11
|
+
* `runAgentProbe()` call site behaviour exactly.
|
|
12
|
+
*/
|
|
13
|
+
export function runAgentProbe() {
|
|
14
|
+
const config = loadConfig();
|
|
15
|
+
// v2: check profiles.agent first
|
|
16
|
+
if (config.profiles?.agent) {
|
|
17
|
+
const defaultName = config.defaults?.agent;
|
|
18
|
+
const profileCount = Object.keys(config.profiles.agent).length;
|
|
19
|
+
if (profileCount === 0) {
|
|
20
|
+
return {
|
|
21
|
+
name: "agent-profile",
|
|
22
|
+
kind: "deterministic",
|
|
23
|
+
status: "unknown",
|
|
24
|
+
confidence: "high",
|
|
25
|
+
message: "No agent profiles configured in profiles.agent.",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const profileName = defaultName ?? Object.keys(config.profiles.agent)[0];
|
|
29
|
+
const profile = config.profiles.agent[profileName];
|
|
30
|
+
return {
|
|
31
|
+
name: "agent-profile",
|
|
32
|
+
kind: "deterministic",
|
|
33
|
+
status: "pass",
|
|
34
|
+
confidence: "high",
|
|
35
|
+
message: `v2 agent profile "${profileName}" configured (platform: ${profile?.platform ?? "unknown"}).`,
|
|
36
|
+
evidence: { profile: profileName, platform: profile?.platform, profileCount },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (!config.profiles?.agent && !config.defaults?.agent) {
|
|
40
|
+
return {
|
|
41
|
+
name: "agent-profile",
|
|
42
|
+
kind: "deterministic",
|
|
43
|
+
status: "unknown",
|
|
44
|
+
confidence: "high",
|
|
45
|
+
message: "No agent config present.",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
let profile;
|
|
49
|
+
try {
|
|
50
|
+
profile = requireAgentProfile(config);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
name: "agent-profile",
|
|
55
|
+
kind: "deterministic",
|
|
56
|
+
status: "warn",
|
|
57
|
+
confidence: "high",
|
|
58
|
+
message: error instanceof Error ? error.message : String(error),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (profile.sdkMode === true) {
|
|
62
|
+
return {
|
|
63
|
+
name: "agent-profile",
|
|
64
|
+
kind: "deterministic",
|
|
65
|
+
status: profile.model ? "pass" : "warn",
|
|
66
|
+
confidence: "high",
|
|
67
|
+
message: profile.model
|
|
68
|
+
? `SDK mode profile "${profile.name}" is configured.`
|
|
69
|
+
: `SDK mode profile "${profile.name}" has no explicit model.`,
|
|
70
|
+
evidence: { profile: profile.name, sdkMode: true, model: profile.model ?? null },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const detections = detectAgentCliProfiles(config);
|
|
74
|
+
const detection = detections.find((entry) => entry.name === profile.name);
|
|
75
|
+
if (!detection?.available) {
|
|
76
|
+
return {
|
|
77
|
+
name: "agent-profile",
|
|
78
|
+
kind: "deterministic",
|
|
79
|
+
status: "fail",
|
|
80
|
+
confidence: "high",
|
|
81
|
+
message: `Default agent profile "${profile.name}" is not available on PATH.`,
|
|
82
|
+
evidence: { profile: profile.name, bin: profile.bin },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const version = spawnSync(profile.bin, ["--version"], { encoding: "utf8", timeout: 5_000 });
|
|
86
|
+
if ((version.status ?? 1) !== 0) {
|
|
87
|
+
return {
|
|
88
|
+
name: "agent-profile",
|
|
89
|
+
kind: "deterministic",
|
|
90
|
+
status: "warn",
|
|
91
|
+
confidence: "medium",
|
|
92
|
+
message: `Agent binary "${profile.bin}" was found but \`--version\` failed.`,
|
|
93
|
+
evidence: {
|
|
94
|
+
profile: profile.name,
|
|
95
|
+
bin: profile.bin,
|
|
96
|
+
exitCode: version.status ?? null,
|
|
97
|
+
stderr: (version.stderr ?? "").trim(),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
name: "agent-profile",
|
|
103
|
+
kind: "deterministic",
|
|
104
|
+
status: "pass",
|
|
105
|
+
confidence: "high",
|
|
106
|
+
message: `Agent profile "${profile.name}" is available.`,
|
|
107
|
+
evidence: { profile: profile.name, bin: profile.bin, version: (version.stdout ?? "").trim() },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The ordered health-check registry. ORDER IS LOAD-BEARING: `akmHealth`
|
|
112
|
+
* iterates this array and appends to hardChecks/advisories in sequence, so the
|
|
113
|
+
* declaration order below is exactly the emission order (hard checks first in
|
|
114
|
+
* their array, advisories in theirs). Each `run` is a verbatim copy of the
|
|
115
|
+
* corresponding former inline block.
|
|
116
|
+
*/
|
|
117
|
+
export const HEALTH_CHECKS = [
|
|
118
|
+
{
|
|
119
|
+
name: "state-db-schema",
|
|
120
|
+
channel: "hard",
|
|
121
|
+
run: (ctx) => ({
|
|
122
|
+
name: "state-db-schema",
|
|
123
|
+
kind: "deterministic",
|
|
124
|
+
status: ctx.missingTables.length === 0 ? "pass" : "fail",
|
|
125
|
+
confidence: "high",
|
|
126
|
+
message: ctx.missingTables.length === 0
|
|
127
|
+
? "state.db opened and required tables are present."
|
|
128
|
+
: `state.db is missing required tables: ${ctx.missingTables.join(", ")}`,
|
|
129
|
+
evidence: { path: ctx.stateDbPath, tables: ctx.tableNames },
|
|
130
|
+
}),
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "state-db-round-trip",
|
|
134
|
+
channel: "hard",
|
|
135
|
+
run: (ctx) => ({
|
|
136
|
+
name: "state-db-round-trip",
|
|
137
|
+
kind: "deterministic",
|
|
138
|
+
status: ctx.probe.ok ? "pass" : "fail",
|
|
139
|
+
confidence: "high",
|
|
140
|
+
message: ctx.probe.ok
|
|
141
|
+
? "state.db append/read round-trip succeeded."
|
|
142
|
+
: `state.db round-trip failed: ${ctx.probe.error}`,
|
|
143
|
+
evidence: { path: ctx.stateDbPath, durationMs: ctx.probe.durationMs },
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "task-history-read",
|
|
148
|
+
channel: "hard",
|
|
149
|
+
run: (ctx) => ({
|
|
150
|
+
name: "task-history-read",
|
|
151
|
+
kind: "deterministic",
|
|
152
|
+
status: "pass",
|
|
153
|
+
confidence: "high",
|
|
154
|
+
message: `Read ${ctx.taskRowCount} task-history row(s) since ${ctx.since}.`,
|
|
155
|
+
evidence: { rows: ctx.taskRowCount, since: ctx.since },
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "task-log-backing",
|
|
160
|
+
channel: "hard",
|
|
161
|
+
run: (ctx) => ({
|
|
162
|
+
name: "task-log-backing",
|
|
163
|
+
kind: "deterministic",
|
|
164
|
+
status: ctx.logBackingRate === 1 ? "pass" : "fail",
|
|
165
|
+
confidence: "high",
|
|
166
|
+
message: ctx.logBackingRate === 1
|
|
167
|
+
? "Every task_history log_path resolved on disk."
|
|
168
|
+
: `${ctx.taskRowsWithLogsCount - ctx.existingLogRowsCount} task log(s) referenced in task_history are missing.`,
|
|
169
|
+
evidence: { totalWithLogs: ctx.taskRowsWithLogsCount, existingLogs: ctx.existingLogRowsCount },
|
|
170
|
+
}),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "active-runs",
|
|
174
|
+
channel: "hard",
|
|
175
|
+
run: (ctx) => ({
|
|
176
|
+
name: "active-runs",
|
|
177
|
+
kind: "deterministic",
|
|
178
|
+
status: ctx.stuckActiveRuns === 0 ? "pass" : "warn",
|
|
179
|
+
confidence: "high",
|
|
180
|
+
message: ctx.stuckActiveRuns === 0
|
|
181
|
+
? "No active task runs exceeded the stale threshold."
|
|
182
|
+
: `${ctx.stuckActiveRuns} active task run(s) are older than ${Math.round(ACTIVE_RUN_WARN_MS / 60000)} minutes.`,
|
|
183
|
+
evidence: { stuckActiveRuns: ctx.stuckActiveRuns },
|
|
184
|
+
}),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "agent-profile",
|
|
188
|
+
channel: "hard",
|
|
189
|
+
run: () => runAgentProbe(),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "semantic-search-runtime",
|
|
193
|
+
channel: "advisory",
|
|
194
|
+
run: (ctx) => ({
|
|
195
|
+
name: "semantic-search-runtime",
|
|
196
|
+
kind: "deterministic",
|
|
197
|
+
status: !ctx.semanticStatus ||
|
|
198
|
+
ctx.semanticStatus.status === "pending" ||
|
|
199
|
+
ctx.semanticStatus.status === "ready-js" ||
|
|
200
|
+
ctx.semanticStatus.status === "ready-vec"
|
|
201
|
+
? "pass"
|
|
202
|
+
: "warn",
|
|
203
|
+
confidence: "medium",
|
|
204
|
+
message: ctx.semanticStatus
|
|
205
|
+
? `Semantic search status: ${ctx.semanticStatus.status}`
|
|
206
|
+
: "No semantic-search runtime status recorded yet.",
|
|
207
|
+
evidence: ctx.semanticStatus ? { ...ctx.semanticStatus } : undefined,
|
|
208
|
+
}),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
// session-log-failures: demoted to informational — the ERROR_PATTERNS regex
|
|
212
|
+
// scans pre-LLM session text and produces false positives on diagnostic
|
|
213
|
+
// conversation. It does not gate the real extraction pipeline (akmExtract).
|
|
214
|
+
// Never triggers warn; kept for backward-compat visibility only.
|
|
215
|
+
name: "session-log-failures",
|
|
216
|
+
channel: "advisory",
|
|
217
|
+
run: (ctx) => ({
|
|
218
|
+
name: "session-log-failures",
|
|
219
|
+
kind: "heuristic",
|
|
220
|
+
status: "pass",
|
|
221
|
+
confidence: "low",
|
|
222
|
+
message: ctx.sessionLogEntries.length === 0
|
|
223
|
+
? "No repeated external session-log failure patterns were detected."
|
|
224
|
+
: `${ctx.sessionLogEntries.length} raw session-log keyword match(es) detected (pre-LLM, informational only).`,
|
|
225
|
+
evidence: { candidates: ctx.sessionLogEntries.slice(0, 5) },
|
|
226
|
+
}),
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "session-extraction",
|
|
230
|
+
channel: "advisory",
|
|
231
|
+
run: (ctx) => {
|
|
232
|
+
const sx = ctx.sessionExtraction;
|
|
233
|
+
const sxWarnReasons = [];
|
|
234
|
+
if (sx.warnings > 0)
|
|
235
|
+
sxWarnReasons.push(`${sx.warnings} harness error(s)`);
|
|
236
|
+
if (sx.ran && sx.sessionsScanned >= 5 && sx.proposalsCreated === 0)
|
|
237
|
+
sxWarnReasons.push("no proposals generated across scanned sessions");
|
|
238
|
+
return {
|
|
239
|
+
name: "session-extraction",
|
|
240
|
+
kind: "heuristic",
|
|
241
|
+
status: sxWarnReasons.length > 0 ? "warn" : "pass",
|
|
242
|
+
confidence: sx.ran ? "medium" : "low",
|
|
243
|
+
message: sx.ran
|
|
244
|
+
? sxWarnReasons.length > 0
|
|
245
|
+
? `Session extraction degraded: ${sxWarnReasons.join("; ")}.`
|
|
246
|
+
: `Session extraction healthy: ${sx.sessionsScanned} scanned, ${sx.sessionsExtracted} extracted, ${sx.proposalsCreated} proposal(s) created.`
|
|
247
|
+
: "Session extraction not active (feature disabled or no harness available).",
|
|
248
|
+
evidence: {
|
|
249
|
+
ran: sx.ran,
|
|
250
|
+
sessionsScanned: sx.sessionsScanned,
|
|
251
|
+
sessionsExtracted: sx.sessionsExtracted,
|
|
252
|
+
sessionsSkipped: sx.sessionsSkipped,
|
|
253
|
+
proposalsCreated: sx.proposalsCreated,
|
|
254
|
+
warnings: sx.warnings,
|
|
255
|
+
durationMs: sx.durationMs,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: "auto-accept-validation",
|
|
262
|
+
channel: "advisory",
|
|
263
|
+
run: (ctx) => {
|
|
264
|
+
const aa = ctx.autoAccept;
|
|
265
|
+
return {
|
|
266
|
+
name: "auto-accept-validation",
|
|
267
|
+
kind: "heuristic",
|
|
268
|
+
status: aa.validationFailed > 0 ? "warn" : "pass",
|
|
269
|
+
confidence: aa.promoted + aa.validationFailed > 0 ? "high" : "low",
|
|
270
|
+
message: aa.validationFailed > 0
|
|
271
|
+
? `${aa.validationFailed} proposal(s) passed confidence threshold but failed auto-accept validation (truncated description, invalid frontmatter, etc.) — they remain in the queue for manual review.`
|
|
272
|
+
: aa.promoted > 0
|
|
273
|
+
? `Auto-accept healthy: ${aa.promoted} proposal(s) promoted, 0 validation failures.`
|
|
274
|
+
: "Auto-accept gate did not run (disabled or no proposals above threshold).",
|
|
275
|
+
evidence: { promoted: aa.promoted, validationFailed: aa.validationFailed },
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
];
|