akm-cli 0.10.261019 → 0.10.261020-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 +18 -0
- package/dist/commands/health/plugin-staleness.js +126 -112
- package/dist/commands/sources/plugin-channels.js +147 -0
- package/dist/commands/sources/plugin-upgrade.js +341 -59
- package/dist/commands/sources/self-update.js +6 -3
- package/dist/commands/sources/sources-cli.js +15 -2
- package/dist/indexer/passes/metadata.js +8 -6
- package/dist/output/text/command-format.js +10 -3
- package/dist/scripts/akm-migrate-node.js +13 -7
- package/dist/scripts/akm-migrate.js +13 -7
- package/docs/architecture/internals/health-advisories.md +2 -2
- package/docs/architecture/testing/testing-workflow.md +13 -7
- package/docs/migration/release-notes/0.10.261020.md +22 -0
- package/docs/migration/release-notes/README.md +1 -0
- package/docs/reference/cli.md +37 -9
- package/package.json +3 -1
|
@@ -875,9 +875,9 @@ function isMarkdownFenceClosing(line, fence) {
|
|
|
875
875
|
* Version of what {@link projectMarkdownContent} indexes. It is part of every
|
|
876
876
|
* directory's index fingerprint, so bumping it makes the next `akm index`
|
|
877
877
|
* re-project every directory once instead of keeping the old text for
|
|
878
|
-
* unchanged files.
|
|
878
|
+
* unchanged files. 3: count each fenced identifier once per document (akm#1284).
|
|
879
879
|
*/
|
|
880
|
-
export const CONTENT_PROJECTION_VERSION =
|
|
880
|
+
export const CONTENT_PROJECTION_VERSION = 3;
|
|
881
881
|
/** At or above this length a token with a digit reads as a key or hash, not a name. */
|
|
882
882
|
const TOKEN_LIKE_MIN_LENGTH = 20;
|
|
883
883
|
/**
|
|
@@ -1114,7 +1114,7 @@ export function projectMarkdownContent(body, truncationInfo) {
|
|
|
1114
1114
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
1115
1115
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
1116
1116
|
const projected = [];
|
|
1117
|
-
const fenced =
|
|
1117
|
+
const fenced = new Map();
|
|
1118
1118
|
forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
|
|
1119
1119
|
let trimmed = visible.trim();
|
|
1120
1120
|
if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
|
|
@@ -1135,11 +1135,13 @@ export function projectMarkdownContent(body, truncationInfo) {
|
|
|
1135
1135
|
projected.push(trimmed);
|
|
1136
1136
|
}, (_index, fencedLine) => {
|
|
1137
1137
|
const identifiers = fencedCodeIdentifiers(fencedLine);
|
|
1138
|
-
|
|
1139
|
-
|
|
1138
|
+
for (const identifier of identifiers.split(/\s+/)) {
|
|
1139
|
+
if (identifier)
|
|
1140
|
+
fenced.set(identifier.toLowerCase(), identifier);
|
|
1141
|
+
}
|
|
1140
1142
|
});
|
|
1141
1143
|
// Fenced identifiers follow the prose, so a head-truncated embedding input keeps the prose first.
|
|
1142
|
-
const text = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
|
|
1144
|
+
const text = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
|
|
1143
1145
|
if (!text)
|
|
1144
1146
|
return undefined;
|
|
1145
1147
|
if (truncationInfo)
|
|
@@ -680,11 +680,15 @@ function formatUpgradePluginLines(r) {
|
|
|
680
680
|
}
|
|
681
681
|
const plugins = Array.isArray(r.plugins) ? r.plugins : [];
|
|
682
682
|
for (const p of plugins) {
|
|
683
|
-
if (p.outcome === "current" || p.outcome === "skipped")
|
|
683
|
+
if ((p.outcome === "current" || p.outcome === "skipped") &&
|
|
684
|
+
(r.updateAvailable === undefined || !p.channel) &&
|
|
685
|
+
!p.channelMismatch &&
|
|
686
|
+
!p.targetChannel)
|
|
684
687
|
continue;
|
|
685
688
|
const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} → v${p.to}` : "";
|
|
689
|
+
const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
|
|
686
690
|
const note = p.message ? ` (${p.message})` : "";
|
|
687
|
-
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
|
|
691
|
+
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
|
|
688
692
|
}
|
|
689
693
|
return lines;
|
|
690
694
|
}
|
|
@@ -698,8 +702,11 @@ function formatUpgradeHead(r) {
|
|
|
698
702
|
if (r.upgraded === true) {
|
|
699
703
|
return `akm upgraded: v${r.currentVersion} → v${r.newVersion}`;
|
|
700
704
|
}
|
|
705
|
+
if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
|
|
706
|
+
return `akm v${r.currentVersion} → v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
|
|
707
|
+
}
|
|
701
708
|
if (r.updateAvailable === true) {
|
|
702
|
-
return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
|
|
709
|
+
return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
|
|
703
710
|
}
|
|
704
711
|
if (r.updateAvailable === false && r.latestVersion) {
|
|
705
712
|
return `akm v${r.currentVersion} is already the latest version`;
|
|
@@ -34812,7 +34812,7 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
34812
34812
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
34813
34813
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
34814
34814
|
const projected = [];
|
|
34815
|
-
const fenced =
|
|
34815
|
+
const fenced = new Map;
|
|
34816
34816
|
forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
|
|
34817
34817
|
let trimmed = visible.trim();
|
|
34818
34818
|
if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
|
|
@@ -34832,10 +34832,12 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
34832
34832
|
projected.push(trimmed);
|
|
34833
34833
|
}, (_index, fencedLine) => {
|
|
34834
34834
|
const identifiers = fencedCodeIdentifiers(fencedLine);
|
|
34835
|
-
|
|
34836
|
-
|
|
34835
|
+
for (const identifier of identifiers.split(/\s+/)) {
|
|
34836
|
+
if (identifier)
|
|
34837
|
+
fenced.set(identifier.toLowerCase(), identifier);
|
|
34838
|
+
}
|
|
34837
34839
|
});
|
|
34838
|
-
const text2 = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
|
|
34840
|
+
const text2 = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
|
|
34839
34841
|
if (!text2)
|
|
34840
34842
|
return;
|
|
34841
34843
|
if (truncationInfo)
|
|
@@ -70528,11 +70530,12 @@ function formatUpgradePluginLines(r) {
|
|
|
70528
70530
|
}
|
|
70529
70531
|
const plugins = Array.isArray(r.plugins) ? r.plugins : [];
|
|
70530
70532
|
for (const p of plugins) {
|
|
70531
|
-
if (p.outcome === "current" || p.outcome === "skipped")
|
|
70533
|
+
if ((p.outcome === "current" || p.outcome === "skipped") && (r.updateAvailable === undefined || !p.channel) && !p.channelMismatch && !p.targetChannel)
|
|
70532
70534
|
continue;
|
|
70533
70535
|
const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} → v${p.to}` : "";
|
|
70536
|
+
const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
|
|
70534
70537
|
const note = p.message ? ` (${p.message})` : "";
|
|
70535
|
-
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
|
|
70538
|
+
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
|
|
70536
70539
|
}
|
|
70537
70540
|
return lines;
|
|
70538
70541
|
}
|
|
@@ -70547,8 +70550,11 @@ function formatUpgradeHead(r) {
|
|
|
70547
70550
|
if (r.upgraded === true) {
|
|
70548
70551
|
return `akm upgraded: v${r.currentVersion} → v${r.newVersion}`;
|
|
70549
70552
|
}
|
|
70553
|
+
if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
|
|
70554
|
+
return `akm v${r.currentVersion} → v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
|
|
70555
|
+
}
|
|
70550
70556
|
if (r.updateAvailable === true) {
|
|
70551
|
-
return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
|
|
70557
|
+
return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
|
|
70552
70558
|
}
|
|
70553
70559
|
if (r.updateAvailable === false && r.latestVersion) {
|
|
70554
70560
|
return `akm v${r.currentVersion} is already the latest version`;
|
|
@@ -34811,7 +34811,7 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
34811
34811
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
34812
34812
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
34813
34813
|
const projected = [];
|
|
34814
|
-
const fenced =
|
|
34814
|
+
const fenced = new Map;
|
|
34815
34815
|
forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
|
|
34816
34816
|
let trimmed = visible.trim();
|
|
34817
34817
|
if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
|
|
@@ -34831,10 +34831,12 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
34831
34831
|
projected.push(trimmed);
|
|
34832
34832
|
}, (_index, fencedLine) => {
|
|
34833
34833
|
const identifiers = fencedCodeIdentifiers(fencedLine);
|
|
34834
|
-
|
|
34835
|
-
|
|
34834
|
+
for (const identifier of identifiers.split(/\s+/)) {
|
|
34835
|
+
if (identifier)
|
|
34836
|
+
fenced.set(identifier.toLowerCase(), identifier);
|
|
34837
|
+
}
|
|
34836
34838
|
});
|
|
34837
|
-
const text2 = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
|
|
34839
|
+
const text2 = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
|
|
34838
34840
|
if (!text2)
|
|
34839
34841
|
return;
|
|
34840
34842
|
if (truncationInfo)
|
|
@@ -70526,11 +70528,12 @@ function formatUpgradePluginLines(r) {
|
|
|
70526
70528
|
}
|
|
70527
70529
|
const plugins = Array.isArray(r.plugins) ? r.plugins : [];
|
|
70528
70530
|
for (const p of plugins) {
|
|
70529
|
-
if (p.outcome === "current" || p.outcome === "skipped")
|
|
70531
|
+
if ((p.outcome === "current" || p.outcome === "skipped") && (r.updateAvailable === undefined || !p.channel) && !p.channelMismatch && !p.targetChannel)
|
|
70530
70532
|
continue;
|
|
70531
70533
|
const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} \u2192 v${p.to}` : "";
|
|
70534
|
+
const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
|
|
70532
70535
|
const note = p.message ? ` (${p.message})` : "";
|
|
70533
|
-
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
|
|
70536
|
+
lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
|
|
70534
70537
|
}
|
|
70535
70538
|
return lines;
|
|
70536
70539
|
}
|
|
@@ -70545,8 +70548,11 @@ function formatUpgradeHead(r) {
|
|
|
70545
70548
|
if (r.upgraded === true) {
|
|
70546
70549
|
return `akm upgraded: v${r.currentVersion} \u2192 v${r.newVersion}`;
|
|
70547
70550
|
}
|
|
70551
|
+
if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
|
|
70552
|
+
return `akm v${r.currentVersion} \u2192 v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
|
|
70553
|
+
}
|
|
70548
70554
|
if (r.updateAvailable === true) {
|
|
70549
|
-
return `akm v${r.currentVersion} \u2192 v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
|
|
70555
|
+
return `akm v${r.currentVersion} \u2192 v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
|
|
70550
70556
|
}
|
|
70551
70557
|
if (r.updateAvailable === false && r.latestVersion) {
|
|
70552
70558
|
return `akm v${r.currentVersion} is already the latest version`;
|
|
@@ -34,7 +34,7 @@ harness's `--version`, looks up the latest akm release on GitHub for `cli-versio
|
|
|
34
34
|
Claude plugin is installed. With
|
|
35
35
|
`--no-probe` none of these runs: the connection rows carry no `reachable` field and the
|
|
36
36
|
message says reachability was not probed, and `plugin-version` reports `unknown` (its
|
|
37
|
-
`AKM_VERSION_RANGE` check is local and still runs). The `plugin-version` and `cli-version`
|
|
37
|
+
`AKM_MIN_VERSION` (or legacy `AKM_VERSION_RANGE`) check is local and still runs). The `plugin-version` and `cli-version`
|
|
38
38
|
lookups are best-effort and silent on failure; see `src/commands/health/plugin-staleness.ts`
|
|
39
39
|
and `src/commands/health/version-drift.ts`.
|
|
40
40
|
|
|
@@ -62,7 +62,7 @@ and `src/commands/health/version-drift.ts`.
|
|
|
62
62
|
| `type-directory-disagreement` | `warn`: an indexed asset's resolved type differs from the type its directory declares. Each line gives the file, both types, and the classifier signal that won (`winner`). | Review the listed files. Intended overrides (for example a `knowledge/` file containing `$ARGUMENTS`) are marked `known-good override`. |
|
|
63
63
|
| `memory-cleanup-archive` | `pass` with size and file count when the working bundle has `.akm/memory-cleanup/archive` content and no git history (the purge does not run there). `warn` when a git-backed bundle has archived files the purge cannot remove (untracked, modified, or unverifiable in git). | Commit the archived files so the purge can remove them once they age out. |
|
|
64
64
|
| `data-dir-usage` | `warn`: the data directory is over 1 GB and either more than 3 times the size of `state.db`, `index.db`, and `logs.db` (with their WAL and SHM files), or one top-level subdirectory holds more than half of it. The message names that subdirectory and its size. | Inspect the named subdirectory. `backups/tasks/` holds task-file snapshots written by `akm migrate apply`. |
|
|
65
|
-
| `plugin-version` | One row per
|
|
65
|
+
| `plugin-version` | One row per native `claude plugin list --json` AKM installation, with scope, enabled state and install path; cached versions are never used to choose an installation. `AKM_MIN_VERSION` takes precedence over legacy `AKM_VERSION_RANGE`. Disabled and other-project installations are inert. Missing metadata or multiple applicable paths/versions produce `unknown`, since the native list does not identify which conflicting installation a running session loaded. The newest version is read on the channel the marketplace clone follows: on the remote's default branch the newest stable tag, on any other branch (such as `next`) the release tag on that branch's head, and on a clone pinned to a tag that tag. The newest-tag lookup is `--probe`-gated: with `--no-probe` the row is `unknown` ("not probed") and only the local range check still runs. `warn`: the plugin is stale, or its range does not admit the running CLI. | Run the `claude plugin update <ref>` command in the message. |
|
|
66
66
|
| `opencode-plugin-version` | The same check for the OpenCode plugin's own bundled `akm-cli` (read from its `package.json`, never executed): it runs in-process and shares the host's databases, so its lag matters the same way. OpenCode 1 caches each spec in its own folder, so it reads the one folder of the spec the global OpenCode config names under `plugin` (`akm-opencode`, read as `akm-opencode@latest`, or `akm-opencode@next`), and for `akm-opencode@<version>` reports the plugin as pinned with no staleness verdict; with no entry, or no folder for it, it reads `packages/akm-opencode`, and it never scans the other cached specs. It reads local files only and is never `--probe`-gated. `warn`: the bundled version differs from the running CLI. Omitted when the OpenCode plugin is not installed. | Update the OpenCode plugin. |
|
|
67
67
|
| `state-db-readable` | `fail`: `state.db` cannot be read, or is missing in a read-only run (which does not create it). Every other check is skipped, because none of them can read it. | Check the owner and mode of the data directory (or point `AKM_DATA_DIR` / `XDG_DATA_HOME` at one you own); run any akm command that records state, such as `akm health`, to create it. |
|
|
68
68
|
|
|
@@ -439,18 +439,24 @@ orchestration, checksum, and failure paths.
|
|
|
439
439
|
|
|
440
440
|
`tests/integration/upgrade-rehearsal/` runs once per origin in
|
|
441
441
|
`KNOWN_UPGRADE_ORIGINS` (`previous-release.ts`): `previous`, the highest stable
|
|
442
|
-
release below the candidate's `package.json` version
|
|
443
|
-
|
|
442
|
+
release below the candidate's `package.json` version; `0.9.32`, which keeps the
|
|
443
|
+
full engines migration covered after `previous` advances to 0.10; and `0.9.15`,
|
|
444
|
+
which covers scheduler rows installed before host-local activation was recorded.
|
|
445
|
+
Each origin installs that release as a real global npm
|
|
444
446
|
package (a real `npm pack` / `npm install --global` into a throwaway prefix, see
|
|
445
|
-
`scripts/package-install.ts`)
|
|
447
|
+
`scripts/package-install.ts`). The `previous` and `0.9.32` origins build a full
|
|
448
|
+
home — filesystem,
|
|
446
449
|
git (with an in-bundle symlink at its root), website, and npm bundles, scheduled
|
|
447
|
-
tasks, a synced native (fake) crontab, and
|
|
448
|
-
itself writes
|
|
449
|
-
|
|
450
|
+
tasks, a synced native (fake) crontab, and model configuration the release
|
|
451
|
+
itself writes: native connections/harnesses on 0.10+, or the full 0.9 `engines`
|
|
452
|
+
form (an llm engine with an `apiKeyFile`, agent engines, a `models.json`, and a
|
|
453
|
+
command and task that name an engine). The `0.9.15` origin uses a smaller home
|
|
454
|
+
with one directly installed scheduled task. Each then installs
|
|
450
455
|
the CANDIDATE build OVER it in the SAME prefix: an in-place swap, the same thing
|
|
451
456
|
a real `npm i -g akm-cli@…` or `bun add -g` upgrade does. It then runs the
|
|
452
457
|
candidate against that home (`migrate status` / `apply`, which converts the
|
|
453
|
-
`engines` form, files its key and rewrites the `engine:` keys,
|
|
458
|
+
`engines` form, files its key and rewrites the `engine:` keys, or preserves
|
|
459
|
+
native connections/harnesses, `bundle list`,
|
|
454
460
|
`search` / `show`, `task sync` dry-run and real — plain, no `--rebind`, as an
|
|
455
461
|
upgrading user runs it — executing the generated cron command and confirming it
|
|
456
462
|
ran the candidate, `task run`, `health`, `improve --dry-run`), and finally runs a
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# akm v0.10.261020 migration notes
|
|
2
|
+
|
|
3
|
+
This beta fixes Claude plugin health reporting, adds coordinated channel
|
|
4
|
+
switching, and reduces repeated fenced identifiers in search content.
|
|
5
|
+
|
|
6
|
+
The next index pass refreshes existing content projections and changed embedding
|
|
7
|
+
inputs automatically. No manual database or configuration migration is required
|
|
8
|
+
when upgrading from 0.10.261019.
|
|
9
|
+
|
|
10
|
+
After installing this beta, `akm upgrade --channel next` switches the CLI and
|
|
11
|
+
installed Claude, Codex and OpenCode plugins together. The existing `--next`
|
|
12
|
+
flag keeps its prior behavior. To return to stable, use
|
|
13
|
+
`akm upgrade --channel latest`; if the target version is older, add
|
|
14
|
+
`--allow-downgrade`. Changed settings receive backups, and the command reports
|
|
15
|
+
any harness that could not finish switching. Restart the harness after updates.
|
|
16
|
+
|
|
17
|
+
Claude health now uses native installation metadata. It reports conflicting or
|
|
18
|
+
incomplete installation selections as unknown instead of choosing a cached
|
|
19
|
+
version. This can change a previous warning without changing the installation.
|
|
20
|
+
|
|
21
|
+
If upgrading from 0.9, first follow the
|
|
22
|
+
[0.9 to 0.10 migration guide](../v0.9-to-v0.10.md).
|
|
@@ -7,6 +7,7 @@ live one level up in `docs/migration/`.
|
|
|
7
7
|
|
|
8
8
|
## Available notes
|
|
9
9
|
|
|
10
|
+
- [0.10.261020](0.10.261020.md) — Coordinated beta/stable channel switching, native Claude health, and automatic search-projection refresh.
|
|
10
11
|
- [0.10.261019](0.10.261019.md) — The 0.10 series: 0.9.15 version floor, merged CLI spellings, `default`/`consolidate` strategies only, OpenCode 2, feedback-scaled ranking, and `0.10.YYMMNN` versions.
|
|
11
12
|
- [0.9.19](0.9.19.md) — Bundle-scoped improve planning, proposal reopen, and consolidate/distill guardrails.
|
|
12
13
|
- [0.9.17](0.9.17.md) — Retire proposals, declared links replacing the LLM entity graph, and scoped improve planning.
|
package/docs/reference/cli.md
CHANGED
|
@@ -1537,7 +1537,9 @@ computed, with a 256 MiB binary limit. Release/checksum metadata is capped at
|
|
|
1537
1537
|
akm upgrade # Install a newer release if there is one, run every pending migration, then update the harness plugins
|
|
1538
1538
|
akm upgrade --check # Report pending updates, CLI and plugins, without changing anything (no migration step)
|
|
1539
1539
|
akm upgrade --force # Force the install even if already on latest
|
|
1540
|
-
akm upgrade --next #
|
|
1540
|
+
akm upgrade --next # Include prereleases when selecting the newest CLI release
|
|
1541
|
+
akm upgrade --channel next # Switch CLI and installed harness plugins to next
|
|
1542
|
+
akm upgrade --channel latest # Return CLI and installed harness plugins to stable
|
|
1541
1543
|
```
|
|
1542
1544
|
|
|
1543
1545
|
| Flag | Description |
|
|
@@ -1545,7 +1547,9 @@ akm upgrade --next # Install the newest prerelease (@next) instead of the
|
|
|
1545
1547
|
| `--check` | Report pending updates (CLI and per-harness plugins) without changing anything |
|
|
1546
1548
|
| `--force` | Force upgrade even if on latest version |
|
|
1547
1549
|
| `--skip-post-upgrade` | Skip the post-upgrade index rebuild |
|
|
1548
|
-
| `--next` |
|
|
1550
|
+
| `--channel latest\|next` | Switch the CLI and installed Claude, Codex and OpenCode plugins together; works with `--check` |
|
|
1551
|
+
| `--allow-downgrade` | Permit an older target version during an explicit `--channel` switch |
|
|
1552
|
+
| `--next` | Include prereleases when selecting the newest CLI release; retain configured harness channels (see below). Works with `--check`, `--force` and `-q` |
|
|
1549
1553
|
|
|
1550
1554
|
Offline, or to migrate without a release check, run `akm migrate apply`
|
|
1551
1555
|
directly: it is the same step.
|
|
@@ -1607,7 +1611,7 @@ target is the akm-cli that `akm-opencode@latest` depends on
|
|
|
1607
1611
|
The result then carries `lockstep: { plugin, pinnedVersion, newestVersion, heldBack }`,
|
|
1608
1612
|
`latestVersion` is the pinned version, the install names that exact version
|
|
1609
1613
|
rather than `@latest`, and the text output says the CLI is held back. The CLI
|
|
1610
|
-
is never moved backwards to meet the pin
|
|
1614
|
+
is never moved backwards to meet the pin unless an explicit channel switch also names `--allow-downgrade`. With both OpenCode plugins present
|
|
1611
1615
|
(`akm-opencode` and `akm-opencode-v2`), the CLI is held to the older of their
|
|
1612
1616
|
two pins, and `lockstep.plugin` names the one that sets it. Claude Code and Codex have no
|
|
1613
1617
|
in-process copy and are not part of this rule.
|
|
@@ -1623,7 +1627,7 @@ retries.
|
|
|
1623
1627
|
#### Prereleases (`--next`)
|
|
1624
1628
|
|
|
1625
1629
|
`akm upgrade --next` means "newest available, prereleases included". The result
|
|
1626
|
-
carries `channel: "next"` (`"latest"` otherwise)
|
|
1630
|
+
carries `channel: "next"` (`"latest"` otherwise), plus the CLI's inferred `currentChannel` and each installed plugin's configured `channel` and `channelMismatch`.
|
|
1627
1631
|
|
|
1628
1632
|
- **CLI.** The target is the `next` dist-tag of `akm-cli` (read from the npm
|
|
1629
1633
|
registry, so it works for binary installs too) when that is newer than the
|
|
@@ -1656,14 +1660,38 @@ carries `channel: "next"` (`"latest"` otherwise); no other field changes.
|
|
|
1656
1660
|
- **Claude Code and Codex.** Their plugin comes from the `akm-plugins` git
|
|
1657
1661
|
marketplace, and the channel is the ref the marketplace follows: the default
|
|
1658
1662
|
branch is stable, the `next` branch carries prereleases. `akm upgrade` updates
|
|
1659
|
-
whatever ref the marketplace follows
|
|
1660
|
-
`--next
|
|
1661
|
-
|
|
1662
|
-
`settings.json`), or run `codex plugin marketplace add itlackey/akm-plugins --ref next`
|
|
1663
|
-
in Codex. Under `--next` their entries carry a note naming the ref followed.
|
|
1663
|
+
whatever ref the marketplace follows. `--next` alone leaves that ref unchanged;
|
|
1664
|
+
`--channel next` changes it. Under `--next` their entries carry a note naming
|
|
1665
|
+
the ref followed.
|
|
1664
1666
|
The plugins need akm 0.10.261001 or newer; any newer akm passes.
|
|
1665
1667
|
- `--check --next` reports all of this and changes nothing.
|
|
1666
1668
|
|
|
1669
|
+
#### Switching channels together (`--channel`)
|
|
1670
|
+
|
|
1671
|
+
`akm upgrade --channel next` selects the actual npm `next` CLI tag and changes
|
|
1672
|
+
installed harness plugins to their `next` branch or package tag.
|
|
1673
|
+
`--channel latest` selects stable and removes those prerelease refs. An explicit
|
|
1674
|
+
switch may replace a pinned plugin spec. The command checks target CLI and plugin
|
|
1675
|
+
versions first; if any would go backwards, repeat with `--allow-downgrade`.
|
|
1676
|
+
A failed CLI install or migration stops the plugin switch.
|
|
1677
|
+
|
|
1678
|
+
Claude and Codex retain their marketplace registrations, plugin enablement,
|
|
1679
|
+
`pluginConfigs`, and unrelated settings. akm edits only the marketplace ref,
|
|
1680
|
+
then uses the native updater. Claude's installed user, project and local scopes
|
|
1681
|
+
are updated explicitly. OpenCode changes only the installed plugin's spec,
|
|
1682
|
+
retaining tuple options and JSONC comments, then refreshes the desired cache.
|
|
1683
|
+
Every changed config file has a sibling `.akm-channel-*.bak` backup, whose path
|
|
1684
|
+
appears in that harness's `backups` result. Restart the harness to load updates.
|
|
1685
|
+
|
|
1686
|
+
`--check --channel next` shows `channel`, `targetChannel` and mismatches without
|
|
1687
|
+
writing settings or fetching Git marketplaces. The CLI's `currentChannel` is
|
|
1688
|
+
inferred from its version: prerelease means `next`, otherwise `latest`.
|
|
1689
|
+
A configured channel is distinct from a successful refresh: native update
|
|
1690
|
+
failures retain the configured target and backup paths but report `failed`.
|
|
1691
|
+
An installed plugin that cannot switch, including OpenCode awaiting shutdown,
|
|
1692
|
+
makes an explicit switch exit `1`; retry after resolving its reported cause.
|
|
1693
|
+
The switch is coordinated, not a transaction across independent harnesses.
|
|
1694
|
+
|
|
1667
1695
|
#### Containers
|
|
1668
1696
|
|
|
1669
1697
|
With the plugin step, a container entrypoint needs only:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.261020-beta",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
|
|
6
6
|
"keywords": [
|
|
@@ -119,9 +119,11 @@
|
|
|
119
119
|
"citty": "^0.2.2",
|
|
120
120
|
"dotenv": "^17.4.2",
|
|
121
121
|
"fast-xml-parser": "^5.10.1",
|
|
122
|
+
"jsonc-parser": "^3.3.1",
|
|
122
123
|
"marked": "^18.1.1",
|
|
123
124
|
"node-html-parser": "^9.0.1",
|
|
124
125
|
"semver": "^7.6.0",
|
|
126
|
+
"smol-toml": "^1.9.1",
|
|
125
127
|
"turndown": "^7.2.4",
|
|
126
128
|
"yaml": "^2.8.4",
|
|
127
129
|
"zod": "^4.6.6"
|