akm-cli 0.10.261016-beta → 0.10.261018-beta
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 +144 -0
- package/README.md +8 -10
- package/SECURITY.md +7 -99
- package/STABILITY.md +57 -98
- package/dist/assets/opencode/akm-plugin.js +103 -1
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -2
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +11 -17
- package/dist/cli.js +32 -41
- package/dist/commands/feedback-cli.js +5 -4
- package/dist/commands/health.js +15 -16
- package/dist/commands/proposal/proposal-cli.js +1 -1
- package/dist/commands/read/registry-search.js +4 -1
- package/dist/commands/read/search.js +6 -6
- package/dist/commands/sources/self-update.js +9 -5
- package/dist/commands/tasks/tasks.js +12 -13
- package/dist/core/adapter/adapters/agent-skills-adapter.js +7 -7
- package/dist/core/adapter/adapters/akm-task-adapter.js +1 -1
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/adapters/claude-adapter.js +1 -1
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +1 -1
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +1 -1
- package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -1
- package/dist/core/bundle-rename.js +17 -7
- package/dist/core/config/convert-engine-references.js +23 -7
- package/dist/core/config/convert-engines.js +94 -28
- package/dist/core/config/convert-models-overlay.js +14 -2
- package/dist/indexer/bundle-identity-guard.js +6 -6
- package/dist/indexer/index-written-assets.js +3 -3
- package/dist/indexer/indexer.js +12 -8
- package/dist/indexer/materialize-embeddings.js +12 -2
- package/dist/indexer/passes/metadata.js +103 -46
- package/dist/indexer/search/ranking.js +7 -3
- package/dist/indexer/search/search-fields.js +1 -1
- package/dist/indexer/usage/usage-events.js +30 -8
- package/dist/indexer/walk/walker.js +1 -1
- package/dist/integrations/agent/spawn.js +7 -2
- package/dist/integrations/harnesses/opencode/agent-builder.js +10 -1
- package/dist/integrations/harnesses/opencode/runtime/binary.js +6 -3
- package/dist/integrations/harnesses/opencode/runtime/index.js +18 -9
- package/dist/integrations/harnesses/opencode/session-log-v2.js +11 -1
- package/dist/output/shapes/helpers.js +3 -3
- package/dist/output/text/command-format.js +5 -6
- package/dist/scripts/akm-migrate-node.js +122 -36
- package/dist/scripts/akm-migrate.js +122 -36
- package/dist/sources/providers/git-provider.js +2 -4
- package/dist/sources/providers/provider-utils.js +8 -13
- package/dist/sources/snapshot-fetchers/website-ingest.js +6 -7
- package/dist/storage/repositories/events-repository.js +15 -0
- package/dist/storage/repositories/improve-ledger-repository.js +13 -0
- package/dist/storage/repositories/index-entries-repository.js +43 -5
- package/dist/storage/repositories/outcome-repository.js +12 -0
- package/dist/storage/repositories/proposals-repository.js +5 -5
- package/dist/storage/repositories/salience-repository.js +13 -0
- package/dist/storage/repositories/task-history-repository.js +8 -7
- package/dist/storage/repositories/workflow-runs-repository.js +10 -8
- package/docs/README.md +24 -60
- package/docs/agents/README.md +3 -8
- package/docs/architecture/README.md +18 -20
- package/docs/architecture/adapters.md +40 -43
- package/docs/architecture/architecture.md +180 -154
- package/docs/architecture/improvement.md +95 -91
- package/docs/architecture/internals/classification.md +101 -119
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +33 -35
- package/docs/architecture/internals/health-advisories.md +59 -46
- package/docs/architecture/internals/improve-workflow.md +166 -693
- package/docs/architecture/internals/indexing.md +65 -465
- package/docs/architecture/internals/storage-locations.md +301 -848
- package/docs/architecture/persisted-data-compat.md +6 -6
- package/docs/architecture/specs/okf-support.md +67 -95
- package/docs/architecture/specs/ref.md +67 -125
- package/docs/architecture/testing/testing-workflow.md +108 -168
- package/docs/architecture/workflow-engine.md +34 -33
- package/docs/guides/README.md +5 -5
- package/docs/guides/author-bundles.md +72 -98
- package/docs/guides/author-workflows.md +11 -18
- package/docs/guides/bundles.md +91 -123
- package/docs/guides/capture-knowledge.md +10 -9
- package/docs/guides/concepts.md +45 -30
- package/docs/guides/discover-and-load.md +39 -32
- package/docs/guides/getting-started.md +24 -24
- package/docs/guides/improve-the-library.md +98 -80
- package/docs/guides/recipes/headless-install.md +4 -4
- package/docs/guides/recipes/website-source.md +9 -5
- package/docs/guides/run-workflows.md +10 -11
- package/docs/guides/scheduling.md +11 -17
- package/docs/guides/use-with-any-agent.md +15 -14
- package/docs/guides/wikis.md +6 -9
- package/docs/integration/bundling-akm.md +21 -26
- package/docs/maintainers/README.md +2 -2
- package/docs/maintainers/local-development.md +3 -16
- package/docs/migration/README.md +2 -1
- package/docs/migration/release-notes/0.10.0.md +196 -23
- package/docs/migration/release-notes/README.md +2 -2
- package/docs/migration/v0.9-to-v0.10.md +103 -12
- package/docs/product-surface.md +10 -8
- package/docs/reference/README.md +26 -15
- package/docs/reference/asset-types.md +11 -12
- package/docs/reference/bundle-types.md +6 -5
- package/docs/reference/cli.md +52 -28
- package/docs/reference/configuration.md +91 -73
- package/docs/reference/data-and-telemetry.md +204 -421
- package/docs/reference/env-and-secrets.md +80 -83
- package/docs/reference/memory.md +1 -1
- package/docs/reference/refs.md +23 -36
- package/docs/reference/registry.md +138 -348
- package/docs/reference/supported-formats.md +8 -8
- package/docs/reference/tasks.md +13 -19
- package/docs/reference/website-sources.md +23 -15
- package/docs/reference/workflow-schema.md +28 -47
- package/docs/reference/workflows.md +33 -37
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -112,9 +112,6 @@ function applyEarlyStderrFlags(argv) {
|
|
|
112
112
|
setVerbose(true);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
// resolveHelpMigrateVersionArg moved to ./cli/invocation (chunk-9 WI-9.9
|
|
116
|
-
// argv-normalization fold — it re-scanned process.argv, same as
|
|
117
|
-
// findCittyTopLevelCommand and parseAllFlagValues below).
|
|
118
115
|
/**
|
|
119
116
|
* Stderr-only human-friendly hint after a non-interactive `setup` invocation.
|
|
120
117
|
* Default --format is `json`, so a CI or piped consumer sees only the JSON on
|
|
@@ -155,10 +152,9 @@ const setupCommand = defineCommand({
|
|
|
155
152
|
description: "Interactive configuration wizard. Enables agent programs (Claude Code, Codex, OpenCode, ...), sets up a model connection and embeddings, and picks bundle sources and registries. Flags answer individual questions; --yes takes the detected default for the rest, for scripting.",
|
|
156
153
|
},
|
|
157
154
|
args: {
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
// this in is a `--help` visibility fix, not a behavior change.
|
|
155
|
+
// `setup` is a raw `defineCommand` (not `defineJsonCommand`), so it does
|
|
156
|
+
// not get `GLOBAL_OUTPUT_ARGS` for free. Three of its four run branches
|
|
157
|
+
// call `output()`; spreading this in is a `--help` visibility fix.
|
|
162
158
|
...GLOBAL_OUTPUT_ARGS,
|
|
163
159
|
endpoint: {
|
|
164
160
|
type: "string",
|
|
@@ -285,11 +281,11 @@ const healthCommand = defineCommand({
|
|
|
285
281
|
description: "Check akm runtime health, artifacts, and improve metrics",
|
|
286
282
|
},
|
|
287
283
|
args: {
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
// `--output`
|
|
284
|
+
// `health` is a raw `defineCommand` (not `defineJsonCommand`), so it does
|
|
285
|
+
// not get `GLOBAL_OUTPUT_ARGS` for free. `--format`/`--detail`/
|
|
286
|
+
// `--output` parse correctly here regardless (this command has
|
|
291
287
|
// no positional for a stray value to fall into), so this is purely a
|
|
292
|
-
// `--help` visibility / consistency
|
|
288
|
+
// `--help` visibility / consistency measure.
|
|
293
289
|
...GLOBAL_OUTPUT_ARGS,
|
|
294
290
|
since: {
|
|
295
291
|
type: "string",
|
|
@@ -389,8 +385,8 @@ const healthCommand = defineCommand({
|
|
|
389
385
|
}
|
|
390
386
|
output("health", base);
|
|
391
387
|
});
|
|
392
|
-
//
|
|
393
|
-
//
|
|
388
|
+
// `emitJsonError` (src/cli/shared.ts) does not force-exit on the error
|
|
389
|
+
// path — it sets `process.exitCode` and returns, so a `--report`
|
|
394
390
|
// failure thrown AFTER `resultStatus` was already assigned (e.g. the
|
|
395
391
|
// proposal-queue read above) would otherwise leave `resultStatus`
|
|
396
392
|
// populated here too. Skip the status-derived exit entirely once
|
|
@@ -443,14 +439,12 @@ const completionsCommand = defineCommand({
|
|
|
443
439
|
},
|
|
444
440
|
},
|
|
445
441
|
run({ args }) {
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// same error-classification wrapper other bare `defineCommand`s in this
|
|
453
|
-
// file use, e.g. `help migrate` below).
|
|
442
|
+
// An unsupported `--shell` value must reach the standard JSON envelope as
|
|
443
|
+
// the classified exit-2 usage error, not escape to citty's top-level error
|
|
444
|
+
// handling as a raw stack trace (`completions` is format-exempt, so it
|
|
445
|
+
// stays a raw `defineCommand` rather than `defineJsonCommand`, but still
|
|
446
|
+
// needs the same error-classification wrapper other bare `defineCommand`s
|
|
447
|
+
// in this file use, e.g. `help migrate` below).
|
|
454
448
|
return runWithJsonErrors(() => {
|
|
455
449
|
if (args.shell !== "bash") {
|
|
456
450
|
throw new UsageError(`Unsupported shell: ${args.shell}. Only bash is supported.`);
|
|
@@ -678,7 +672,7 @@ const EXIT_GENERAL = EXIT_CODES.GENERAL;
|
|
|
678
672
|
const EXIT_HEALTH_WARN = EXIT_CODES.HEALTH_WARN;
|
|
679
673
|
// ── Top-level driver (replaces citty's `runMain`) ───────────────────────────
|
|
680
674
|
//
|
|
681
|
-
//
|
|
675
|
+
// citty's own `runMain` catches EVERY error escaping `runCommand` —
|
|
682
676
|
// including its unexported `CLIError`, thrown for "Unknown command …", "No
|
|
683
677
|
// command specified.", "Missing required argument/positional …", and invalid
|
|
684
678
|
// enum values — and unconditionally calls `process.exit(1)`, regardless of
|
|
@@ -692,7 +686,7 @@ const EXIT_HEALTH_WARN = EXIT_CODES.HEALTH_WARN;
|
|
|
692
686
|
// of `runMain`, replicating `runMain`'s `--help` / `--version`
|
|
693
687
|
// short-circuits and its CLIError → usage-banner rendering, but classifying
|
|
694
688
|
// a CLIError as USAGE (2) instead of GENERAL (1). Every other error escaping
|
|
695
|
-
// this boundary keeps the
|
|
689
|
+
// this boundary keeps the GENERAL (1) mapping — this only
|
|
696
690
|
// reclassifies the one error family citty itself throws before any of our
|
|
697
691
|
// own command bodies (and their `runWithJsonErrors` / `emitJsonError`
|
|
698
692
|
// classification) ever run.
|
|
@@ -762,7 +756,7 @@ function resolveCittyCommandPath(cmd, rawArgs, path = []) {
|
|
|
762
756
|
* dropping the `akm ` root prefix every top-level command's `--help` already
|
|
763
757
|
* shows. Building a synthetic parent whose `meta.name` is the full prefix
|
|
764
758
|
* (`akm task`) fixes it for any depth without patching the vendored
|
|
765
|
-
* dependency
|
|
759
|
+
* dependency.
|
|
766
760
|
*/
|
|
767
761
|
function buildUsageParentForPath(path) {
|
|
768
762
|
// `version` carries through too — citty's renderUsage falls back to
|
|
@@ -776,7 +770,7 @@ function buildUsageParentForPath(path) {
|
|
|
776
770
|
},
|
|
777
771
|
};
|
|
778
772
|
}
|
|
779
|
-
// ── Sectioned root help
|
|
773
|
+
// ── Sectioned root help ────────────────────────────────────────────────
|
|
780
774
|
//
|
|
781
775
|
// citty's own generated COMMANDS list is a flat, unordered dump of every
|
|
782
776
|
// top-level command — fine for a handful of commands, not for the ~28 this
|
|
@@ -853,7 +847,7 @@ function renderCommandSections() {
|
|
|
853
847
|
return HELP_SECTIONS.map(({ title, commands }) => `${title}\n${formatCommandRows(commands)}`).join("\n\n");
|
|
854
848
|
}
|
|
855
849
|
/**
|
|
856
|
-
* Sectioned replacement for citty's root COMMANDS list
|
|
850
|
+
* Sectioned replacement for citty's root COMMANDS list. Reuses
|
|
857
851
|
* `renderUsage(main)` for the banner + exit-code table (kept verbatim) +
|
|
858
852
|
* USAGE line + global OPTIONS, then cuts the string before citty's own
|
|
859
853
|
* "COMMANDS" heading (present because `main` has `subCommands`) and appends
|
|
@@ -938,7 +932,7 @@ function cittyCliErrorUsageCode(error) {
|
|
|
938
932
|
}
|
|
939
933
|
/**
|
|
940
934
|
* Route a citty `CLIError` through the standard JSON envelope instead of
|
|
941
|
-
* citty's own usage-banner + raw `console.error(message)
|
|
935
|
+
* citty's own usage-banner + raw `console.error(message)`: the
|
|
942
936
|
* one-line diagnosis is the error's own message (e.g. "Unknown command
|
|
943
937
|
* foo"), and the hint is a short pointer — with a did-you-mean suggestion
|
|
944
938
|
* prepended when the unresolved token is close to a real sibling command —
|
|
@@ -962,12 +956,10 @@ export function normalizeCittyCliError(error, rawArgs) {
|
|
|
962
956
|
}
|
|
963
957
|
/**
|
|
964
958
|
* The CLI's real startup sequence, extracted into a function so error paths
|
|
965
|
-
* can `return` early — top-level `return` is a syntax error in an ES module
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
* and returns, every direct call site here needs its own explicit `return;`
|
|
970
|
-
* to stop the rest of startup from running after a fatal early error.
|
|
959
|
+
* can `return` early — top-level `return` is a syntax error in an ES module.
|
|
960
|
+
* `emitJsonError` (src/cli/shared.ts) only records `process.exitCode` and
|
|
961
|
+
* returns, so every direct call site here needs its own explicit `return;` to
|
|
962
|
+
* stop the rest of startup from running after a fatal early error.
|
|
971
963
|
*/
|
|
972
964
|
export async function runCli() {
|
|
973
965
|
try {
|
|
@@ -978,7 +970,7 @@ export async function runCli() {
|
|
|
978
970
|
return;
|
|
979
971
|
}
|
|
980
972
|
// Mint the ParsedInvocation singleton from the (normalized) argv — the ONE
|
|
981
|
-
// place argv is parsed for the whole process
|
|
973
|
+
// place argv is parsed for the whole process.
|
|
982
974
|
// Every out-of-cli.ts command module reads argv state through
|
|
983
975
|
// `getParsedInvocation()` from here on instead of re-scanning process.argv.
|
|
984
976
|
setParsedInvocation(process.argv);
|
|
@@ -1024,11 +1016,10 @@ export async function runCli() {
|
|
|
1024
1016
|
return;
|
|
1025
1017
|
}
|
|
1026
1018
|
const commandPath = resolveCittyCommandPath(main, process.argv.slice(2));
|
|
1027
|
-
//
|
|
1019
|
+
// Every command that renders through output() honours all six --format
|
|
1028
1020
|
// values. The declared exempt set (src/output/format-exempt.ts) does not
|
|
1029
1021
|
// render an envelope at all, so warn rather than pretend: silently ignoring
|
|
1030
|
-
// the flag
|
|
1031
|
-
// warning, not an error, because the flag is harmless here and scripts that
|
|
1022
|
+
// the flag makes the behaviour hard to discover. A warning, not an error, because the flag is harmless here and scripts that
|
|
1032
1023
|
// pass --format globally to a mixed batch of commands should still work.
|
|
1033
1024
|
const invocation = getParsedInvocation();
|
|
1034
1025
|
if ((invocation.hasFlag("--format") || invocation.getFlagValue("--format") !== undefined) &&
|
|
@@ -1082,7 +1073,7 @@ export async function runCli() {
|
|
|
1082
1073
|
if (HELP_FLAGS.some((flag) => ownArgs.includes(flag))) {
|
|
1083
1074
|
const resolved = resolveDeepestCittyCommand(main, rawArgs);
|
|
1084
1075
|
if (resolved === main) {
|
|
1085
|
-
// Root `--help
|
|
1076
|
+
// Root `--help`: the sectioned overview, not citty's
|
|
1086
1077
|
// flat COMMANDS dump.
|
|
1087
1078
|
process.stdout.write(`${await renderSectionedRootHelp()}\n`);
|
|
1088
1079
|
}
|
|
@@ -1097,14 +1088,14 @@ export async function runCli() {
|
|
|
1097
1088
|
return;
|
|
1098
1089
|
}
|
|
1099
1090
|
// citty's parseArgs (strict: false) silently ignores undeclared flags, so
|
|
1100
|
-
// a typo
|
|
1101
|
-
// --version, so those keep working on any command.
|
|
1091
|
+
// a typo would otherwise run the command with defaults and exit 0. Checked
|
|
1092
|
+
// here, after --help and --version, so those keep working on any command.
|
|
1102
1093
|
assertKnownFlags(main, rawArgs);
|
|
1103
1094
|
await runCommand(main, { rawArgs });
|
|
1104
1095
|
}
|
|
1105
1096
|
catch (error) {
|
|
1106
1097
|
if (isCittyCliError(error)) {
|
|
1107
|
-
//
|
|
1098
|
+
// Reclassify citty's own "unknown command" / "no command
|
|
1108
1099
|
// specified" / "missing required argument" family as USAGE (2) and
|
|
1109
1100
|
// route it through the SAME JSON envelope every other command's
|
|
1110
1101
|
// failure uses (`emitJsonError`), rather than citty's own usage-banner
|
|
@@ -435,10 +435,11 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
435
435
|
"next search; no reindex is needed. Each recorded positive raises the asset's\n" +
|
|
436
436
|
"score and each negative lowers it, the same way for every asset: the more\n" +
|
|
437
437
|
"positives, the higher it ranks (5 outrank 2), and each further vote counts\n" +
|
|
438
|
-
"for a little less. The effect is small
|
|
439
|
-
"
|
|
440
|
-
"feedback
|
|
441
|
-
"score that improve and
|
|
438
|
+
"for a little less. The effect is small: in keyword-only search one vote\n" +
|
|
439
|
+
"moves a hit one place, and with embeddings it breaks only near-ties. Only\n" +
|
|
440
|
+
"feedback recorded as the user counts, not feedback from improve, task or\n" +
|
|
441
|
+
"audit runs. Feedback also moves the utility score that improve and\n" +
|
|
442
|
+
"`akm metrics` read.",
|
|
442
443
|
},
|
|
443
444
|
args: {
|
|
444
445
|
// Optional in citty so run() is invoked even when omitted; we re-validate
|
package/dist/commands/health.js
CHANGED
|
@@ -72,21 +72,21 @@ function validateAkmHealthOptions(options) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
// ── akmHealth phase helpers (
|
|
76
|
-
//
|
|
75
|
+
// ── akmHealth phase helpers (the function's natural
|
|
76
|
+
// gather/advise/check/assemble phases) ──────────────────────────────────────
|
|
77
77
|
/** Event type appended + read back by the state.db round-trip probe. */
|
|
78
78
|
const HEALTH_PROBE_EVENT = "health_probe";
|
|
79
|
-
/** Synthetic sentinel ref
|
|
79
|
+
/** Synthetic sentinel ref: a colon-free
|
|
80
80
|
* `<subsystem>/_<marker>` label. `health` has no asset stash-subdir, so
|
|
81
81
|
* `health/_probe` names the subsystem. */
|
|
82
82
|
const HEALTH_PROBE_REF = "health/_probe";
|
|
83
83
|
/**
|
|
84
84
|
* Verify state.db can accept a write and read it back — WITHOUT leaving any
|
|
85
|
-
* permanent trace
|
|
86
|
-
*
|
|
87
|
-
* check
|
|
88
|
-
*
|
|
89
|
-
*
|
|
85
|
+
* permanent trace. Leaving the `health_probe` event in place after every
|
|
86
|
+
* `akm health` invocation would grow state.db without bound for a read-only
|
|
87
|
+
* health check run on a cron (the only purge is `improve`'s retention pass,
|
|
88
|
+
* which a health-only user never runs). The probe row inserted here is
|
|
89
|
+
* deleted again inside the SAME connection once the
|
|
90
90
|
* round trip is confirmed, so the net effect on the `events` table is always
|
|
91
91
|
* zero rows — the round trip still genuinely exercises append + read against
|
|
92
92
|
* the real table, it just doesn't accumulate.
|
|
@@ -132,7 +132,7 @@ export function probeStateDbRoundTrip(stateDbPath) {
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
135
|
+
* Dedupe stuck-active rows by task_id (keeping the oldest/largest age
|
|
136
136
|
* per id) so the `active-runs` check can name WHICH tasks are stuck instead of
|
|
137
137
|
* just a count. No pid/liveness probing — purely a projection of the rows
|
|
138
138
|
* already read.
|
|
@@ -148,7 +148,7 @@ function dedupeStuckActiveTasks(rows, now) {
|
|
|
148
148
|
return [...byTask.entries()].map(([taskId, ageMs]) => ({ taskId, ageMs }));
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
151
|
-
*
|
|
151
|
+
* Group task_history rows by task_id and return the one with the
|
|
152
152
|
* highest fail rate among tasks with at least MIN_ROWS_FOR_WORST_TASK_FAIL_RATE
|
|
153
153
|
* rows in the window — surfaces a consistently-failing task that a large,
|
|
154
154
|
* mostly-healthy population would otherwise hide behind the aggregate rate.
|
|
@@ -184,7 +184,7 @@ function gatherTaskHistoryPhase(db, since, stateDbPath, now, readOnly) {
|
|
|
184
184
|
const requiredTables = ["events", "proposals", "schema_migrations", "task_history"];
|
|
185
185
|
const missingTables = requiredTables.filter((name) => !tableNames.includes(name));
|
|
186
186
|
const probe = readOnly ? { ok: true, durationMs: null, skipped: true } : probeStateDbRoundTrip(stateDbPath);
|
|
187
|
-
//
|
|
187
|
+
// Read-only, independent of the round-trip probe above — integrity_check
|
|
188
188
|
// catches corruption a successful append/read cannot (out-of-order rowids,
|
|
189
189
|
// bad index entry counts), and the freelist reading is purely informational.
|
|
190
190
|
const stateDbIntegrity = runStateDbIntegrityCheck(stateDbPath);
|
|
@@ -251,7 +251,7 @@ function gatherAncillaryAdvisories(db, options, egressConfigView) {
|
|
|
251
251
|
const indexStateMismatch = detectIndexStateGenerationMismatch(db);
|
|
252
252
|
if (indexStateMismatch)
|
|
253
253
|
advisories.push(indexStateMismatch);
|
|
254
|
-
//
|
|
254
|
+
// Surface a `stash-git-exposure` advisory when env/secret assets are
|
|
255
255
|
// git-tracked AND a remote is configured (the leak moment). Best-effort.
|
|
256
256
|
// Cheap guard: only shell out to git when the stash has its OWN `.git` (or a
|
|
257
257
|
// test injected a fake seam), so the hot path never spawns for a non-git
|
|
@@ -295,8 +295,7 @@ function gatherAncillaryAdvisories(db, options, egressConfigView) {
|
|
|
295
295
|
catch {
|
|
296
296
|
// Non-fatal.
|
|
297
297
|
}
|
|
298
|
-
//
|
|
299
|
-
// own never gets the purge sweep, so its memory-cleanup archive only ever
|
|
298
|
+
// A bundle with no git history of its own never gets the purge sweep, so its memory-cleanup archive only ever
|
|
300
299
|
// grows — report its size and file count instead. Best-effort — an
|
|
301
300
|
// unreadable archive must not abort the health report.
|
|
302
301
|
try {
|
|
@@ -425,7 +424,7 @@ function detectIndexStateGenerationMismatch(stateDb) {
|
|
|
425
424
|
}
|
|
426
425
|
}
|
|
427
426
|
/**
|
|
428
|
-
*
|
|
427
|
+
* Window-compare mode. Resolves `--window-compare`/`--windows` into
|
|
429
428
|
* per-window bundles and computes deltas between the earliest and latest
|
|
430
429
|
* window. Top-level metrics retain the primary `--since` query.
|
|
431
430
|
*/
|
|
@@ -655,7 +654,7 @@ export async function akmHealth(options = {}) {
|
|
|
655
654
|
const hardFailure = hardChecks.some((check) => check.status === "fail");
|
|
656
655
|
const deterministicWarnings = [...hardChecks, ...advisories].some((check) => check.status === "warn" && check.kind === "deterministic");
|
|
657
656
|
const status = hardFailure ? "fail" : deterministicWarnings ? "warn" : "pass";
|
|
658
|
-
// ── Per-run mode
|
|
657
|
+
// ── Per-run mode ────────────────────────────────────────────
|
|
659
658
|
const runs = options.groupBy === "run" ? perRunSummaries : undefined;
|
|
660
659
|
return {
|
|
661
660
|
schemaVersion: 3,
|
|
@@ -390,7 +390,7 @@ const proposalDrainCommand = defineJsonCommand({
|
|
|
390
390
|
},
|
|
391
391
|
promote: {
|
|
392
392
|
type: "boolean",
|
|
393
|
-
description: "Promote (accept) matching proposals.
|
|
393
|
+
description: "Promote (accept) matching proposals. Without it, the strategy's apply mode decides, and the default strategy's is promote (akm#1274).",
|
|
394
394
|
default: false,
|
|
395
395
|
},
|
|
396
396
|
judgment: {
|
|
@@ -14,8 +14,11 @@ export async function searchRegistry(query, options) {
|
|
|
14
14
|
return { query: "", hits: [], warnings: [] };
|
|
15
15
|
}
|
|
16
16
|
const limit = clampLimit(options?.limit);
|
|
17
|
+
// AKM_REGISTRY_URL outranks the caller's list: `akm search` passes
|
|
18
|
+
// `config.registries`, which would otherwise shadow the override.
|
|
19
|
+
const envOverride = process.env.AKM_REGISTRY_URL?.trim() ? resolveRegistries() : undefined;
|
|
17
20
|
// resolveRegistries() already filters by enabled; explicit registries are filtered here
|
|
18
|
-
const raw = options?.registries ?? resolveRegistries();
|
|
21
|
+
const raw = envOverride ?? options?.registries ?? resolveRegistries();
|
|
19
22
|
const warnings = [];
|
|
20
23
|
const entries = (options?.registries ? raw.filter((r) => r.enabled !== false) : raw).filter((entry) => {
|
|
21
24
|
if (!hasRegistryUrlCredentials(entry.url))
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `akm search` — entry point.
|
|
6
6
|
*
|
|
7
7
|
* Search consults the local FTS5 index. There is one query path
|
|
8
|
-
* because there is one data store
|
|
8
|
+
* because there is one data store; there is no provider fan-out.
|
|
9
9
|
*
|
|
10
10
|
* The orchestration here is thin: build the FTS query, optionally interleave
|
|
11
11
|
* a registry search behind `--from registry|all`, and log a usage event.
|
|
@@ -214,9 +214,9 @@ function resolveEntryIds(db, hits) {
|
|
|
214
214
|
try {
|
|
215
215
|
const entryId = getEntryIdByFilePath(db, hit.path);
|
|
216
216
|
if (entryId !== undefined) {
|
|
217
|
-
//
|
|
218
|
-
// derived from the resolved entry row's `item_ref` (
|
|
219
|
-
//
|
|
217
|
+
// Persist the DURABLE fully-qualified `bundle//conceptId` spelling,
|
|
218
|
+
// derived from the resolved entry row's `item_ref` (durable keys come
|
|
219
|
+
// from the resolved item, never raw input).
|
|
220
220
|
const itemRef = getItemRefById(db, entryId);
|
|
221
221
|
if (itemRef !== null) {
|
|
222
222
|
results.push({ entryId, ref: itemRef, hit });
|
|
@@ -254,7 +254,7 @@ function logSearchEvent(rawQuery, response, mode = "keyword", eventSource = "use
|
|
|
254
254
|
// Emit a structured event to events.jsonl so workflow-trace consumers
|
|
255
255
|
// detect akm search invocations without relying on stdout scraping.
|
|
256
256
|
const stashHits = response.hits.filter((h) => h.type !== "registry");
|
|
257
|
-
//
|
|
257
|
+
// Include registry hit refs so a show following a registry-only search generates a select event
|
|
258
258
|
const registryHitRefs = (response.registryHits ?? []).map((h) => `registry:${h.id}`);
|
|
259
259
|
const allResultRefs = [...stashHits.map((h) => h.ref), ...registryHitRefs];
|
|
260
260
|
appendEvent({
|
|
@@ -267,7 +267,7 @@ function logSearchEvent(rawQuery, response, mode = "keyword", eventSource = "use
|
|
|
267
267
|
// Under contention these usage hints are skipped, not waited for.
|
|
268
268
|
withIndexDb((db) => {
|
|
269
269
|
const resolved = resolveEntryIds(db, stashHits.slice(0, 50));
|
|
270
|
-
// usage_events telemetry
|
|
270
|
+
// usage_events telemetry writes to state.db;
|
|
271
271
|
// entry_id/entry_ref are resolved from index.db above and carried across.
|
|
272
272
|
const stashHitCount = response.hits.length;
|
|
273
273
|
const registryHitCount = Array.isArray(response.registryHits) ? response.registryHits.length : 0;
|
|
@@ -7,7 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fetchWithRetry, IS_WINDOWS, ResponseTooLargeError, readBodyWithByteCap, readChunkWithDeadline, } from "../../core/common.js";
|
|
9
9
|
import { ConfigError } from "../../core/errors.js";
|
|
10
|
-
import { warn } from "../../core/warn.js";
|
|
10
|
+
import { isQuiet, warn } from "../../core/warn.js";
|
|
11
11
|
import { githubHeaders } from "../../integrations/github.js";
|
|
12
12
|
import { getDirname, mainPath, semverOrder } from "../../runtime.js";
|
|
13
13
|
import { resolveNpmGlobalRoot } from "../../tasks/resolve-akm-bin.js";
|
|
@@ -428,7 +428,11 @@ async function runMigrationStep(runTool) {
|
|
|
428
428
|
return { status: "failed", error: result.stderr.trim() || line || `akm-migrate exited ${result.status}` };
|
|
429
429
|
}
|
|
430
430
|
/**
|
|
431
|
-
* Rebuild the derived index after a successful upgrade.
|
|
431
|
+
* Rebuild the derived index after a successful upgrade. The first index after
|
|
432
|
+
* an upgrade can re-embed part of the corpus and take minutes, so the child's
|
|
433
|
+
* stderr (its progress lines) goes straight to the terminal; its stdout, never a
|
|
434
|
+
* terminal here, is captured. `--format json` keeps the progress on stderr
|
|
435
|
+
* whatever output format the user has configured, and `--quiet` is passed on.
|
|
432
436
|
*/
|
|
433
437
|
function runPostUpgradeTasks(akmBin, opts) {
|
|
434
438
|
if (opts.skip) {
|
|
@@ -439,10 +443,10 @@ function runPostUpgradeTasks(akmBin, opts) {
|
|
|
439
443
|
};
|
|
440
444
|
}
|
|
441
445
|
try {
|
|
442
|
-
const result = childProcess.spawnSync(akmBin, ["index"], {
|
|
446
|
+
const result = childProcess.spawnSync(akmBin, ["index", "--format", "json", ...(isQuiet() ? ["--quiet"] : [])], {
|
|
443
447
|
encoding: "utf8",
|
|
444
448
|
env: process.env,
|
|
445
|
-
stdio: "pipe",
|
|
449
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
446
450
|
});
|
|
447
451
|
if (result.error) {
|
|
448
452
|
return {
|
|
@@ -452,7 +456,7 @@ function runPostUpgradeTasks(akmBin, opts) {
|
|
|
452
456
|
};
|
|
453
457
|
}
|
|
454
458
|
if (result.status !== 0) {
|
|
455
|
-
const detail = (result.
|
|
459
|
+
const detail = (result.stdout ?? "").trim() || `exit code ${result.status}`;
|
|
456
460
|
return {
|
|
457
461
|
ok: false,
|
|
458
462
|
skipped: false,
|
|
@@ -178,10 +178,10 @@ export async function akmTasksRun(id, options = {}) {
|
|
|
178
178
|
const adapterId = bundle.source.adapterId ?? detectAdapterId(bundle.source.path);
|
|
179
179
|
const resolvedId = taskIdForAdapter(parsed.id, adapterId);
|
|
180
180
|
const scheduled = options.scheduled === true;
|
|
181
|
-
// Built ONCE at this invocation boundary. eventSource is "task"
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
181
|
+
// Built ONCE at this invocation boundary. eventSource is "task" whether or
|
|
182
|
+
// not --scheduled was passed — scheduled stays a separate field carrying its
|
|
183
|
+
// own meaning (activation policy, scheduler env), never selecting the event
|
|
184
|
+
// source.
|
|
185
185
|
const provenance = createExecutionProvenanceContext(scheduled);
|
|
186
186
|
// The raw, exact-name input flags `tasks-cli.ts`'s Stage 1 captures ride
|
|
187
187
|
// through unchanged to `runTask` -> `loadPreparedTask`'s Stage 2 materializer,
|
|
@@ -206,8 +206,8 @@ export async function akmTasksRun(id, options = {}) {
|
|
|
206
206
|
// projectability, and resolver failures therefore create no history row.
|
|
207
207
|
const result = await runTask(resolvedId, runOptions);
|
|
208
208
|
// "command" means the agent/LLM arm — the native shell/script arm reports
|
|
209
|
-
// "shell" / "script"
|
|
210
|
-
//
|
|
209
|
+
// "shell" / "script". A shell/script task's process exit 78 passes through
|
|
210
|
+
// as CLI exit 78 (documented behavior, src/assets/hints/cli-hints-short.md).
|
|
211
211
|
const exitCode = result.status === "failed" &&
|
|
212
212
|
(result.target.kind === "shell" || result.target.kind === "script") &&
|
|
213
213
|
result.detail?.exitCode === 78
|
|
@@ -597,10 +597,9 @@ export async function akmTasksDoctor(deps = {}) {
|
|
|
597
597
|
const config = loadConfig();
|
|
598
598
|
const defaultEngine = (defaultHarness(config) ?? defaultConnection(config))?.name;
|
|
599
599
|
const engines = [...Object.keys(config.connections ?? {}), ...Object.keys(config.harnesses ?? {})];
|
|
600
|
-
//
|
|
601
|
-
// strategy. The struct is a fixed shape, so this is a deliberate addition.
|
|
600
|
+
// Surface the effective triage settings for the default improve strategy.
|
|
602
601
|
const improveStrategyName = config.improve?.strategy ?? "default";
|
|
603
|
-
//
|
|
602
|
+
// Report the EFFECTIVE strategy, not the raw one. Resolving the raw
|
|
604
603
|
// strategy here would report `applyMode: "promote"` for a promote strategy
|
|
605
604
|
// under a review-first config, while the run actually uses "queue" — a doctor
|
|
606
605
|
// command lying about the thing it exists to diagnose.
|
|
@@ -753,7 +752,7 @@ function errorMessage(cause) {
|
|
|
753
752
|
}
|
|
754
753
|
/**
|
|
755
754
|
* Infer a JSON-Schema-subset `type` keyword from one `--params` value's
|
|
756
|
-
* runtime shape. `null` is not one of the five runtime types
|
|
755
|
+
* runtime shape. `null` is not one of the five usual runtime types
|
|
757
756
|
* (string/number/boolean/object/array) but is a value JSON.parse can still
|
|
758
757
|
* produce for a param; `src/core/json-schema.ts`'s subset validator accepts
|
|
759
758
|
* `"null"` as a `type`, so it is handled rather than mis-typed.
|
|
@@ -768,9 +767,9 @@ function jsonSchemaTypeOf(value) {
|
|
|
768
767
|
/**
|
|
769
768
|
* Render `--params` as typed `inputs:` declarations, one per key, each
|
|
770
769
|
* carrying a `default:` equal to the authored value and a `type:` inferred
|
|
771
|
-
* from its own JSON runtime shape
|
|
772
|
-
* task source v4 accepts `with:` only on `uses: akm/command`
|
|
773
|
-
* `parseTarget`/`checkTopLevelKeys`), and a workflow target's declared
|
|
770
|
+
* from its own JSON runtime shape. Never emitted as `with:` —
|
|
771
|
+
* task source v4 accepts `with:` only on `uses: akm/command`
|
|
772
|
+
* (`parseTarget`/`checkTopLevelKeys`), and a workflow target's declared
|
|
774
773
|
* inputs are what `load-task.ts`'s existing v4 delivery override binds into
|
|
775
774
|
* the child run's params.
|
|
776
775
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
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
4
|
/**
|
|
5
|
-
* The `agent-skills` adapter
|
|
5
|
+
* The `agent-skills` adapter.
|
|
6
6
|
*
|
|
7
7
|
* Recognizes a COLLECTION of standalone SKILL.md packages (like
|
|
8
8
|
* github.com/anthropics/skills): each `<name>/SKILL.md` is one `skill` item
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*
|
|
39
39
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
40
40
|
* `tests/fixtures/bundles/agent-skills/` + goldens
|
|
41
|
-
* `tests/fixtures/format-family-goldens/agent-skills/{recognition,
|
|
41
|
+
* `tests/fixtures/format-family-goldens/agent-skills/{recognition,lint,renderer}.json`.
|
|
42
42
|
*/
|
|
43
43
|
import fs from "node:fs";
|
|
44
44
|
import path from "node:path";
|
|
@@ -52,7 +52,7 @@ const SKILL_MANIFEST = "SKILL.md";
|
|
|
52
52
|
/** Agent Skills hard limits. */
|
|
53
53
|
const NAME_MAX = 64;
|
|
54
54
|
const DESCRIPTION_MAX = 1024;
|
|
55
|
-
/** Agent Skills reserved words a name must not contain
|
|
55
|
+
/** Agent Skills reserved words a name must not contain. */
|
|
56
56
|
const RESERVED_NAME_WORDS = ["anthropic", "claude"];
|
|
57
57
|
/** name charset/shape rule. */
|
|
58
58
|
const NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
@@ -98,7 +98,7 @@ function recognize(c, file) {
|
|
|
98
98
|
doc.tags = tags;
|
|
99
99
|
return doc;
|
|
100
100
|
}
|
|
101
|
-
/** The Agent Skills
|
|
101
|
+
/** The Agent Skills hard-rule checks for one SKILL.md (name + description). */
|
|
102
102
|
function skillFieldDiagnostics(relPath, dirName, data) {
|
|
103
103
|
const diagnostics = [];
|
|
104
104
|
const name = typeof data.name === "string" ? data.name.normalize("NFKC") : "";
|
|
@@ -176,8 +176,8 @@ async function scanPackageCandidate(dir, entries, ctx, depth) {
|
|
|
176
176
|
*
|
|
177
177
|
* `validate` walks CHANGES, and a change is always a file — so a package
|
|
178
178
|
* directory carrying resources but no manifest contributes nothing the
|
|
179
|
-
* change-loop can see, and the check the
|
|
180
|
-
*
|
|
179
|
+
* change-loop can see, and the check the lint golden's `missingSkillMd` edge
|
|
180
|
+
* case names would be unreachable. This scans the
|
|
181
181
|
* component root through {@link ValidateContext.list} instead, so the case is
|
|
182
182
|
* actually reported.
|
|
183
183
|
*
|
|
@@ -230,7 +230,7 @@ export const agentSkillsAdapter = {
|
|
|
230
230
|
readCandidates(c, conceptId) {
|
|
231
231
|
return [{ path: path.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
|
|
232
232
|
},
|
|
233
|
-
/** Install-time probe
|
|
233
|
+
/** Install-time probe: a root that directly contains one or more `<name>/SKILL.md` skill packages. */
|
|
234
234
|
looksLikeRoot(root) {
|
|
235
235
|
let entries;
|
|
236
236
|
try {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
28
28
|
* `tests/fixtures/bundles/akm-task/` + goldens
|
|
29
|
-
* `tests/fixtures/format-family-goldens/akm-task/{recognition,
|
|
29
|
+
* `tests/fixtures/format-family-goldens/akm-task/{recognition,lint,renderer}.json`.
|
|
30
30
|
*/
|
|
31
31
|
import fs from "node:fs";
|
|
32
32
|
import path from "node:path";
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
17
17
|
* `tests/fixtures/bundles/akm-workflow/` + goldens
|
|
18
|
-
* `tests/fixtures/format-family-goldens/akm-workflow/{recognition,
|
|
18
|
+
* `tests/fixtures/format-family-goldens/akm-workflow/{recognition,lint,renderer}.json`.
|
|
19
19
|
*/
|
|
20
20
|
import fs from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
18
18
|
* `tests/fixtures/bundles/claude/` + goldens
|
|
19
|
-
* `tests/fixtures/format-family-goldens/claude/{recognition,
|
|
19
|
+
* `tests/fixtures/format-family-goldens/claude/{recognition,lint,renderer}.json`.
|
|
20
20
|
*/
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import path from "node:path";
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*
|
|
26
26
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
27
27
|
* `tests/fixtures/bundles/dotenv/` + goldens
|
|
28
|
-
* `tests/fixtures/format-family-goldens/dotenv/{recognition,
|
|
28
|
+
* `tests/fixtures/format-family-goldens/dotenv/{recognition,lint,renderer}.json`.
|
|
29
29
|
*/
|
|
30
30
|
import fs from "node:fs";
|
|
31
31
|
import path from "node:path";
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
21
21
|
* `tests/fixtures/bundles/generic-files/` + goldens
|
|
22
|
-
* `tests/fixtures/format-family-goldens/generic-files/{recognition,
|
|
22
|
+
* `tests/fixtures/format-family-goldens/generic-files/{recognition,lint,renderer}.json`.
|
|
23
23
|
*/
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
13
13
|
* `tests/fixtures/bundles/llm-wiki/` + goldens
|
|
14
|
-
* `tests/fixtures/format-family-goldens/llm-wiki/{recognition,
|
|
14
|
+
* `tests/fixtures/format-family-goldens/llm-wiki/{recognition,renderer,lint}.json`.
|
|
15
15
|
* The adapter is built to MATCH those goldens (driven by
|
|
16
16
|
* `tests/core/adapter/llm-wiki-adapter.test.ts`).
|
|
17
17
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
18
18
|
* `tests/fixtures/bundles/opencode/` + goldens
|
|
19
|
-
* `tests/fixtures/format-family-goldens/opencode/{recognition,
|
|
19
|
+
* `tests/fixtures/format-family-goldens/opencode/{recognition,lint,renderer}.json`.
|
|
20
20
|
*/
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import path from "node:path";
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
24
24
|
* `tests/fixtures/bundles/website-snapshot/` + goldens
|
|
25
|
-
* `tests/fixtures/format-family-goldens/website-snapshot/{recognition,
|
|
25
|
+
* `tests/fixtures/format-family-goldens/website-snapshot/{recognition,lint,renderer}.json`.
|
|
26
26
|
*/
|
|
27
27
|
import fs from "node:fs";
|
|
28
28
|
import path from "node:path";
|