akm-cli 0.8.2 → 0.9.0-beta.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 +187 -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/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 +51 -14
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +171 -3862
- 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 +240 -3
- package/dist/commands/config-edit.js +344 -0
- 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.js +94 -262
- package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
- 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} +185 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +4 -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} +509 -245
- 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/{reflect.js → improve/reflect.js} +33 -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 +15 -10
- package/dist/commands/proposal/proposal-cli.js +478 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +5 -5
- 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 +13 -7
- 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 +8 -8
- 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} +45 -1
- 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/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 +88 -46
- 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} +126 -116
- 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} +92 -23
- 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} +16 -1
- 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 +131 -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/output/context.js +6 -44
- 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 +2 -4
- 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 +54 -39
- 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 +1594 -673
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +240 -166
- 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 +28 -15
- 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 +50 -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 +16 -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
package/dist/commands/health.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { spawnSync } from "node:child_process";
|
|
5
4
|
import fs from "node:fs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { getExecutionLogCandidates } from "../integrations/session-logs";
|
|
5
|
+
import { ConfigError, UsageError } from "../core/errors.js";
|
|
6
|
+
import { appendEvent, readEvents } from "../core/events.js";
|
|
7
|
+
import { getStateDbPathInDataDir } from "../core/paths.js";
|
|
8
|
+
import { listExistingTableNames, openStateDatabase, queryCompletedTaskIntervals, queryImproveRuns, queryTaskHistory, } from "../core/state-db.js";
|
|
9
|
+
import { parseSinceToIso } from "../core/time.js";
|
|
10
|
+
import { readSemanticStatus } from "../indexer/search/semantic-status.js";
|
|
11
|
+
import { getExecutionLogCandidates } from "../integrations/session-logs/index.js";
|
|
12
|
+
import { HEALTH_CHECKS } from "./health/checks.js";
|
|
15
13
|
const DEFAULT_SINCE_MS = 24 * 60 * 60 * 1000;
|
|
16
14
|
const IMPROVE_COMPLETED_EVENT = "improve_completed";
|
|
17
15
|
const HEALTH_PROBE_EVENT = "health_probe";
|
|
@@ -104,6 +102,7 @@ function createUnknownImproveMetrics() {
|
|
|
104
102
|
ran: false,
|
|
105
103
|
considered: 0,
|
|
106
104
|
cacheHits: 0,
|
|
105
|
+
retryAttempts: 0,
|
|
107
106
|
freshAttempts: 0,
|
|
108
107
|
splitParents: 0,
|
|
109
108
|
written: 0,
|
|
@@ -111,6 +110,7 @@ function createUnknownImproveMetrics() {
|
|
|
111
110
|
skippedChildExists: 0,
|
|
112
111
|
skippedAborted: 0,
|
|
113
112
|
unaccounted: 0,
|
|
113
|
+
htmlErrorCount: 0,
|
|
114
114
|
yieldEligibleRuns: 0,
|
|
115
115
|
yieldEligibleConsidered: 0,
|
|
116
116
|
yieldEligibleWritten: 0,
|
|
@@ -128,6 +128,8 @@ function createUnknownImproveMetrics() {
|
|
|
128
128
|
cacheHitRate: 0,
|
|
129
129
|
truncations: 0,
|
|
130
130
|
failures: 0,
|
|
131
|
+
htmlErrors: 0,
|
|
132
|
+
retryAttempts: 0,
|
|
131
133
|
durationMs: 0,
|
|
132
134
|
},
|
|
133
135
|
sessionExtraction: {
|
|
@@ -337,18 +339,26 @@ function projectRunMetrics(result) {
|
|
|
337
339
|
metrics.consolidation.mergedSecondaries += toFiniteNumber(consolidation.mergedSecondaries);
|
|
338
340
|
metrics.consolidation.failedChunkMemories += toFiniteNumber(consolidation.failedChunkMemories);
|
|
339
341
|
// Structured emitter (new on this branch): consolidate.ts now pushes
|
|
340
|
-
// `{
|
|
341
|
-
// post-LLM rejection.
|
|
342
|
-
//
|
|
342
|
+
// per-ref grouped `{ref, skips: [{op, reason}]}` entries to `skipReasons`
|
|
343
|
+
// for every deterministic post-LLM rejection. Each ref appears once but
|
|
344
|
+
// may carry multiple skips; aggregate every reason. Pre-fix envelopes have
|
|
345
|
+
// neither field, so be defensive.
|
|
343
346
|
const skipReasons = consolidation.skipReasons;
|
|
344
347
|
if (Array.isArray(skipReasons)) {
|
|
345
348
|
for (const entry of skipReasons) {
|
|
346
349
|
if (!entry || typeof entry !== "object")
|
|
347
350
|
continue;
|
|
348
|
-
const
|
|
349
|
-
if (
|
|
351
|
+
const skips = entry.skips;
|
|
352
|
+
if (!Array.isArray(skips))
|
|
350
353
|
continue;
|
|
351
|
-
|
|
354
|
+
for (const skip of skips) {
|
|
355
|
+
if (!skip || typeof skip !== "object")
|
|
356
|
+
continue;
|
|
357
|
+
const reason = skip.reason;
|
|
358
|
+
if (typeof reason !== "string" || !reason.trim())
|
|
359
|
+
continue;
|
|
360
|
+
metrics.consolidation.skipReasons[reason] = (metrics.consolidation.skipReasons[reason] ?? 0) + 1;
|
|
361
|
+
}
|
|
352
362
|
}
|
|
353
363
|
}
|
|
354
364
|
}
|
|
@@ -358,12 +368,14 @@ function projectRunMetrics(result) {
|
|
|
358
368
|
const writtenFacts = toFiniteNumber(memoryInference.writtenFacts);
|
|
359
369
|
metrics.memoryInference.considered += considered;
|
|
360
370
|
metrics.memoryInference.cacheHits += toFiniteNumber(memoryInference.cacheHits);
|
|
371
|
+
metrics.memoryInference.retryAttempts += toFiniteNumber(memoryInference.retryAttempts);
|
|
361
372
|
metrics.memoryInference.splitParents += toFiniteNumber(memoryInference.splitParents);
|
|
362
373
|
metrics.memoryInference.written += writtenFacts;
|
|
363
374
|
metrics.memoryInference.skippedNoFacts += toFiniteNumber(memoryInference.skippedNoFacts);
|
|
364
375
|
metrics.memoryInference.skippedChildExists += toFiniteNumber(memoryInference.skippedChildExists);
|
|
365
376
|
metrics.memoryInference.skippedAborted += toFiniteNumber(memoryInference.skippedAborted);
|
|
366
377
|
metrics.memoryInference.unaccounted += toFiniteNumber(memoryInference.unaccounted);
|
|
378
|
+
metrics.memoryInference.htmlErrorCount += toFiniteNumber(memoryInference.htmlErrorCount);
|
|
367
379
|
// Yield-rate gating: pre-cache-feature envelopes lack the `cacheHits`
|
|
368
380
|
// field entirely. Treating their `considered` as freshAttempts (since
|
|
369
381
|
// cacheHits=0) is mathematically tempting but operationally wrong —
|
|
@@ -391,6 +403,8 @@ function projectRunMetrics(result) {
|
|
|
391
403
|
metrics.graphExtraction.cacheMisses += toFiniteNumber(telemetry.cacheMisses);
|
|
392
404
|
metrics.graphExtraction.truncations += toFiniteNumber(telemetry.truncationCount);
|
|
393
405
|
metrics.graphExtraction.failures += toFiniteNumber(telemetry.failureCount);
|
|
406
|
+
metrics.graphExtraction.htmlErrors += toFiniteNumber(telemetry.htmlErrorCount);
|
|
407
|
+
metrics.graphExtraction.retryAttempts += toFiniteNumber(telemetry.retryAttempts);
|
|
394
408
|
}
|
|
395
409
|
}
|
|
396
410
|
metrics.graphExtraction.durationMs += toFiniteNumber(result.graphExtractionDurationMs);
|
|
@@ -520,6 +534,7 @@ function mergeImproveMetrics(dst, src) {
|
|
|
520
534
|
dst.memoryInference.skippedChildExists += src.memoryInference.skippedChildExists;
|
|
521
535
|
dst.memoryInference.skippedAborted += src.memoryInference.skippedAborted;
|
|
522
536
|
dst.memoryInference.unaccounted += src.memoryInference.unaccounted;
|
|
537
|
+
dst.memoryInference.htmlErrorCount += src.memoryInference.htmlErrorCount;
|
|
523
538
|
dst.memoryInference.yieldEligibleRuns += src.memoryInference.yieldEligibleRuns;
|
|
524
539
|
dst.memoryInference.yieldEligibleConsidered += src.memoryInference.yieldEligibleConsidered;
|
|
525
540
|
dst.memoryInference.yieldEligibleWritten += src.memoryInference.yieldEligibleWritten;
|
|
@@ -531,6 +546,7 @@ function mergeImproveMetrics(dst, src) {
|
|
|
531
546
|
dst.graphExtraction.cacheMisses += src.graphExtraction.cacheMisses;
|
|
532
547
|
dst.graphExtraction.truncations += src.graphExtraction.truncations;
|
|
533
548
|
dst.graphExtraction.failures += src.graphExtraction.failures;
|
|
549
|
+
dst.graphExtraction.htmlErrors += src.graphExtraction.htmlErrors;
|
|
534
550
|
dst.graphExtraction.durationMs += src.graphExtraction.durationMs;
|
|
535
551
|
dst.sessionExtraction.sessionsScanned += src.sessionExtraction.sessionsScanned;
|
|
536
552
|
dst.sessionExtraction.sessionsExtracted += src.sessionExtraction.sessionsExtracted;
|
|
@@ -539,15 +555,9 @@ function mergeImproveMetrics(dst, src) {
|
|
|
539
555
|
dst.sessionExtraction.warnings += src.sessionExtraction.warnings;
|
|
540
556
|
dst.sessionExtraction.durationMs += src.sessionExtraction.durationMs;
|
|
541
557
|
}
|
|
542
|
-
function loadImproveRunRows(db, since, until) {
|
|
543
|
-
const sql = until
|
|
544
|
-
? "SELECT id, started_at, completed_at, ok, scope_mode, scope_value, result_json FROM improve_runs WHERE started_at >= ? AND started_at < ? AND dry_run = 0 ORDER BY started_at DESC"
|
|
545
|
-
: "SELECT id, started_at, completed_at, ok, scope_mode, scope_value, result_json FROM improve_runs WHERE started_at >= ? AND dry_run = 0 ORDER BY started_at DESC";
|
|
546
|
-
return (until ? db.prepare(sql).all(since, until) : db.prepare(sql).all(since));
|
|
547
|
-
}
|
|
548
558
|
function summarizeImproveRuns(db, since, until) {
|
|
549
559
|
const accum = createUnknownImproveMetrics();
|
|
550
|
-
const rows =
|
|
560
|
+
const rows = queryImproveRuns(db, since, until);
|
|
551
561
|
// Per-phase wall-time samples. Each entry is one envelope's durationMs for
|
|
552
562
|
// that phase. Phases that did not run on a given envelope are simply
|
|
553
563
|
// omitted (NOT counted as 0) so the median/p95 reflect actual phase work.
|
|
@@ -666,10 +676,7 @@ function loadTaskIntervals(db, since, until) {
|
|
|
666
676
|
const untilMs = until ? new Date(until).getTime() : Number.POSITIVE_INFINITY;
|
|
667
677
|
const widenedSince = new Date(sinceMs - 5 * 60 * 1000).toISOString();
|
|
668
678
|
const widenedUntil = Number.isFinite(untilMs) ? new Date(untilMs + 5 * 60 * 1000).toISOString() : undefined;
|
|
669
|
-
const
|
|
670
|
-
? "SELECT started_at, completed_at FROM task_history WHERE task_id = 'akm-improve' AND started_at >= ? AND started_at < ? AND completed_at IS NOT NULL ORDER BY started_at"
|
|
671
|
-
: "SELECT started_at, completed_at FROM task_history WHERE task_id = 'akm-improve' AND started_at >= ? AND completed_at IS NOT NULL ORDER BY started_at";
|
|
672
|
-
const rows = (widenedUntil ? db.prepare(sql).all(widenedSince, widenedUntil) : db.prepare(sql).all(widenedSince));
|
|
679
|
+
const rows = queryCompletedTaskIntervals(db, widenedSince, widenedUntil);
|
|
673
680
|
const intervals = [];
|
|
674
681
|
for (const row of rows) {
|
|
675
682
|
const startMs = new Date(row.started_at).getTime();
|
|
@@ -702,18 +709,27 @@ function findContainingTaskInterval(timestampMs, intervals) {
|
|
|
702
709
|
return undefined;
|
|
703
710
|
}
|
|
704
711
|
function buildPerRunSummaries(db, since, until) {
|
|
705
|
-
const rows =
|
|
712
|
+
const rows = queryImproveRuns(db, since, until);
|
|
706
713
|
const taskIntervals = loadTaskIntervals(db, since, until);
|
|
707
714
|
const summaries = [];
|
|
708
715
|
for (const row of rows) {
|
|
709
716
|
const startMs = new Date(row.started_at).getTime();
|
|
710
717
|
const endMs = new Date(row.completed_at).getTime();
|
|
711
|
-
// Prefer the
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
718
|
+
// Prefer the improve_runs row's own (completed_at - started_at) delta:
|
|
719
|
+
// recordImproveRun now persists distinct start/end timestamps, so the
|
|
720
|
+
// row's own delta is the authoritative per-run wall time even for
|
|
721
|
+
// manually-invoked `akm improve` runs with no enclosing task_history.
|
|
722
|
+
// Only fall back to the task_history containing-interval join for legacy/
|
|
723
|
+
// backfill rows where started_at == completed_at (row delta is 0).
|
|
724
|
+
const hasRowDelta = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs;
|
|
725
|
+
let wallTimeMs;
|
|
726
|
+
if (hasRowDelta) {
|
|
727
|
+
wallTimeMs = endMs - startMs;
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
const interval = Number.isFinite(startMs) ? findContainingTaskInterval(startMs, taskIntervals) : undefined;
|
|
731
|
+
wallTimeMs = interval?.durationMs ?? 0;
|
|
732
|
+
}
|
|
717
733
|
summaries.push(projectImproveRunSummary(row, wallTimeMs));
|
|
718
734
|
}
|
|
719
735
|
return summaries;
|
|
@@ -759,108 +775,11 @@ function probeStateDbRoundTrip(stateDbPath) {
|
|
|
759
775
|
}
|
|
760
776
|
return { ok: true, durationMs };
|
|
761
777
|
}
|
|
762
|
-
function runAgentProbe() {
|
|
763
|
-
const config = loadConfig();
|
|
764
|
-
// v2: check profiles.agent first
|
|
765
|
-
if (config.profiles?.agent) {
|
|
766
|
-
const defaultName = config.defaults?.agent;
|
|
767
|
-
const profileCount = Object.keys(config.profiles.agent).length;
|
|
768
|
-
if (profileCount === 0) {
|
|
769
|
-
return {
|
|
770
|
-
name: "agent-profile",
|
|
771
|
-
kind: "deterministic",
|
|
772
|
-
status: "unknown",
|
|
773
|
-
confidence: "high",
|
|
774
|
-
message: "No agent profiles configured in profiles.agent.",
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
const profileName = defaultName ?? Object.keys(config.profiles.agent)[0];
|
|
778
|
-
const profile = config.profiles.agent[profileName];
|
|
779
|
-
return {
|
|
780
|
-
name: "agent-profile",
|
|
781
|
-
kind: "deterministic",
|
|
782
|
-
status: "pass",
|
|
783
|
-
confidence: "high",
|
|
784
|
-
message: `v2 agent profile "${profileName}" configured (platform: ${profile?.platform ?? "unknown"}).`,
|
|
785
|
-
evidence: { profile: profileName, platform: profile?.platform, profileCount },
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
if (!config.profiles?.agent && !config.defaults?.agent) {
|
|
789
|
-
return {
|
|
790
|
-
name: "agent-profile",
|
|
791
|
-
kind: "deterministic",
|
|
792
|
-
status: "unknown",
|
|
793
|
-
confidence: "high",
|
|
794
|
-
message: "No agent config present.",
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
|
-
let profile;
|
|
798
|
-
try {
|
|
799
|
-
profile = requireAgentProfile(config);
|
|
800
|
-
}
|
|
801
|
-
catch (error) {
|
|
802
|
-
return {
|
|
803
|
-
name: "agent-profile",
|
|
804
|
-
kind: "deterministic",
|
|
805
|
-
status: "warn",
|
|
806
|
-
confidence: "high",
|
|
807
|
-
message: error instanceof Error ? error.message : String(error),
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
if (profile.sdkMode === true) {
|
|
811
|
-
return {
|
|
812
|
-
name: "agent-profile",
|
|
813
|
-
kind: "deterministic",
|
|
814
|
-
status: profile.model ? "pass" : "warn",
|
|
815
|
-
confidence: "high",
|
|
816
|
-
message: profile.model
|
|
817
|
-
? `SDK mode profile "${profile.name}" is configured.`
|
|
818
|
-
: `SDK mode profile "${profile.name}" has no explicit model.`,
|
|
819
|
-
evidence: { profile: profile.name, sdkMode: true, model: profile.model ?? null },
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
const detections = detectAgentCliProfiles(config);
|
|
823
|
-
const detection = detections.find((entry) => entry.name === profile.name);
|
|
824
|
-
if (!detection?.available) {
|
|
825
|
-
return {
|
|
826
|
-
name: "agent-profile",
|
|
827
|
-
kind: "deterministic",
|
|
828
|
-
status: "fail",
|
|
829
|
-
confidence: "high",
|
|
830
|
-
message: `Default agent profile "${profile.name}" is not available on PATH.`,
|
|
831
|
-
evidence: { profile: profile.name, bin: profile.bin },
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
const version = spawnSync(profile.bin, ["--version"], { encoding: "utf8", timeout: 5_000 });
|
|
835
|
-
if ((version.status ?? 1) !== 0) {
|
|
836
|
-
return {
|
|
837
|
-
name: "agent-profile",
|
|
838
|
-
kind: "deterministic",
|
|
839
|
-
status: "warn",
|
|
840
|
-
confidence: "medium",
|
|
841
|
-
message: `Agent binary "${profile.bin}" was found but \`--version\` failed.`,
|
|
842
|
-
evidence: {
|
|
843
|
-
profile: profile.name,
|
|
844
|
-
bin: profile.bin,
|
|
845
|
-
exitCode: version.status ?? null,
|
|
846
|
-
stderr: (version.stderr ?? "").trim(),
|
|
847
|
-
},
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
return {
|
|
851
|
-
name: "agent-profile",
|
|
852
|
-
kind: "deterministic",
|
|
853
|
-
status: "pass",
|
|
854
|
-
confidence: "high",
|
|
855
|
-
message: `Agent profile "${profile.name}" is available.`,
|
|
856
|
-
evidence: { profile: profile.name, bin: profile.bin, version: (version.stdout ?? "").trim() },
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
778
|
/**
|
|
860
779
|
* Parse a `--window-compare <duration>` shorthand into two adjacent windows
|
|
861
780
|
* (current, prior). Duration syntax matches {@link parseHealthSince}.
|
|
862
781
|
*/
|
|
863
|
-
function resolveWindowCompare(duration) {
|
|
782
|
+
function resolveWindowCompare(duration, now = () => Date.now()) {
|
|
864
783
|
const trimmed = duration.trim();
|
|
865
784
|
const durationMatch = trimmed.match(/^(\d+)([dhm])$/i);
|
|
866
785
|
if (!durationMatch) {
|
|
@@ -873,10 +792,10 @@ function resolveWindowCompare(duration) {
|
|
|
873
792
|
}
|
|
874
793
|
const multiplier = unit === "h" ? 60 * 60 * 1000 : unit === "m" ? 60 * 1000 : 24 * 60 * 60 * 1000;
|
|
875
794
|
const ms = amount * multiplier;
|
|
876
|
-
const
|
|
877
|
-
const currentSince = new Date(
|
|
878
|
-
const currentUntil = new Date(
|
|
879
|
-
const priorSince = new Date(
|
|
795
|
+
const nowMs = now();
|
|
796
|
+
const currentSince = new Date(nowMs - ms).toISOString();
|
|
797
|
+
const currentUntil = new Date(nowMs).toISOString();
|
|
798
|
+
const priorSince = new Date(nowMs - 2 * ms).toISOString();
|
|
880
799
|
const priorUntil = currentSince;
|
|
881
800
|
return [
|
|
882
801
|
{ name: "current", since: currentSince, until: currentUntil },
|
|
@@ -924,8 +843,10 @@ const INTERESTING_DELTA_PATHS = [
|
|
|
924
843
|
"improve.memoryInference.written",
|
|
925
844
|
"improve.memoryInference.yieldRate",
|
|
926
845
|
"improve.memoryInference.skippedNoFacts",
|
|
846
|
+
"improve.memoryInference.htmlErrorCount",
|
|
927
847
|
"improve.graphExtraction.cacheHitRate",
|
|
928
848
|
"improve.graphExtraction.failures",
|
|
849
|
+
"improve.graphExtraction.htmlErrors",
|
|
929
850
|
"improve.sessionExtraction.sessionsScanned",
|
|
930
851
|
"improve.sessionExtraction.proposalsCreated",
|
|
931
852
|
"improve.autoAccept.promoted",
|
|
@@ -961,7 +882,7 @@ function computeDeltas(first, last) {
|
|
|
961
882
|
}
|
|
962
883
|
return out;
|
|
963
884
|
}
|
|
964
|
-
function buildWindowMetrics(db, stateDbPath, since, until) {
|
|
885
|
+
function buildWindowMetrics(db, stateDbPath, since, until, now = () => Date.now()) {
|
|
965
886
|
const taskRows = queryTaskHistory(db, { since }).filter((row) => {
|
|
966
887
|
const startMs = new Date(row.started_at).getTime();
|
|
967
888
|
const untilMs = new Date(until).getTime();
|
|
@@ -971,7 +892,7 @@ function buildWindowMetrics(db, stateDbPath, since, until) {
|
|
|
971
892
|
const existingLogRows = taskRowsWithLogs.filter((row) => row.log_path && fs.existsSync(row.log_path));
|
|
972
893
|
const failedTaskRows = taskRows.filter((row) => row.status === "failed");
|
|
973
894
|
const activeRows = taskRows.filter((row) => row.status === "active");
|
|
974
|
-
const stuckActiveRuns = activeRows.filter((row) =>
|
|
895
|
+
const stuckActiveRuns = activeRows.filter((row) => now() - new Date(row.started_at).getTime() > ACTIVE_RUN_WARN_MS).length;
|
|
975
896
|
const promptRows = taskRows.filter((row) => row.target_kind === "prompt");
|
|
976
897
|
const promptFailures = promptRows.filter((row) => {
|
|
977
898
|
const detail = parseTaskMetadata(row).detail;
|
|
@@ -1027,8 +948,9 @@ function validateAkmHealthOptions(options) {
|
|
|
1027
948
|
}
|
|
1028
949
|
export function akmHealth(options = {}) {
|
|
1029
950
|
validateAkmHealthOptions(options);
|
|
951
|
+
const now = options.now ?? (() => Date.now());
|
|
1030
952
|
const since = parseHealthSince(options.since);
|
|
1031
|
-
const stateDbPath = getStateDbPathInDataDir();
|
|
953
|
+
const stateDbPath = options.stateDbPath ?? getStateDbPathInDataDir();
|
|
1032
954
|
const hardChecks = [];
|
|
1033
955
|
const advisories = [];
|
|
1034
956
|
const getExecutionLogCandidatesFn = options.getExecutionLogCandidatesFn ?? getExecutionLogCandidates;
|
|
@@ -1040,37 +962,17 @@ export function akmHealth(options = {}) {
|
|
|
1040
962
|
throw new ConfigError(`Unable to open state.db: ${error instanceof Error ? error.message : String(error)}`, "INVALID_CONFIG_FILE");
|
|
1041
963
|
}
|
|
1042
964
|
try {
|
|
1043
|
-
const tables = db
|
|
1044
|
-
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('events', 'task_history', 'proposals', 'schema_migrations') ORDER BY name")
|
|
1045
|
-
.all();
|
|
965
|
+
const tables = listExistingTableNames(db, ["events", "task_history", "proposals", "schema_migrations"]);
|
|
1046
966
|
const tableNames = tables.map((row) => row.name).sort();
|
|
1047
967
|
const requiredTables = ["events", "proposals", "schema_migrations", "task_history"];
|
|
1048
968
|
const missingTables = requiredTables.filter((name) => !tableNames.includes(name));
|
|
1049
|
-
hardChecks.push({
|
|
1050
|
-
name: "state-db-schema",
|
|
1051
|
-
kind: "deterministic",
|
|
1052
|
-
status: missingTables.length === 0 ? "pass" : "fail",
|
|
1053
|
-
confidence: "high",
|
|
1054
|
-
message: missingTables.length === 0
|
|
1055
|
-
? "state.db opened and required tables are present."
|
|
1056
|
-
: `state.db is missing required tables: ${missingTables.join(", ")}`,
|
|
1057
|
-
evidence: { path: stateDbPath, tables: tableNames },
|
|
1058
|
-
});
|
|
1059
969
|
const probe = probeStateDbRoundTrip(stateDbPath);
|
|
1060
|
-
hardChecks.push({
|
|
1061
|
-
name: "state-db-round-trip",
|
|
1062
|
-
kind: "deterministic",
|
|
1063
|
-
status: probe.ok ? "pass" : "fail",
|
|
1064
|
-
confidence: "high",
|
|
1065
|
-
message: probe.ok ? "state.db append/read round-trip succeeded." : `state.db round-trip failed: ${probe.error}`,
|
|
1066
|
-
evidence: { path: stateDbPath, durationMs: probe.durationMs },
|
|
1067
|
-
});
|
|
1068
970
|
const taskRows = queryTaskHistory(db, { since });
|
|
1069
971
|
const taskRowsWithLogs = taskRows.filter((row) => row.log_path !== null);
|
|
1070
972
|
const existingLogRows = taskRowsWithLogs.filter((row) => row.log_path && fs.existsSync(row.log_path));
|
|
1071
973
|
const failedTaskRows = taskRows.filter((row) => row.status === "failed");
|
|
1072
974
|
const activeRows = taskRows.filter((row) => row.status === "active");
|
|
1073
|
-
const stuckActiveRuns = activeRows.filter((row) =>
|
|
975
|
+
const stuckActiveRuns = activeRows.filter((row) => now() - new Date(row.started_at).getTime() > ACTIVE_RUN_WARN_MS).length;
|
|
1074
976
|
const promptRows = taskRows.filter((row) => row.target_kind === "prompt");
|
|
1075
977
|
const promptFailures = promptRows.filter((row) => {
|
|
1076
978
|
const detail = parseTaskMetadata(row).detail;
|
|
@@ -1079,51 +981,7 @@ export function akmHealth(options = {}) {
|
|
|
1079
981
|
const logBackingRate = taskRowsWithLogs.length === 0 ? 1 : existingLogRows.length / taskRowsWithLogs.length;
|
|
1080
982
|
const taskFailRate = taskRows.length === 0 ? 0 : failedTaskRows.length / taskRows.length;
|
|
1081
983
|
const agentFailureRate = promptRows.length === 0 ? 0 : promptFailures.length / promptRows.length;
|
|
1082
|
-
hardChecks.push({
|
|
1083
|
-
name: "task-history-read",
|
|
1084
|
-
kind: "deterministic",
|
|
1085
|
-
status: "pass",
|
|
1086
|
-
confidence: "high",
|
|
1087
|
-
message: `Read ${taskRows.length} task-history row(s) since ${since}.`,
|
|
1088
|
-
evidence: { rows: taskRows.length, since },
|
|
1089
|
-
});
|
|
1090
|
-
hardChecks.push({
|
|
1091
|
-
name: "task-log-backing",
|
|
1092
|
-
kind: "deterministic",
|
|
1093
|
-
status: logBackingRate === 1 ? "pass" : "fail",
|
|
1094
|
-
confidence: "high",
|
|
1095
|
-
message: logBackingRate === 1
|
|
1096
|
-
? "Every task_history log_path resolved on disk."
|
|
1097
|
-
: `${taskRowsWithLogs.length - existingLogRows.length} task log(s) referenced in task_history are missing.`,
|
|
1098
|
-
evidence: { totalWithLogs: taskRowsWithLogs.length, existingLogs: existingLogRows.length },
|
|
1099
|
-
});
|
|
1100
|
-
hardChecks.push({
|
|
1101
|
-
name: "active-runs",
|
|
1102
|
-
kind: "deterministic",
|
|
1103
|
-
status: stuckActiveRuns === 0 ? "pass" : "warn",
|
|
1104
|
-
confidence: "high",
|
|
1105
|
-
message: stuckActiveRuns === 0
|
|
1106
|
-
? "No active task runs exceeded the stale threshold."
|
|
1107
|
-
: `${stuckActiveRuns} active task run(s) are older than ${Math.round(ACTIVE_RUN_WARN_MS / 60000)} minutes.`,
|
|
1108
|
-
evidence: { stuckActiveRuns },
|
|
1109
|
-
});
|
|
1110
|
-
hardChecks.push(runAgentProbe());
|
|
1111
984
|
const semanticStatus = readSemanticStatus();
|
|
1112
|
-
advisories.push({
|
|
1113
|
-
name: "semantic-search-runtime",
|
|
1114
|
-
kind: "deterministic",
|
|
1115
|
-
status: !semanticStatus ||
|
|
1116
|
-
semanticStatus.status === "pending" ||
|
|
1117
|
-
semanticStatus.status === "ready-js" ||
|
|
1118
|
-
semanticStatus.status === "ready-vec"
|
|
1119
|
-
? "pass"
|
|
1120
|
-
: "warn",
|
|
1121
|
-
confidence: "medium",
|
|
1122
|
-
message: semanticStatus
|
|
1123
|
-
? `Semantic search status: ${semanticStatus.status}`
|
|
1124
|
-
: "No semantic-search runtime status recorded yet.",
|
|
1125
|
-
evidence: semanticStatus ? { ...semanticStatus } : undefined,
|
|
1126
|
-
});
|
|
1127
985
|
const improveInvoked = readEvents({ since, type: "improve_invoked" }, { dbPath: stateDbPath }).events.length;
|
|
1128
986
|
const improveCompletedEvents = readEvents({ since, type: IMPROVE_COMPLETED_EVENT }, { dbPath: stateDbPath }).events;
|
|
1129
987
|
const improveSkippedEvents = readEvents({ since, type: "improve_skipped" }, { dbPath: stateDbPath }).events;
|
|
@@ -1139,7 +997,7 @@ export function akmHealth(options = {}) {
|
|
|
1139
997
|
improveSummary.wallTime = computeWallTimeStats(wallTimes, improveSummary.wallTime.byPhase);
|
|
1140
998
|
let sessionLogEntries = [];
|
|
1141
999
|
try {
|
|
1142
|
-
const sinceDays = Math.max(0, Math.ceil((
|
|
1000
|
+
const sinceDays = Math.max(0, Math.ceil((now() - new Date(since).getTime()) / (24 * 60 * 60 * 1000)));
|
|
1143
1001
|
sessionLogEntries = getExecutionLogCandidatesFn(sinceDays).map((entry) => ({
|
|
1144
1002
|
topic: entry.topic,
|
|
1145
1003
|
frequency: entry.frequency,
|
|
@@ -1150,59 +1008,33 @@ export function akmHealth(options = {}) {
|
|
|
1150
1008
|
catch {
|
|
1151
1009
|
sessionLogEntries = [];
|
|
1152
1010
|
}
|
|
1153
|
-
//
|
|
1154
|
-
//
|
|
1155
|
-
//
|
|
1156
|
-
//
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
? `Session extraction degraded: ${sxWarnReasons.join("; ")}.`
|
|
1181
|
-
: `Session extraction healthy: ${sx.sessionsScanned} scanned, ${sx.sessionsExtracted} extracted, ${sx.proposalsCreated} proposal(s) created.`
|
|
1182
|
-
: "Session extraction not active (feature disabled or no harness available).",
|
|
1183
|
-
evidence: {
|
|
1184
|
-
ran: sx.ran,
|
|
1185
|
-
sessionsScanned: sx.sessionsScanned,
|
|
1186
|
-
sessionsExtracted: sx.sessionsExtracted,
|
|
1187
|
-
sessionsSkipped: sx.sessionsSkipped,
|
|
1188
|
-
proposalsCreated: sx.proposalsCreated,
|
|
1189
|
-
warnings: sx.warnings,
|
|
1190
|
-
durationMs: sx.durationMs,
|
|
1191
|
-
},
|
|
1192
|
-
});
|
|
1193
|
-
const aa = improveSummary.autoAccept;
|
|
1194
|
-
advisories.push({
|
|
1195
|
-
name: "auto-accept-validation",
|
|
1196
|
-
kind: "heuristic",
|
|
1197
|
-
status: aa.validationFailed > 0 ? "warn" : "pass",
|
|
1198
|
-
confidence: aa.promoted + aa.validationFailed > 0 ? "high" : "low",
|
|
1199
|
-
message: aa.validationFailed > 0
|
|
1200
|
-
? `${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.`
|
|
1201
|
-
: aa.promoted > 0
|
|
1202
|
-
? `Auto-accept healthy: ${aa.promoted} proposal(s) promoted, 0 validation failures.`
|
|
1203
|
-
: "Auto-accept gate did not run (disabled or no proposals above threshold).",
|
|
1204
|
-
evidence: { promoted: aa.promoted, validationFailed: aa.validationFailed },
|
|
1205
|
-
});
|
|
1011
|
+
// Run the ordered health-check registry. Each check projects the shared
|
|
1012
|
+
// context computed above into one HealthCheckResult; `channel` routes it to
|
|
1013
|
+
// hardChecks or advisories. Declaration order in HEALTH_CHECKS is the
|
|
1014
|
+
// emission order — see src/commands/health/checks.ts.
|
|
1015
|
+
const checkContext = {
|
|
1016
|
+
stateDbPath,
|
|
1017
|
+
since,
|
|
1018
|
+
tableNames,
|
|
1019
|
+
missingTables,
|
|
1020
|
+
probe,
|
|
1021
|
+
taskRowCount: taskRows.length,
|
|
1022
|
+
taskRowsWithLogsCount: taskRowsWithLogs.length,
|
|
1023
|
+
existingLogRowsCount: existingLogRows.length,
|
|
1024
|
+
logBackingRate,
|
|
1025
|
+
stuckActiveRuns,
|
|
1026
|
+
semanticStatus,
|
|
1027
|
+
sessionLogEntries,
|
|
1028
|
+
sessionExtraction: improveSummary.sessionExtraction,
|
|
1029
|
+
autoAccept: improveSummary.autoAccept,
|
|
1030
|
+
};
|
|
1031
|
+
for (const check of HEALTH_CHECKS) {
|
|
1032
|
+
const result = check.run(checkContext);
|
|
1033
|
+
if (check.channel === "hard")
|
|
1034
|
+
hardChecks.push(result);
|
|
1035
|
+
else
|
|
1036
|
+
advisories.push(result);
|
|
1037
|
+
}
|
|
1206
1038
|
const metrics = {
|
|
1207
1039
|
taskFailRate: roundRate(taskFailRate),
|
|
1208
1040
|
agentFailureRate: roundRate(agentFailureRate),
|
|
@@ -1216,7 +1048,7 @@ export function akmHealth(options = {}) {
|
|
|
1216
1048
|
// ── Window-compare mode (Phase 3) ─────────────────────────────────────
|
|
1217
1049
|
let windowSpecs;
|
|
1218
1050
|
if (options.windowCompare) {
|
|
1219
|
-
windowSpecs = resolveWindowCompare(options.windowCompare);
|
|
1051
|
+
windowSpecs = resolveWindowCompare(options.windowCompare, now);
|
|
1220
1052
|
}
|
|
1221
1053
|
else if (options.windows && options.windows.length > 0) {
|
|
1222
1054
|
windowSpecs = options.windows;
|
|
@@ -1229,8 +1061,8 @@ export function akmHealth(options = {}) {
|
|
|
1229
1061
|
if (windowSpecs && db) {
|
|
1230
1062
|
windowResults = windowSpecs.map((spec) => {
|
|
1231
1063
|
const winSince = parseHealthSince(spec.since);
|
|
1232
|
-
const winUntil = spec.until ? parseHealthSince(spec.until) : new Date().toISOString();
|
|
1233
|
-
const bundle = buildWindowMetrics(db, stateDbPath, winSince, winUntil);
|
|
1064
|
+
const winUntil = spec.until ? parseHealthSince(spec.until) : new Date(now()).toISOString();
|
|
1065
|
+
const bundle = buildWindowMetrics(db, stateDbPath, winSince, winUntil, now);
|
|
1234
1066
|
return {
|
|
1235
1067
|
name: spec.name,
|
|
1236
1068
|
since: winSince,
|