akm-cli 0.7.5 → 0.8.0-rc.6
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/{.github/CHANGELOG.md → CHANGELOG.md} +113 -2
- package/README.md +20 -4
- package/SECURITY.md +93 -0
- package/dist/cli/config-migrate.js +144 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/confirm.js +73 -0
- package/dist/cli/parse-args.js +133 -0
- package/dist/cli.js +1995 -551
- package/dist/commands/agent-dispatch.js +110 -0
- package/dist/commands/agent-support.js +68 -0
- package/dist/commands/completions.js +3 -0
- package/dist/commands/config-cli.js +130 -534
- package/dist/commands/consolidate.js +1531 -0
- package/dist/commands/curate.js +44 -3
- package/dist/commands/db-cli.js +23 -0
- package/dist/commands/distill-promotion-policy.js +660 -0
- package/dist/commands/distill.js +990 -75
- package/dist/commands/eval-cases.js +43 -0
- package/dist/commands/events.js +5 -23
- package/dist/commands/graph.js +477 -0
- package/dist/commands/health.js +400 -0
- package/dist/commands/help/help-accept.md +9 -0
- package/dist/commands/help/help-improve.md +77 -0
- package/dist/commands/help/help-proposals.md +15 -0
- package/dist/commands/help/help-propose.md +17 -0
- package/dist/commands/help/help-reject.md +8 -0
- package/dist/commands/history.js +54 -46
- package/dist/commands/improve-profiles.js +146 -0
- package/dist/commands/improve-result-file.js +103 -0
- package/dist/commands/improve.js +2175 -0
- package/dist/commands/info.js +5 -2
- package/dist/commands/init.js +50 -2
- package/dist/commands/installed-stashes.js +102 -139
- package/dist/commands/knowledge.js +136 -0
- package/dist/commands/lint/agent-linter.js +49 -0
- package/dist/commands/lint/base-linter.js +479 -0
- package/dist/commands/lint/command-linter.js +49 -0
- package/dist/commands/lint/default-linter.js +16 -0
- package/dist/commands/lint/index.js +183 -0
- package/dist/commands/lint/knowledge-linter.js +16 -0
- package/dist/commands/lint/markdown-insertion.js +343 -0
- package/dist/commands/lint/memory-linter.js +61 -0
- package/dist/commands/lint/registry.js +36 -0
- package/dist/commands/lint/skill-linter.js +45 -0
- package/dist/commands/lint/task-linter.js +50 -0
- package/dist/commands/lint/types.js +4 -0
- package/dist/commands/lint/vault-key-rules.js +139 -0
- package/dist/commands/lint/workflow-linter.js +56 -0
- package/dist/commands/lint.js +4 -0
- package/dist/commands/migration-help.js +5 -2
- package/dist/commands/proposal.js +66 -12
- package/dist/commands/propose.js +86 -31
- package/dist/commands/reflect.js +1119 -73
- package/dist/commands/registry-search.js +5 -2
- package/dist/commands/remember.js +69 -6
- package/dist/commands/schema-repair.js +203 -0
- package/dist/commands/search.js +115 -14
- package/dist/commands/self-update.js +3 -0
- package/dist/commands/show.js +144 -25
- package/dist/commands/source-add.js +17 -45
- package/dist/commands/source-clone.js +3 -0
- package/dist/commands/source-manage.js +14 -19
- package/dist/commands/tasks.js +438 -0
- package/dist/commands/url-checker.js +42 -0
- package/dist/commands/vault.js +130 -77
- package/dist/core/action-contributors.js +28 -0
- package/dist/core/asset-ref.js +7 -0
- package/dist/core/asset-registry.js +7 -16
- package/dist/core/asset-serialize.js +88 -0
- package/dist/core/asset-spec.js +22 -0
- package/dist/core/common.js +157 -0
- package/dist/core/concurrent.js +25 -0
- package/dist/core/config-io.js +347 -0
- package/dist/core/config-migration.js +625 -0
- package/dist/core/config-schema.js +501 -0
- package/dist/core/config-sources.js +108 -0
- package/dist/core/config-types.js +4 -0
- package/dist/core/config-walker.js +337 -0
- package/dist/core/config.js +327 -987
- package/dist/core/errors.js +40 -19
- package/dist/core/events.js +91 -138
- package/dist/core/file-lock.js +104 -0
- package/dist/core/frontmatter.js +3 -6
- package/dist/core/lesson-lint.js +3 -0
- package/dist/core/markdown.js +20 -0
- package/dist/core/memory-belief.js +62 -0
- package/dist/core/memory-contradiction-detect.js +274 -0
- package/dist/core/memory-improve.js +806 -0
- package/dist/core/parse.js +158 -0
- package/dist/core/paths.js +326 -14
- package/dist/core/proposal-quality-validators.js +364 -0
- package/dist/core/proposal-validators.js +69 -0
- package/dist/core/proposals.js +498 -42
- package/dist/core/state-db.js +927 -0
- package/dist/core/text-truncation.js +107 -0
- package/dist/core/time.js +54 -0
- package/dist/core/warn.js +62 -1
- package/dist/core/write-source.js +3 -0
- package/dist/indexer/db-backup.js +391 -0
- package/dist/indexer/db-search.js +152 -253
- package/dist/indexer/db.js +933 -103
- package/dist/indexer/ensure-index.js +64 -0
- package/dist/indexer/file-context.js +3 -0
- package/dist/indexer/graph-boost.js +376 -101
- package/dist/indexer/graph-db.js +391 -0
- package/dist/indexer/graph-dedup.js +95 -0
- package/dist/indexer/graph-extraction.js +550 -124
- package/dist/indexer/index-context.js +4 -0
- package/dist/indexer/indexer.js +506 -291
- package/dist/indexer/llm-cache.js +47 -0
- package/dist/indexer/manifest.js +3 -0
- package/dist/indexer/matchers.js +148 -160
- package/dist/indexer/memory-inference.js +99 -74
- package/dist/indexer/metadata-contributors.js +29 -0
- package/dist/indexer/metadata.js +255 -196
- package/dist/indexer/path-resolver.js +92 -0
- package/dist/indexer/project-context.js +192 -0
- package/dist/indexer/ranking-contributors.js +331 -0
- package/dist/indexer/ranking.js +81 -0
- package/dist/indexer/search-fields.js +5 -9
- package/dist/indexer/search-hit-enrichers.js +111 -0
- package/dist/indexer/search-source.js +44 -10
- package/dist/indexer/semantic-status.js +5 -16
- package/dist/indexer/staleness-detect.js +447 -0
- package/dist/indexer/usage-events.js +12 -9
- package/dist/indexer/walker.js +28 -0
- package/dist/integrations/agent/builders.js +135 -0
- package/dist/integrations/agent/config.js +122 -230
- package/dist/integrations/agent/detect.js +3 -0
- package/dist/integrations/agent/index.js +7 -13
- package/dist/integrations/agent/model-aliases.js +55 -0
- package/dist/integrations/agent/profiles.js +70 -5
- package/dist/integrations/agent/prompts.js +150 -74
- package/dist/integrations/agent/runner.js +151 -0
- package/dist/integrations/agent/sdk-runner.js +126 -0
- package/dist/integrations/agent/spawn.js +118 -23
- package/dist/integrations/github.js +3 -0
- package/dist/integrations/lockfile.js +32 -69
- package/dist/integrations/session-logs/index.js +68 -0
- package/dist/integrations/session-logs/providers/claude-code.js +59 -0
- package/dist/integrations/session-logs/providers/opencode.js +55 -0
- package/dist/integrations/session-logs/types.js +4 -0
- package/dist/llm/call-ai.js +62 -0
- package/dist/llm/client.js +72 -124
- package/dist/llm/embedder.js +3 -19
- package/dist/llm/embedders/cache.js +3 -7
- package/dist/llm/embedders/local.js +3 -0
- package/dist/llm/embedders/remote.js +20 -8
- package/dist/llm/embedders/types.js +3 -7
- package/dist/llm/feature-gate.js +89 -48
- package/dist/llm/graph-extract.js +676 -70
- package/dist/llm/index-passes.js +9 -23
- package/dist/llm/memory-infer.js +52 -71
- package/dist/llm/metadata-enhance.js +42 -29
- package/dist/llm/prompts/graph-extract-user-prompt.md +35 -0
- package/dist/output/cli-hints-full.md +281 -0
- package/dist/output/cli-hints-short.md +65 -0
- package/dist/output/cli-hints.js +5 -318
- package/dist/output/context.js +3 -0
- package/dist/output/renderers.js +223 -256
- package/dist/output/shapes.js +150 -105
- package/dist/output/text.js +318 -30
- package/dist/registry/build-index.js +3 -0
- package/dist/registry/create-provider-registry.js +3 -0
- package/dist/registry/factory.js +3 -0
- package/dist/registry/origin-resolve.js +3 -0
- package/dist/registry/providers/index.js +3 -0
- package/dist/registry/providers/skills-sh.js +70 -49
- package/dist/registry/providers/static-index.js +53 -48
- package/dist/registry/providers/types.js +3 -24
- package/dist/registry/resolve.js +11 -16
- package/dist/registry/types.js +3 -0
- package/dist/scripts/migrate-storage.js +17307 -0
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8900 -0
- package/dist/scripts/migrations/v16-to-v17.js +141 -0
- package/dist/setup/detect.js +3 -0
- package/dist/setup/ripgrep-install.js +3 -0
- package/dist/setup/ripgrep-resolve.js +3 -0
- package/dist/setup/setup.js +775 -37
- package/dist/setup/steps.js +3 -15
- package/dist/sources/include.js +3 -0
- package/dist/sources/provider-factory.js +5 -12
- package/dist/sources/provider.js +3 -20
- package/dist/sources/providers/filesystem.js +19 -23
- package/dist/sources/providers/git.js +7 -5
- package/dist/sources/providers/index.js +3 -0
- package/dist/sources/providers/install-types.js +3 -13
- package/dist/sources/providers/npm.js +3 -4
- package/dist/sources/providers/provider-utils.js +3 -0
- package/dist/sources/providers/sync-from-ref.js +3 -11
- package/dist/sources/providers/tar-utils.js +3 -0
- package/dist/sources/providers/website.js +18 -22
- package/dist/sources/resolve.js +3 -0
- package/dist/sources/types.js +3 -0
- package/dist/sources/website-ingest.js +7 -0
- package/dist/tasks/backends/cron.js +203 -0
- package/dist/tasks/backends/exec-utils.js +28 -0
- package/dist/tasks/backends/index.js +24 -0
- package/dist/tasks/backends/launchd-template.xml +19 -0
- package/dist/tasks/backends/launchd.js +187 -0
- package/dist/tasks/backends/schtasks-template.xml +29 -0
- package/dist/tasks/backends/schtasks.js +215 -0
- package/dist/tasks/parser.js +211 -0
- package/dist/tasks/resolveAkmBin.js +87 -0
- package/dist/tasks/runner.js +458 -0
- package/dist/tasks/schedule.js +211 -0
- package/dist/tasks/schema.js +15 -0
- package/dist/tasks/validator.js +62 -0
- package/dist/version.js +3 -0
- package/dist/wiki/index-template.md +12 -0
- package/dist/wiki/ingest-workflow-template.md +54 -0
- package/dist/wiki/log-template.md +8 -0
- package/dist/wiki/schema-template.md +61 -0
- package/dist/wiki/wiki-templates.js +15 -0
- package/dist/wiki/wiki.js +13 -61
- package/dist/workflows/authoring.js +8 -25
- package/dist/workflows/cli.js +3 -0
- package/dist/workflows/db.js +140 -10
- package/dist/workflows/document-cache.js +3 -10
- package/dist/workflows/parser.js +3 -0
- package/dist/workflows/renderer.js +11 -3
- package/dist/workflows/runs.js +62 -91
- package/dist/workflows/schema.js +3 -0
- package/dist/workflows/scope-key.js +3 -0
- package/dist/workflows/validator.js +4 -8
- package/dist/workflows/workflow-template.md +24 -0
- package/docs/README.md +9 -2
- package/docs/data-and-telemetry.md +225 -0
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +2 -2
- package/docs/migration/release-notes/0.8.0.md +48 -0
- package/docs/migration/v0.7-to-v0.8.md +1307 -0
- package/package.json +20 -8
- package/.github/LICENSE +0 -374
- package/dist/commands/install-audit.js +0 -381
- package/dist/templates/wiki-templates.js +0 -100
|
@@ -0,0 +1,400 @@
|
|
|
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 fs from "node:fs";
|
|
6
|
+
import { loadConfig } from "../core/config";
|
|
7
|
+
import { ConfigError, UsageError } from "../core/errors";
|
|
8
|
+
import { appendEvent, readEvents } from "../core/events";
|
|
9
|
+
import { getStateDbPathInDataDir } from "../core/paths";
|
|
10
|
+
import { openStateDatabase, queryTaskHistory } from "../core/state-db";
|
|
11
|
+
import { parseSinceToIso } from "../core/time";
|
|
12
|
+
import { readSemanticStatus } from "../indexer/semantic-status";
|
|
13
|
+
import { detectAgentCliProfiles, requireAgentProfile } from "../integrations/agent";
|
|
14
|
+
import { getExecutionLogCandidates } from "../integrations/session-logs";
|
|
15
|
+
const DEFAULT_SINCE_MS = 24 * 60 * 60 * 1000;
|
|
16
|
+
const IMPROVE_COMPLETED_EVENT = "improve_completed";
|
|
17
|
+
const HEALTH_PROBE_EVENT = "health_probe";
|
|
18
|
+
const ACTIVE_RUN_WARN_MS = 15 * 60 * 1000;
|
|
19
|
+
export function parseHealthSince(since) {
|
|
20
|
+
if (since === undefined || since.trim() === "") {
|
|
21
|
+
return new Date(Date.now() - DEFAULT_SINCE_MS).toISOString();
|
|
22
|
+
}
|
|
23
|
+
const trimmed = since.trim();
|
|
24
|
+
const durationMatch = trimmed.match(/^(\d+)([dhm])$/i);
|
|
25
|
+
if (durationMatch) {
|
|
26
|
+
const amount = Number.parseInt(durationMatch[1] ?? "0", 10);
|
|
27
|
+
const unit = (durationMatch[2] ?? "d").toLowerCase();
|
|
28
|
+
if (!Number.isFinite(amount) || amount < 0) {
|
|
29
|
+
throw new UsageError("--since must be a non-negative duration or timestamp.", "INVALID_FLAG_VALUE");
|
|
30
|
+
}
|
|
31
|
+
const multiplier = unit === "h" ? 60 * 60 * 1000 : unit === "m" ? 30 * 24 * 60 * 60 * 1000 : 24 * 60 * 60 * 1000;
|
|
32
|
+
return new Date(Date.now() - amount * multiplier).toISOString();
|
|
33
|
+
}
|
|
34
|
+
return parseSinceToIso(trimmed);
|
|
35
|
+
}
|
|
36
|
+
function roundRate(value) {
|
|
37
|
+
return Number(value.toFixed(4));
|
|
38
|
+
}
|
|
39
|
+
function parseTaskMetadata(row) {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(row.metadata_json);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function createUnknownImproveMetrics() {
|
|
48
|
+
return {
|
|
49
|
+
invoked: 0,
|
|
50
|
+
completed: 0,
|
|
51
|
+
skipped: 0,
|
|
52
|
+
skipReasons: {},
|
|
53
|
+
plannedRefs: 0,
|
|
54
|
+
actions: {
|
|
55
|
+
reflect: 0,
|
|
56
|
+
distill: 0,
|
|
57
|
+
distillSkipped: 0,
|
|
58
|
+
memoryPrune: 0,
|
|
59
|
+
memoryInference: 0,
|
|
60
|
+
graphExtraction: 0,
|
|
61
|
+
error: 0,
|
|
62
|
+
},
|
|
63
|
+
reflectsWithErrorContext: 0,
|
|
64
|
+
coverageGapCount: 0,
|
|
65
|
+
executionLogCandidateCount: 0,
|
|
66
|
+
evalCasesWritten: 0,
|
|
67
|
+
deadUrlCount: 0,
|
|
68
|
+
memorySummary: { eligible: 0, derived: 0 },
|
|
69
|
+
memoryCleanup: {
|
|
70
|
+
pruneCandidates: 0,
|
|
71
|
+
contradictionCandidates: 0,
|
|
72
|
+
beliefStateTransitions: 0,
|
|
73
|
+
consolidationCandidates: 0,
|
|
74
|
+
archived: 0,
|
|
75
|
+
warnings: 0,
|
|
76
|
+
},
|
|
77
|
+
consolidation: { ran: false, processed: 0, durationMs: 0 },
|
|
78
|
+
memoryInference: { ran: false, writes: 0, durationMs: 0 },
|
|
79
|
+
graphExtraction: { ran: false, extractedFiles: 0, durationMs: 0 },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function toFiniteNumber(value) {
|
|
83
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
84
|
+
return value;
|
|
85
|
+
if (typeof value === "string" && value.trim()) {
|
|
86
|
+
const parsed = Number(value);
|
|
87
|
+
if (Number.isFinite(parsed))
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
function summarizeImproveCompleted(events) {
|
|
93
|
+
const metrics = createUnknownImproveMetrics();
|
|
94
|
+
metrics.completed = events.length;
|
|
95
|
+
for (const event of events) {
|
|
96
|
+
const meta = event.metadata ?? {};
|
|
97
|
+
metrics.plannedRefs += toFiniteNumber(meta.plannedRefs);
|
|
98
|
+
metrics.actions.reflect += toFiniteNumber(meta.reflectActions);
|
|
99
|
+
metrics.actions.distill += toFiniteNumber(meta.distillActions);
|
|
100
|
+
metrics.actions.distillSkipped += toFiniteNumber(meta.distillSkippedActions);
|
|
101
|
+
metrics.actions.memoryPrune += toFiniteNumber(meta.memoryPruneActions);
|
|
102
|
+
metrics.actions.memoryInference += toFiniteNumber(meta.memoryInferenceActions);
|
|
103
|
+
metrics.actions.graphExtraction += toFiniteNumber(meta.graphExtractionActions);
|
|
104
|
+
metrics.actions.error += toFiniteNumber(meta.errorActions);
|
|
105
|
+
metrics.reflectsWithErrorContext += toFiniteNumber(meta.reflectsWithErrorContext);
|
|
106
|
+
metrics.coverageGapCount += toFiniteNumber(meta.coverageGapCount);
|
|
107
|
+
metrics.executionLogCandidateCount += toFiniteNumber(meta.executionLogCandidateCount);
|
|
108
|
+
metrics.evalCasesWritten += toFiniteNumber(meta.evalCasesWritten);
|
|
109
|
+
metrics.deadUrlCount += toFiniteNumber(meta.deadUrlCount);
|
|
110
|
+
metrics.memorySummary.eligible += toFiniteNumber(meta.memoryEligible);
|
|
111
|
+
metrics.memorySummary.derived += toFiniteNumber(meta.memoryDerived);
|
|
112
|
+
metrics.memoryCleanup.pruneCandidates += toFiniteNumber(meta.memoryCleanupPruneCandidates);
|
|
113
|
+
metrics.memoryCleanup.contradictionCandidates += toFiniteNumber(meta.memoryCleanupContradictionCandidates);
|
|
114
|
+
metrics.memoryCleanup.beliefStateTransitions += toFiniteNumber(meta.memoryCleanupBeliefStateTransitions);
|
|
115
|
+
metrics.memoryCleanup.consolidationCandidates += toFiniteNumber(meta.memoryCleanupConsolidationCandidates);
|
|
116
|
+
metrics.memoryCleanup.archived += toFiniteNumber(meta.memoryCleanupArchived);
|
|
117
|
+
metrics.memoryCleanup.warnings += toFiniteNumber(meta.memoryCleanupWarnings);
|
|
118
|
+
metrics.consolidation.processed += toFiniteNumber(meta.consolidationProcessed);
|
|
119
|
+
metrics.consolidation.durationMs += toFiniteNumber(meta.consolidationDurationMs);
|
|
120
|
+
metrics.memoryInference.writes += toFiniteNumber(meta.memoryInferenceWrites);
|
|
121
|
+
metrics.memoryInference.durationMs += toFiniteNumber(meta.memoryInferenceDurationMs);
|
|
122
|
+
metrics.graphExtraction.extractedFiles += toFiniteNumber(meta.graphExtractionExtractedFiles);
|
|
123
|
+
metrics.graphExtraction.durationMs += toFiniteNumber(meta.graphExtractionDurationMs);
|
|
124
|
+
}
|
|
125
|
+
metrics.consolidation.ran = metrics.consolidation.processed > 0 || metrics.consolidation.durationMs > 0;
|
|
126
|
+
metrics.memoryInference.ran = metrics.memoryInference.writes > 0 || metrics.memoryInference.durationMs > 0;
|
|
127
|
+
metrics.graphExtraction.ran = metrics.graphExtraction.extractedFiles > 0 || metrics.graphExtraction.durationMs > 0;
|
|
128
|
+
return metrics;
|
|
129
|
+
}
|
|
130
|
+
function buildImproveSkipSummary(events) {
|
|
131
|
+
const skipReasons = {};
|
|
132
|
+
for (const event of events) {
|
|
133
|
+
const reason = typeof event.metadata?.reason === "string" && event.metadata.reason.trim() ? event.metadata.reason : "unknown";
|
|
134
|
+
skipReasons[reason] = (skipReasons[reason] ?? 0) + 1;
|
|
135
|
+
}
|
|
136
|
+
return { skipped: events.length, skipReasons };
|
|
137
|
+
}
|
|
138
|
+
function probeStateDbRoundTrip(stateDbPath) {
|
|
139
|
+
const before = readEvents({}, { dbPath: stateDbPath }).nextOffset;
|
|
140
|
+
const started = Date.now();
|
|
141
|
+
appendEvent({ eventType: HEALTH_PROBE_EVENT, ref: "health:probe", metadata: { source: "akm health" } }, { dbPath: stateDbPath });
|
|
142
|
+
const after = readEvents({ sinceOffset: before, type: HEALTH_PROBE_EVENT, ref: "health:probe" }, { dbPath: stateDbPath });
|
|
143
|
+
const durationMs = Date.now() - started;
|
|
144
|
+
if (after.events.length === 0 || after.nextOffset <= before) {
|
|
145
|
+
return { ok: false, durationMs, error: "probe event was not readable after append" };
|
|
146
|
+
}
|
|
147
|
+
return { ok: true, durationMs };
|
|
148
|
+
}
|
|
149
|
+
function runAgentProbe() {
|
|
150
|
+
const config = loadConfig();
|
|
151
|
+
// v2: check profiles.agent first
|
|
152
|
+
if (config.profiles?.agent) {
|
|
153
|
+
const defaultName = config.defaults?.agent;
|
|
154
|
+
const profileCount = Object.keys(config.profiles.agent).length;
|
|
155
|
+
if (profileCount === 0) {
|
|
156
|
+
return {
|
|
157
|
+
name: "agent-profile",
|
|
158
|
+
kind: "deterministic",
|
|
159
|
+
status: "unknown",
|
|
160
|
+
confidence: "high",
|
|
161
|
+
message: "No agent profiles configured in profiles.agent.",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const profileName = defaultName ?? Object.keys(config.profiles.agent)[0];
|
|
165
|
+
const profile = config.profiles.agent[profileName];
|
|
166
|
+
return {
|
|
167
|
+
name: "agent-profile",
|
|
168
|
+
kind: "deterministic",
|
|
169
|
+
status: "pass",
|
|
170
|
+
confidence: "high",
|
|
171
|
+
message: `v2 agent profile "${profileName}" configured (platform: ${profile?.platform ?? "unknown"}).`,
|
|
172
|
+
evidence: { profile: profileName, platform: profile?.platform, profileCount },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (!config.profiles?.agent && !config.defaults?.agent) {
|
|
176
|
+
return {
|
|
177
|
+
name: "agent-profile",
|
|
178
|
+
kind: "deterministic",
|
|
179
|
+
status: "unknown",
|
|
180
|
+
confidence: "high",
|
|
181
|
+
message: "No agent config present.",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
let profile;
|
|
185
|
+
try {
|
|
186
|
+
profile = requireAgentProfile(config);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
name: "agent-profile",
|
|
191
|
+
kind: "deterministic",
|
|
192
|
+
status: "warn",
|
|
193
|
+
confidence: "high",
|
|
194
|
+
message: error instanceof Error ? error.message : String(error),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (profile.sdkMode === true) {
|
|
198
|
+
return {
|
|
199
|
+
name: "agent-profile",
|
|
200
|
+
kind: "deterministic",
|
|
201
|
+
status: profile.model ? "pass" : "warn",
|
|
202
|
+
confidence: "high",
|
|
203
|
+
message: profile.model
|
|
204
|
+
? `SDK mode profile "${profile.name}" is configured.`
|
|
205
|
+
: `SDK mode profile "${profile.name}" has no explicit model.`,
|
|
206
|
+
evidence: { profile: profile.name, sdkMode: true, model: profile.model ?? null },
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const detections = detectAgentCliProfiles(config);
|
|
210
|
+
const detection = detections.find((entry) => entry.name === profile.name);
|
|
211
|
+
if (!detection?.available) {
|
|
212
|
+
return {
|
|
213
|
+
name: "agent-profile",
|
|
214
|
+
kind: "deterministic",
|
|
215
|
+
status: "fail",
|
|
216
|
+
confidence: "high",
|
|
217
|
+
message: `Default agent profile "${profile.name}" is not available on PATH.`,
|
|
218
|
+
evidence: { profile: profile.name, bin: profile.bin },
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const version = spawnSync(profile.bin, ["--version"], { encoding: "utf8", timeout: 5_000 });
|
|
222
|
+
if ((version.status ?? 1) !== 0) {
|
|
223
|
+
return {
|
|
224
|
+
name: "agent-profile",
|
|
225
|
+
kind: "deterministic",
|
|
226
|
+
status: "warn",
|
|
227
|
+
confidence: "medium",
|
|
228
|
+
message: `Agent binary "${profile.bin}" was found but \`--version\` failed.`,
|
|
229
|
+
evidence: {
|
|
230
|
+
profile: profile.name,
|
|
231
|
+
bin: profile.bin,
|
|
232
|
+
exitCode: version.status ?? null,
|
|
233
|
+
stderr: (version.stderr ?? "").trim(),
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
name: "agent-profile",
|
|
239
|
+
kind: "deterministic",
|
|
240
|
+
status: "pass",
|
|
241
|
+
confidence: "high",
|
|
242
|
+
message: `Agent profile "${profile.name}" is available.`,
|
|
243
|
+
evidence: { profile: profile.name, bin: profile.bin, version: (version.stdout ?? "").trim() },
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
export function akmHealth(options = {}) {
|
|
247
|
+
const since = parseHealthSince(options.since);
|
|
248
|
+
const stateDbPath = getStateDbPathInDataDir();
|
|
249
|
+
const hardChecks = [];
|
|
250
|
+
const advisories = [];
|
|
251
|
+
const getExecutionLogCandidatesFn = options.getExecutionLogCandidatesFn ?? getExecutionLogCandidates;
|
|
252
|
+
let db;
|
|
253
|
+
try {
|
|
254
|
+
db = openStateDatabase(stateDbPath);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
throw new ConfigError(`Unable to open state.db: ${error instanceof Error ? error.message : String(error)}`, "INVALID_CONFIG_FILE");
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
const tables = db
|
|
261
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('events', 'task_history', 'proposals', 'schema_migrations') ORDER BY name")
|
|
262
|
+
.all();
|
|
263
|
+
const tableNames = tables.map((row) => row.name).sort();
|
|
264
|
+
const requiredTables = ["events", "proposals", "schema_migrations", "task_history"];
|
|
265
|
+
const missingTables = requiredTables.filter((name) => !tableNames.includes(name));
|
|
266
|
+
hardChecks.push({
|
|
267
|
+
name: "state-db-schema",
|
|
268
|
+
kind: "deterministic",
|
|
269
|
+
status: missingTables.length === 0 ? "pass" : "fail",
|
|
270
|
+
confidence: "high",
|
|
271
|
+
message: missingTables.length === 0
|
|
272
|
+
? "state.db opened and required tables are present."
|
|
273
|
+
: `state.db is missing required tables: ${missingTables.join(", ")}`,
|
|
274
|
+
evidence: { path: stateDbPath, tables: tableNames },
|
|
275
|
+
});
|
|
276
|
+
const probe = probeStateDbRoundTrip(stateDbPath);
|
|
277
|
+
hardChecks.push({
|
|
278
|
+
name: "state-db-round-trip",
|
|
279
|
+
kind: "deterministic",
|
|
280
|
+
status: probe.ok ? "pass" : "fail",
|
|
281
|
+
confidence: "high",
|
|
282
|
+
message: probe.ok ? "state.db append/read round-trip succeeded." : `state.db round-trip failed: ${probe.error}`,
|
|
283
|
+
evidence: { path: stateDbPath, durationMs: probe.durationMs },
|
|
284
|
+
});
|
|
285
|
+
const taskRows = queryTaskHistory(db, { since });
|
|
286
|
+
const taskRowsWithLogs = taskRows.filter((row) => row.log_path !== null);
|
|
287
|
+
const existingLogRows = taskRowsWithLogs.filter((row) => row.log_path && fs.existsSync(row.log_path));
|
|
288
|
+
const failedTaskRows = taskRows.filter((row) => row.status === "failed");
|
|
289
|
+
const activeRows = taskRows.filter((row) => row.status === "active");
|
|
290
|
+
const stuckActiveRuns = activeRows.filter((row) => Date.now() - new Date(row.started_at).getTime() > ACTIVE_RUN_WARN_MS).length;
|
|
291
|
+
const promptRows = taskRows.filter((row) => row.target_kind === "prompt");
|
|
292
|
+
const promptFailures = promptRows.filter((row) => {
|
|
293
|
+
const detail = parseTaskMetadata(row).detail;
|
|
294
|
+
return typeof detail?.reason === "string" && detail.reason.length > 0;
|
|
295
|
+
});
|
|
296
|
+
const logBackingRate = taskRowsWithLogs.length === 0 ? 1 : existingLogRows.length / taskRowsWithLogs.length;
|
|
297
|
+
const taskFailRate = taskRows.length === 0 ? 0 : failedTaskRows.length / taskRows.length;
|
|
298
|
+
const agentFailureRate = promptRows.length === 0 ? 0 : promptFailures.length / promptRows.length;
|
|
299
|
+
hardChecks.push({
|
|
300
|
+
name: "task-history-read",
|
|
301
|
+
kind: "deterministic",
|
|
302
|
+
status: "pass",
|
|
303
|
+
confidence: "high",
|
|
304
|
+
message: `Read ${taskRows.length} task-history row(s) since ${since}.`,
|
|
305
|
+
evidence: { rows: taskRows.length, since },
|
|
306
|
+
});
|
|
307
|
+
hardChecks.push({
|
|
308
|
+
name: "task-log-backing",
|
|
309
|
+
kind: "deterministic",
|
|
310
|
+
status: logBackingRate === 1 ? "pass" : "fail",
|
|
311
|
+
confidence: "high",
|
|
312
|
+
message: logBackingRate === 1
|
|
313
|
+
? "Every task_history log_path resolved on disk."
|
|
314
|
+
: `${taskRowsWithLogs.length - existingLogRows.length} task log(s) referenced in task_history are missing.`,
|
|
315
|
+
evidence: { totalWithLogs: taskRowsWithLogs.length, existingLogs: existingLogRows.length },
|
|
316
|
+
});
|
|
317
|
+
hardChecks.push({
|
|
318
|
+
name: "active-runs",
|
|
319
|
+
kind: "deterministic",
|
|
320
|
+
status: stuckActiveRuns === 0 ? "pass" : "warn",
|
|
321
|
+
confidence: "high",
|
|
322
|
+
message: stuckActiveRuns === 0
|
|
323
|
+
? "No active task runs exceeded the stale threshold."
|
|
324
|
+
: `${stuckActiveRuns} active task run(s) are older than ${Math.round(ACTIVE_RUN_WARN_MS / 60000)} minutes.`,
|
|
325
|
+
evidence: { stuckActiveRuns },
|
|
326
|
+
});
|
|
327
|
+
hardChecks.push(runAgentProbe());
|
|
328
|
+
const semanticStatus = readSemanticStatus();
|
|
329
|
+
advisories.push({
|
|
330
|
+
name: "semantic-search-runtime",
|
|
331
|
+
kind: "deterministic",
|
|
332
|
+
status: !semanticStatus ||
|
|
333
|
+
semanticStatus.status === "pending" ||
|
|
334
|
+
semanticStatus.status === "ready-js" ||
|
|
335
|
+
semanticStatus.status === "ready-vec"
|
|
336
|
+
? "pass"
|
|
337
|
+
: "warn",
|
|
338
|
+
confidence: "medium",
|
|
339
|
+
message: semanticStatus
|
|
340
|
+
? `Semantic search status: ${semanticStatus.status}`
|
|
341
|
+
: "No semantic-search runtime status recorded yet.",
|
|
342
|
+
evidence: semanticStatus ? { ...semanticStatus } : undefined,
|
|
343
|
+
});
|
|
344
|
+
const improveInvoked = readEvents({ since, type: "improve_invoked" }, { dbPath: stateDbPath }).events.length;
|
|
345
|
+
const improveCompletedEvents = readEvents({ since, type: IMPROVE_COMPLETED_EVENT }, { dbPath: stateDbPath }).events;
|
|
346
|
+
const improveSkippedEvents = readEvents({ since, type: "improve_skipped" }, { dbPath: stateDbPath }).events;
|
|
347
|
+
const improveSummary = summarizeImproveCompleted(improveCompletedEvents);
|
|
348
|
+
improveSummary.invoked = improveInvoked;
|
|
349
|
+
const skipSummary = buildImproveSkipSummary(improveSkippedEvents);
|
|
350
|
+
improveSummary.skipped = skipSummary.skipped;
|
|
351
|
+
improveSummary.skipReasons = skipSummary.skipReasons;
|
|
352
|
+
let sessionLogEntries = [];
|
|
353
|
+
try {
|
|
354
|
+
const sinceDays = Math.max(0, Math.ceil((Date.now() - new Date(since).getTime()) / (24 * 60 * 60 * 1000)));
|
|
355
|
+
sessionLogEntries = getExecutionLogCandidatesFn(sinceDays).map((entry) => ({
|
|
356
|
+
topic: entry.topic,
|
|
357
|
+
frequency: entry.frequency,
|
|
358
|
+
source: entry.source,
|
|
359
|
+
isFailurePattern: entry.isFailurePattern,
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
sessionLogEntries = [];
|
|
364
|
+
}
|
|
365
|
+
advisories.push({
|
|
366
|
+
name: "session-log-failures",
|
|
367
|
+
kind: "heuristic",
|
|
368
|
+
status: sessionLogEntries.length === 0 ? "pass" : "warn",
|
|
369
|
+
confidence: sessionLogEntries.length === 0 ? "low" : "medium",
|
|
370
|
+
message: sessionLogEntries.length === 0
|
|
371
|
+
? "No repeated external session-log failure patterns were detected."
|
|
372
|
+
: `${sessionLogEntries.length} repeated external session-log failure pattern(s) detected.`,
|
|
373
|
+
evidence: { candidates: sessionLogEntries.slice(0, 5) },
|
|
374
|
+
});
|
|
375
|
+
const metrics = {
|
|
376
|
+
taskFailRate: roundRate(taskFailRate),
|
|
377
|
+
agentFailureRate: roundRate(agentFailureRate),
|
|
378
|
+
stuckActiveRuns,
|
|
379
|
+
logBackingRate: roundRate(logBackingRate),
|
|
380
|
+
probeRoundTripMs: probe.durationMs,
|
|
381
|
+
};
|
|
382
|
+
const hardFailure = hardChecks.some((check) => check.status === "fail");
|
|
383
|
+
const deterministicWarnings = [...hardChecks, ...advisories].some((check) => check.status === "warn" && check.kind === "deterministic");
|
|
384
|
+
const status = hardFailure ? "fail" : deterministicWarnings ? "warn" : "pass";
|
|
385
|
+
return {
|
|
386
|
+
schemaVersion: 1,
|
|
387
|
+
ok: !hardFailure,
|
|
388
|
+
status,
|
|
389
|
+
since,
|
|
390
|
+
hardChecks,
|
|
391
|
+
advisories,
|
|
392
|
+
metrics,
|
|
393
|
+
improve: improveSummary,
|
|
394
|
+
sessionLogAdvisories: sessionLogEntries,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
db.close();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Usage:
|
|
2
|
+
akm improve
|
|
3
|
+
akm improve <type>
|
|
4
|
+
akm improve <ref>
|
|
5
|
+
|
|
6
|
+
Description:
|
|
7
|
+
Analyze existing AKM assets and generate improvement proposals.
|
|
8
|
+
|
|
9
|
+
Modes:
|
|
10
|
+
akm improve
|
|
11
|
+
Improve all eligible assets in the current scope.
|
|
12
|
+
|
|
13
|
+
akm improve <type>
|
|
14
|
+
Improve all assets of a given type.
|
|
15
|
+
Example: akm improve memory
|
|
16
|
+
|
|
17
|
+
akm improve <ref>
|
|
18
|
+
Improve one specific asset.
|
|
19
|
+
Example: akm improve workflow:release-checklist
|
|
20
|
+
|
|
21
|
+
What it does:
|
|
22
|
+
- reviews feedback and recent history
|
|
23
|
+
- proposes edits to existing assets
|
|
24
|
+
- distills lessons where useful
|
|
25
|
+
- promotes durable skill lessons into skill reference-doc proposals when justified
|
|
26
|
+
- cleans and consolidates memories
|
|
27
|
+
- writes results to the proposal queue
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--task <text> Add extra guidance for this improvement pass
|
|
31
|
+
--dry-run Show planned actions without generating proposals
|
|
32
|
+
--target <source> Override the write target for accepted proposals
|
|
33
|
+
--auto-accept[=<value>]
|
|
34
|
+
Confidence threshold (0-100) for auto-accepting proposals.
|
|
35
|
+
Default when flag is absent: ON at threshold 90 (all sub-processes).
|
|
36
|
+
--auto-accept same as --auto-accept=90
|
|
37
|
+
--auto-accept=<N> integer 0-100; accept proposals at or above N
|
|
38
|
+
--auto-accept=safe alias for 90 (back-compat, not deprecated)
|
|
39
|
+
--auto-accept=false disable auto-accept for all sub-processes;
|
|
40
|
+
reflect/distill proposals go to the queue and
|
|
41
|
+
consolidation will prompt interactively on HTTP paths
|
|
42
|
+
Note: until proposals carry real confidence scores, any non-`false`
|
|
43
|
+
value behaves like the legacy "safe" mode (whole-batch auto-accept).
|
|
44
|
+
--profile <name> Improve profile to apply. Built-ins: default, quick,
|
|
45
|
+
thorough, memory-focus. User-defined profiles under
|
|
46
|
+
`profiles.improve.<name>` in config are also accepted.
|
|
47
|
+
Profiles bundle process gating, type filters,
|
|
48
|
+
cooldown overrides, and run-level autoAccept/limit
|
|
49
|
+
defaults. Falls back to `defaults.improve` in config,
|
|
50
|
+
then to "default". Unknown names fall back to default
|
|
51
|
+
with a warning.
|
|
52
|
+
--ignore-cooldown Disable reflect/distill/consolidate cooldown checks for this run
|
|
53
|
+
--reflect-cooldown-days <n>
|
|
54
|
+
Override reflect cooldown with a non-negative integer
|
|
55
|
+
--distill-cooldown-days <n>
|
|
56
|
+
Override distill cooldown with a non-negative integer
|
|
57
|
+
--consolidate-cooldown-days <n>
|
|
58
|
+
Override consolidate cooldown with a non-negative integer
|
|
59
|
+
--consolidate-recovery <mode>
|
|
60
|
+
Recovery mode for stale consolidate journals: abort (default) or clean
|
|
61
|
+
--require-feedback-signal
|
|
62
|
+
Only process refs with recent feedback signal events
|
|
63
|
+
--min-retrieval-count <n>
|
|
64
|
+
Retrieval fallback threshold when no recent feedback exists (default: 5)
|
|
65
|
+
--json-to-stdout Emit the full JSON result on stdout (legacy behaviour).
|
|
66
|
+
(0.8.0+: full result is recorded in the improve_runs table of
|
|
67
|
+
state.db and stdout is empty; use --json-to-stdout for the prior
|
|
68
|
+
behaviour, e.g. `akm improve --json-to-stdout | jq`.)
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
akm improve
|
|
72
|
+
akm improve memory
|
|
73
|
+
akm improve skill
|
|
74
|
+
akm improve skill:code-review
|
|
75
|
+
akm improve workflow:incident-response --task "reduce duplication"
|
|
76
|
+
akm improve --profile quick
|
|
77
|
+
akm improve --profile memory-focus
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Usage:
|
|
2
|
+
akm proposals
|
|
3
|
+
|
|
4
|
+
Description:
|
|
5
|
+
List proposal queue entries.
|
|
6
|
+
|
|
7
|
+
Options:
|
|
8
|
+
--status <status> Filter by pending, accepted, or rejected
|
|
9
|
+
--type <type> Filter by asset type
|
|
10
|
+
--ref <ref> Filter by exact asset ref
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
akm proposals
|
|
14
|
+
akm proposals --status pending
|
|
15
|
+
akm proposals --type skill
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Usage:
|
|
2
|
+
akm propose <type> <name> --task "..."
|
|
3
|
+
akm propose <type> <name> --file <path>
|
|
4
|
+
|
|
5
|
+
Description:
|
|
6
|
+
Create a proposal for a brand-new AKM asset.
|
|
7
|
+
|
|
8
|
+
Input:
|
|
9
|
+
--task <text> Inline task or prompt text
|
|
10
|
+
--file <path> Read task or prompt text from a file
|
|
11
|
+
|
|
12
|
+
Rules:
|
|
13
|
+
Exactly one of --task or --file is required.
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
akm propose skill release-auditor --task "review release artifacts before publish"
|
|
17
|
+
akm propose workflow hotfix-triage --file ./prompts/hotfix-triage.md
|