akm-cli 0.9.31 → 0.10.261001-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 +409 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +92 -106
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +2 -6
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +41 -11
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15745 -16711
- package/dist/scripts/akm-migrate.js +16318 -17280
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +94 -13
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +1 -1
- package/docs/agents/README.md +3 -3
- package/docs/agents/agent-install.md +1 -1
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/adapters.md +17 -31
- package/docs/architecture/architecture.md +4 -5
- package/docs/architecture/improvement.md +115 -76
- package/docs/architecture/internals/improve-workflow.md +22 -16
- package/docs/architecture/internals/indexing.md +1 -1
- package/docs/architecture/internals/search.md +1 -2
- package/docs/architecture/internals/storage-locations.md +6 -6
- package/docs/architecture/persisted-data-compat.md +13 -4
- package/docs/architecture/specs/0.9.0-decisions.md +6 -2
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
- package/docs/architecture/specs/workflow-format-unification.md +1 -6
- package/docs/architecture/testing/manual-testing-checklist.md +21 -30
- package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
- package/docs/architecture/testing/testing-workflow.md +1 -1
- package/docs/architecture/workflow-engine.md +5 -56
- package/docs/guides/author-workflows.md +39 -69
- package/docs/guides/bundles.md +3 -1
- package/docs/guides/capture-knowledge.md +1 -1
- package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
- package/docs/guides/discover-and-load.md +4 -4
- package/docs/guides/getting-started.md +1 -1
- package/docs/guides/improve-the-library.md +10 -9
- package/docs/guides/recipes/headless-install.md +2 -2
- package/docs/guides/run-workflows.md +1 -1
- package/docs/guides/scheduling.md +9 -1
- package/docs/guides/use-with-any-agent.md +49 -4
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/curate-workmap.md +1 -2
- package/docs/maintainers/release-checklist.md +33 -1
- package/docs/migration/README.md +2 -0
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/README.md +1 -0
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/posts/akm-command-tour.md +3 -3
- package/docs/product-surface.md +1 -1
- package/docs/reference/README.md +1 -0
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +3 -5
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +160 -188
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +2 -2
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +1 -1
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +12 -2
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -13,13 +13,14 @@ import * as childProcess from "node:child_process";
|
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import os from "node:os";
|
|
15
15
|
import path from "node:path";
|
|
16
|
-
import { IS_WINDOWS,
|
|
16
|
+
import { IS_WINDOWS, parseJsonc } from "../../core/common.js";
|
|
17
17
|
import { moveToTrash } from "../../core/trash.js";
|
|
18
|
+
import { OPENCODE_SDK_SERVER_BIN } from "../../integrations/agent/profiles.js";
|
|
19
|
+
import { OPENCODE_V1, OPENCODE_V2, readPackageVersion, } from "../../integrations/harnesses/opencode/plugin-layout.js";
|
|
20
|
+
import { detectOpencodeMajor, resolveOpencodeBin } from "../../integrations/harnesses/opencode/version.js";
|
|
18
21
|
import { semverOrder } from "../../runtime.js";
|
|
19
22
|
const MARKETPLACE = "akm-plugins";
|
|
20
23
|
const PLUGIN_ID = `akm@${MARKETPLACE}`;
|
|
21
|
-
const OPENCODE_PACKAGE = "akm-opencode";
|
|
22
|
-
const OPENCODE_NEXT_SPEC = `${OPENCODE_PACKAGE}@next`;
|
|
23
24
|
const READ_TIMEOUT_MS = 30_000;
|
|
24
25
|
const REFRESH_TIMEOUT_MS = 120_000;
|
|
25
26
|
const PREFETCH_TIMEOUT_MS = 180_000;
|
|
@@ -137,20 +138,33 @@ function upgradeCodex(dryRun) {
|
|
|
137
138
|
const after = codexPluginVersion();
|
|
138
139
|
return refreshed("codex", before.version, "version" in after ? after.version : undefined);
|
|
139
140
|
}
|
|
141
|
+
// ── OpenCode ────────────────────────────────────────────────────────────────
|
|
142
|
+
const nextSpec = (flavor) => `${flavor.pkg}@next`;
|
|
140
143
|
function homeDir() {
|
|
141
144
|
return process.env.HOME?.trim() || process.env.USERPROFILE?.trim() || os.homedir();
|
|
142
145
|
}
|
|
146
|
+
function openCodeCacheHome() {
|
|
147
|
+
const cacheHome = process.env.XDG_CACHE_HOME?.trim() || path.join(homeDir(), ".cache");
|
|
148
|
+
return path.join(cacheHome, "opencode");
|
|
149
|
+
}
|
|
150
|
+
/** The spec in a config's plugin entry (a spec string or a `[spec, options]` pair). */
|
|
151
|
+
function entrySpec(entry) {
|
|
152
|
+
const spec = Array.isArray(entry) ? entry[0] : entry;
|
|
153
|
+
return typeof spec === "string" ? spec : undefined;
|
|
154
|
+
}
|
|
155
|
+
const namesPackage = (spec, pkg) => spec === pkg || spec.startsWith(`${pkg}@`);
|
|
143
156
|
/**
|
|
144
|
-
* The
|
|
145
|
-
* `@latest`, `@next`, an exact version, ...),
|
|
146
|
-
*
|
|
147
|
-
* loads. The config is only read, never
|
|
148
|
-
* looked at (akm does not know which project
|
|
157
|
+
* The plugin spec the user's global OpenCode config names for this flavor's
|
|
158
|
+
* package (bare, `@latest`, `@next`, an exact version, ...), with the config key
|
|
159
|
+
* it sits under, or undefined when none does. OpenCode caches each spec in its
|
|
160
|
+
* own folder, so this says which cache it loads. The config is only read, never
|
|
161
|
+
* written; project configs are not looked at (akm does not know which project
|
|
162
|
+
* OpenCode runs in).
|
|
149
163
|
*/
|
|
150
|
-
export function openCodeConfigSpec() {
|
|
164
|
+
export function openCodeConfigSpec(flavor) {
|
|
151
165
|
const configHome = process.env.XDG_CONFIG_HOME?.trim() || path.join(homeDir(), ".config");
|
|
152
166
|
const files = [
|
|
153
|
-
process.env.OPENCODE_CONFIG?.trim(),
|
|
167
|
+
flavor.globalConfigOnly ? undefined : process.env.OPENCODE_CONFIG?.trim(),
|
|
154
168
|
path.join(configHome, "opencode", "opencode.json"),
|
|
155
169
|
path.join(configHome, "opencode", "opencode.jsonc"),
|
|
156
170
|
];
|
|
@@ -158,14 +172,15 @@ export function openCodeConfigSpec() {
|
|
|
158
172
|
if (!file)
|
|
159
173
|
continue;
|
|
160
174
|
try {
|
|
161
|
-
const config =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
const config = parseJsonc(fs.readFileSync(file, "utf8"));
|
|
176
|
+
for (const key of flavor.configKeys) {
|
|
177
|
+
const entries = config[key];
|
|
178
|
+
if (!Array.isArray(entries))
|
|
179
|
+
continue;
|
|
180
|
+
for (const entry of entries) {
|
|
181
|
+
const spec = entrySpec(entry);
|
|
182
|
+
if (spec !== undefined && namesPackage(spec, flavor.pkg))
|
|
183
|
+
return { spec, key };
|
|
169
184
|
}
|
|
170
185
|
}
|
|
171
186
|
}
|
|
@@ -175,30 +190,32 @@ export function openCodeConfigSpec() {
|
|
|
175
190
|
}
|
|
176
191
|
return undefined;
|
|
177
192
|
}
|
|
193
|
+
/** Whether OpenCode 2 has ever cached `akm-opencode-v2` on this host. */
|
|
194
|
+
function openCodeV2Cached() {
|
|
195
|
+
try {
|
|
196
|
+
return fs
|
|
197
|
+
.readdirSync(path.join(openCodeCacheHome(), OPENCODE_V2.cacheFolder("")))
|
|
198
|
+
.some((name) => name.startsWith(`${OPENCODE_V2.pkg}@`));
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
178
204
|
/**
|
|
179
|
-
* The cached
|
|
180
|
-
*
|
|
181
|
-
*
|
|
205
|
+
* The cached plugin OpenCode installed on first use, or undefined when there is
|
|
206
|
+
* none. OpenCode names the folder after the spec it resolved, so a bare package
|
|
207
|
+
* lands in `@latest` and `<pkg>@next` in `@next`.
|
|
182
208
|
*/
|
|
183
|
-
export function detectOpenCodeCache(tag
|
|
184
|
-
const
|
|
185
|
-
const dir = path.join(cacheHome, "opencode", "packages", `${OPENCODE_PACKAGE}@${tag}`);
|
|
209
|
+
export function detectOpenCodeCache(tag, flavor) {
|
|
210
|
+
const dir = path.join(openCodeCacheHome(), flavor.cacheFolder(`${flavor.pkg}@${tag}`));
|
|
186
211
|
if (!fs.existsSync(dir))
|
|
187
212
|
return undefined;
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
191
|
-
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
return undefined;
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
return { dir, version: readVersion(path.join(dir, "node_modules", OPENCODE_PACKAGE, "package.json")) };
|
|
213
|
+
const nodeModules = flavor.nodeModulesDir(dir);
|
|
214
|
+
return { dir, version: nodeModules && readPackageVersion(path.join(nodeModules, flavor.pkg, "package.json")) };
|
|
198
215
|
}
|
|
199
|
-
/** What npm's
|
|
200
|
-
export function lookupOpenCodeLatest(tag
|
|
201
|
-
const spec = `${
|
|
216
|
+
/** What npm's `<pkg>@<tag>` is, and which akm-cli it pins. */
|
|
217
|
+
export function lookupOpenCodeLatest(tag, flavor) {
|
|
218
|
+
const spec = `${flavor.pkg}@${tag}`;
|
|
202
219
|
const view = runCommand(IS_WINDOWS ? "npm.cmd" : "npm", ["view", spec, "version", "dependencies.akm-cli", "--json"], READ_TIMEOUT_MS);
|
|
203
220
|
if (!view.ok)
|
|
204
221
|
return { error: view.error };
|
|
@@ -209,7 +226,7 @@ export function lookupOpenCodeLatest(tag = "latest") {
|
|
|
209
226
|
return { version: parsed.version, akmCli: typeof akmCli === "string" ? akmCli : undefined };
|
|
210
227
|
}
|
|
211
228
|
/**
|
|
212
|
-
*
|
|
229
|
+
* `<pkg>@next`, which must exist and pin an akm-cli no older than the one
|
|
213
230
|
* `@latest` pins: a prerelease channel that trails the stable one is not a target.
|
|
214
231
|
*
|
|
215
232
|
* The two builds are compared by their akm-cli pins, never by their own
|
|
@@ -220,23 +237,23 @@ export function lookupOpenCodeLatest(tag = "latest") {
|
|
|
220
237
|
* (#1089). For the same reason plugin versions are only ever tested for
|
|
221
238
|
* equality (is the cache already this build?), never ordered.
|
|
222
239
|
*/
|
|
223
|
-
export function lookupOpenCodeNext() {
|
|
224
|
-
const next = lookupOpenCodeLatest("next");
|
|
240
|
+
export function lookupOpenCodeNext(flavor) {
|
|
241
|
+
const next = lookupOpenCodeLatest("next", flavor);
|
|
225
242
|
if ("error" in next)
|
|
226
243
|
return next;
|
|
227
|
-
const latest = lookupOpenCodeLatest("latest");
|
|
244
|
+
const latest = lookupOpenCodeLatest("latest", flavor);
|
|
228
245
|
if ("error" in latest)
|
|
229
|
-
return { error: `could not compare with ${
|
|
246
|
+
return { error: `could not compare with ${flavor.pkg}@latest: ${latest.error}` };
|
|
230
247
|
// No pin on @next: returned as is, and the lockstep holds the CLI and says why.
|
|
231
248
|
if (!next.akmCli)
|
|
232
249
|
return next;
|
|
233
250
|
if (!latest.akmCli) {
|
|
234
|
-
return { error: `could not compare with ${
|
|
251
|
+
return { error: `could not compare with ${flavor.pkg}@latest: it declares no akm-cli dependency` };
|
|
235
252
|
}
|
|
236
253
|
if (semverOrder(next.akmCli, latest.akmCli) < 0) {
|
|
237
254
|
return {
|
|
238
|
-
error: `${
|
|
239
|
-
`${latest.akmCli} that ${
|
|
255
|
+
error: `${nextSpec(flavor)} (${next.version}) pins akm-cli ${next.akmCli}, older than the ` +
|
|
256
|
+
`${latest.akmCli} that ${flavor.pkg}@latest (${latest.version}) pins`,
|
|
240
257
|
};
|
|
241
258
|
}
|
|
242
259
|
return next;
|
|
@@ -296,28 +313,31 @@ function openCodeRunning() {
|
|
|
296
313
|
return undefined;
|
|
297
314
|
}
|
|
298
315
|
}
|
|
299
|
-
const
|
|
300
|
-
`set "
|
|
316
|
+
const notFollowingNext = (flavor) => `--next: OpenCode resolves a bare "${flavor.pkg}" to @latest, so it is not updated to a prerelease; ` +
|
|
317
|
+
`set "${flavor.configKeys[0]}": ["${nextSpec(flavor)}"] in your OpenCode config to follow prereleases`;
|
|
301
318
|
/** Why a run leaves alone an OpenCode whose config names a spec this run does not refresh (#1115, #1117). */
|
|
302
|
-
function otherSpecNote(spec) {
|
|
319
|
+
function otherSpecNote(flavor, spec) {
|
|
303
320
|
const loads = `OpenCode loads "${spec}" (your OpenCode config), so this upgrade leaves it alone`;
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
321
|
+
const key = flavor.configKeys[0];
|
|
322
|
+
return spec === nextSpec(flavor)
|
|
323
|
+
? `${loads}; run \`akm upgrade --next\` to update it, or set "${key}": ["${flavor.pkg}"] to follow stable releases`
|
|
324
|
+
: `${loads}; set "${key}": ["${flavor.pkg}"] to have \`akm upgrade\` keep it current`;
|
|
307
325
|
}
|
|
308
|
-
function upgradeOpenCode(dryRun,
|
|
326
|
+
function upgradeOpenCode(dryRun, target) {
|
|
327
|
+
const { flavor, cache, latest, tag, skip } = target;
|
|
328
|
+
const harness = flavor.harness;
|
|
309
329
|
// Refreshing a cache OpenCode does not load would trash one it never re-creates (#1115, #1117).
|
|
310
|
-
if (
|
|
311
|
-
return skipped(
|
|
330
|
+
if (skip)
|
|
331
|
+
return skipped(harness, skip);
|
|
312
332
|
if (!cache || !latest)
|
|
313
|
-
return skipped(
|
|
333
|
+
return skipped(harness, `no cached ${flavor.pkg}@${tag} plugin`);
|
|
314
334
|
if ("error" in latest)
|
|
315
|
-
return failed(
|
|
316
|
-
if (notFollowingNext)
|
|
317
|
-
return skipped(
|
|
335
|
+
return failed(harness, latest.error);
|
|
336
|
+
if (target.notFollowingNext)
|
|
337
|
+
return skipped(harness, notFollowingNext(flavor));
|
|
318
338
|
if (cache.version === latest.version)
|
|
319
|
-
return { harness
|
|
320
|
-
const base = { harness
|
|
339
|
+
return { harness, outcome: "current", from: cache.version, to: latest.version };
|
|
340
|
+
const base = { harness, from: cache.version, to: latest.version };
|
|
321
341
|
const running = openCodeRunning();
|
|
322
342
|
if (running !== false) {
|
|
323
343
|
return {
|
|
@@ -330,30 +350,39 @@ function upgradeOpenCode(dryRun, cache, latest, tag, notFollowingNext, otherSpec
|
|
|
330
350
|
}
|
|
331
351
|
if (dryRun)
|
|
332
352
|
return { ...base, outcome: "pending" };
|
|
333
|
-
// OpenCode must be runnable before the cache goes: it does the prefetch
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
353
|
+
// OpenCode must be runnable before the cache goes: it does the prefetch, and only the major
|
|
354
|
+
// that owns this plugin's cache can re-create it. akm never installs or replaces the binary.
|
|
355
|
+
// OpenCode 2 may sit beside an OpenCode 1 `opencode` as `opencode2`; OpenCode 1 is only ever `opencode`.
|
|
356
|
+
const bin = flavor.major === 2 ? resolveOpencodeBin() : OPENCODE_SDK_SERVER_BIN;
|
|
357
|
+
const detected = detectOpencodeMajor(bin);
|
|
358
|
+
if (!detected.runnable)
|
|
359
|
+
return skipped(harness, `${bin} is not on PATH or \`${bin} --version\` failed`);
|
|
360
|
+
const major = detected.reportedMajor;
|
|
361
|
+
// OpenCode 1 keeps its long-standing behavior when the version cannot be read; OpenCode 2's
|
|
362
|
+
// refresh needs a command only OpenCode 2 has, so it must be sure.
|
|
363
|
+
if (major === undefined ? flavor.major === 2 : major !== flavor.major) {
|
|
364
|
+
return skipped(harness, `\`${bin}\` on PATH is ${major === undefined ? "of an unknown version" : `OpenCode ${major}`}, ` +
|
|
365
|
+
`not OpenCode ${flavor.major}, so it cannot re-create the ${flavor.pkg} cache; the cache is left alone`);
|
|
366
|
+
}
|
|
337
367
|
try {
|
|
338
368
|
moveToTrash(cache.dir);
|
|
339
369
|
}
|
|
340
370
|
catch (error) {
|
|
341
|
-
return failed(
|
|
371
|
+
return failed(harness, `could not move ${cache.dir} to the trash: ${error instanceof Error ? error.message : String(error)}`);
|
|
342
372
|
}
|
|
343
|
-
//
|
|
344
|
-
// from a temp dir, so no project's opencode.json is read.
|
|
373
|
+
// From a temp dir, so no project's opencode.json is read.
|
|
345
374
|
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "akm-opencode-prefetch-"));
|
|
346
375
|
try {
|
|
347
|
-
const prefetch = runCommand(
|
|
376
|
+
const prefetch = runCommand(bin, flavor.prefetch(target.spec), PREFETCH_TIMEOUT_MS, { cwd: workDir });
|
|
348
377
|
if (!prefetch.ok)
|
|
349
|
-
return failed(
|
|
378
|
+
return failed(harness, `${prefetch.error} (the old cache is in the trash)`);
|
|
350
379
|
}
|
|
351
380
|
finally {
|
|
352
381
|
fs.rmSync(workDir, { recursive: true, force: true });
|
|
353
382
|
}
|
|
354
|
-
const after = detectOpenCodeCache(tag);
|
|
383
|
+
const after = detectOpenCodeCache(tag, flavor);
|
|
355
384
|
if (!after)
|
|
356
|
-
return failed(
|
|
385
|
+
return failed(harness, "opencode did not re-create the plugin cache (the old cache is in the trash)");
|
|
357
386
|
return { ...base, outcome: "updated", to: after.version ?? latest.version };
|
|
358
387
|
}
|
|
359
388
|
// ── Orchestration ───────────────────────────────────────────────────────────
|
|
@@ -365,18 +394,17 @@ function withNextNote(entry) {
|
|
|
365
394
|
return { ...entry, message: entry.message ? `${entry.message}; ${NO_PRERELEASE_CHANNEL}` : NO_PRERELEASE_CHANNEL };
|
|
366
395
|
}
|
|
367
396
|
export function upgradePlugins(opts) {
|
|
368
|
-
const { cache, latest, tag, notFollowingNext, otherSpec } = opts.openCode;
|
|
369
397
|
const claude = upgradeClaudeCode(opts.dryRun);
|
|
370
398
|
const codex = upgradeCodex(opts.dryRun);
|
|
371
399
|
return [
|
|
372
400
|
opts.next ? withNextNote(claude) : claude,
|
|
373
401
|
opts.next ? withNextNote(codex) : codex,
|
|
374
|
-
upgradeOpenCode(opts.dryRun,
|
|
402
|
+
...opts.openCode.map((target) => upgradeOpenCode(opts.dryRun, target)),
|
|
375
403
|
];
|
|
376
404
|
}
|
|
377
405
|
/**
|
|
378
|
-
* When
|
|
379
|
-
*
|
|
406
|
+
* When an OpenCode plugin is present the CLI target is the akm-cli that
|
|
407
|
+
* `<pkg>@latest` pins, not the newest release: the plugin runs that
|
|
380
408
|
* exact akm in-process, against databases a newer CLI may already have
|
|
381
409
|
* migrated. The CLI never moves backwards to meet the pin.
|
|
382
410
|
*
|
|
@@ -386,7 +414,7 @@ export function upgradePlugins(opts) {
|
|
|
386
414
|
* `lockstep.reason` says why. Moving the CLI ahead of a pin nobody could read is
|
|
387
415
|
* what lockstep exists to prevent; the OpenCode entry reports the failure.
|
|
388
416
|
*/
|
|
389
|
-
export function applyLockstep(check, latest, tag
|
|
417
|
+
export function applyLockstep(check, latest, tag, pkg) {
|
|
390
418
|
if (!latest)
|
|
391
419
|
return check;
|
|
392
420
|
// Held back only when there is a release this upgrade would otherwise install.
|
|
@@ -394,14 +422,14 @@ export function applyLockstep(check, latest, tag = "latest") {
|
|
|
394
422
|
const pinned = "error" in latest ? undefined : latest.akmCli;
|
|
395
423
|
if (!pinned) {
|
|
396
424
|
const reason = "error" in latest
|
|
397
|
-
? `could not read the akm-cli pin of ${
|
|
398
|
-
: `${
|
|
425
|
+
? `could not read the akm-cli pin of ${pkg}@${tag}: ${latest.error}`
|
|
426
|
+
: `${pkg}@${tag} declares no akm-cli dependency`;
|
|
399
427
|
return {
|
|
400
428
|
...check,
|
|
401
429
|
latestVersion: check.currentVersion,
|
|
402
430
|
updateAvailable: false,
|
|
403
431
|
lockstep: {
|
|
404
|
-
plugin:
|
|
432
|
+
plugin: pkg,
|
|
405
433
|
pinnedVersion: null,
|
|
406
434
|
newestVersion: check.latestVersion,
|
|
407
435
|
heldBack: wouldInstall,
|
|
@@ -411,7 +439,7 @@ export function applyLockstep(check, latest, tag = "latest") {
|
|
|
411
439
|
}
|
|
412
440
|
const heldBack = semverOrder(pinned, check.latestVersion) < 0 && wouldInstall;
|
|
413
441
|
const lockstep = {
|
|
414
|
-
plugin:
|
|
442
|
+
plugin: pkg,
|
|
415
443
|
pinnedVersion: pinned,
|
|
416
444
|
newestVersion: check.latestVersion,
|
|
417
445
|
heldBack,
|
|
@@ -426,40 +454,75 @@ export function applyLockstep(check, latest, tag = "latest") {
|
|
|
426
454
|
};
|
|
427
455
|
}
|
|
428
456
|
/**
|
|
429
|
-
*
|
|
430
|
-
*
|
|
457
|
+
* The plugin the CLI is held to when several are present: one whose pin could not be read (the
|
|
458
|
+
* CLI stays put), else the one pinning the oldest akm-cli, since every plugin runs the CLI that is installed.
|
|
459
|
+
*/
|
|
460
|
+
function lockstepSource(targets) {
|
|
461
|
+
const readable = (t) => t.latest !== undefined && !("error" in t.latest) && typeof t.latest.akmCli === "string";
|
|
462
|
+
const pinned = targets.filter((t) => t.latest);
|
|
463
|
+
return (pinned.find((t) => !readable(t)) ??
|
|
464
|
+
pinned.filter(readable).sort((a, b) => semverOrder(a.latest.akmCli, b.latest.akmCli))[0]);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Which build of one OpenCode plugin the CLI is held to, and which cache refreshes.
|
|
468
|
+
* Under `--next` that is `<pkg>@next`, but only when the user's OpenCode
|
|
431
469
|
* config names that tag: a bare one keeps resolving `@latest`, so the lockstep
|
|
432
470
|
* stays against the `@latest` pin and the entry is reported as skipped. A config
|
|
433
471
|
* naming any other spec (an exact version, or `@next` on a plain run) is left
|
|
434
472
|
* alone, with no lockstep.
|
|
435
473
|
*/
|
|
436
|
-
function resolveOpenCodeTarget(next) {
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
const
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
474
|
+
function resolveOpenCodeTarget(next, flavor, configured) {
|
|
475
|
+
// OpenCode 1 with no config entry behaves like a bare one: it would resolve @latest. OpenCode 2's
|
|
476
|
+
// re-fetch writes the config, so its plugin is only refreshed where the config already names it.
|
|
477
|
+
const spec = configured?.spec ?? flavor.pkg;
|
|
478
|
+
const leftAlone = (skip) => ({
|
|
479
|
+
flavor,
|
|
480
|
+
cache: undefined,
|
|
481
|
+
latest: undefined,
|
|
482
|
+
tag: next ? "next" : "latest",
|
|
483
|
+
spec,
|
|
484
|
+
notFollowingNext: false,
|
|
485
|
+
skip,
|
|
486
|
+
});
|
|
487
|
+
if (flavor.globalConfigOnly) {
|
|
488
|
+
if (!configured) {
|
|
489
|
+
return leftAlone(`OpenCode's global config does not name ${flavor.pkg}; this upgrade only refreshes a plugin it names`);
|
|
490
|
+
}
|
|
491
|
+
if (configured.key !== flavor.configKeys[0]) {
|
|
492
|
+
return leftAlone(`OpenCode loads "${spec}" from the "${configured.key}" key of your config; move it to "${flavor.configKeys[0]}" ` +
|
|
493
|
+
"to have `akm upgrade` keep it current");
|
|
494
|
+
}
|
|
450
495
|
}
|
|
496
|
+
const followsLatest = spec === flavor.pkg || spec === `${flavor.pkg}@latest`;
|
|
497
|
+
const followNext = next && spec === nextSpec(flavor);
|
|
498
|
+
// Any other spec loads a cache this run does not refresh, and pins no akm-cli it should be held to.
|
|
499
|
+
if (!followsLatest && !followNext)
|
|
500
|
+
return leftAlone(otherSpecNote(flavor, spec));
|
|
451
501
|
const tag = followNext ? "next" : "latest";
|
|
452
|
-
const cache = detectOpenCodeCache(tag);
|
|
453
|
-
const latest = cache ? (followNext ? lookupOpenCodeNext() : lookupOpenCodeLatest()) : undefined;
|
|
454
|
-
return { cache, latest, tag, notFollowingNext: next && !followNext };
|
|
502
|
+
const cache = detectOpenCodeCache(tag, flavor);
|
|
503
|
+
const latest = cache ? (followNext ? lookupOpenCodeNext(flavor) : lookupOpenCodeLatest("latest", flavor)) : undefined;
|
|
504
|
+
return { flavor, cache, latest, tag, spec, notFollowingNext: next && !followNext };
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* The OpenCode plugins this host has: OpenCode 1's always, OpenCode 2's only when the global config
|
|
508
|
+
* names `akm-opencode-v2` or OpenCode 2 has cached it, so a host with just OpenCode 1 sees the same
|
|
509
|
+
* output as before.
|
|
510
|
+
*/
|
|
511
|
+
function resolveOpenCodeTargets(next) {
|
|
512
|
+
const targets = [resolveOpenCodeTarget(next, OPENCODE_V1, openCodeConfigSpec(OPENCODE_V1))];
|
|
513
|
+
const v2 = openCodeConfigSpec(OPENCODE_V2);
|
|
514
|
+
if (v2 || openCodeV2Cached())
|
|
515
|
+
targets.push(resolveOpenCodeTarget(next, OPENCODE_V2, v2));
|
|
516
|
+
return targets;
|
|
455
517
|
}
|
|
456
518
|
/** `akm upgrade`: the CLI step (held to the OpenCode plugin's akm), then the plugins. */
|
|
457
519
|
export async function runUpgrade(args, currentVersion, deps) {
|
|
458
520
|
const next = args.next === true;
|
|
459
521
|
const channel = next ? "next" : "latest";
|
|
460
|
-
const openCode =
|
|
522
|
+
const openCode = resolveOpenCodeTargets(next);
|
|
523
|
+
const held = lockstepSource(openCode);
|
|
461
524
|
const check = {
|
|
462
|
-
...applyLockstep(await deps.checkForUpdate(currentVersion, channel),
|
|
525
|
+
...applyLockstep(await deps.checkForUpdate(currentVersion, channel), held?.latest, held?.tag ?? "latest", held?.flavor.pkg ?? OPENCODE_V1.pkg),
|
|
463
526
|
channel,
|
|
464
527
|
};
|
|
465
528
|
if (args.check) {
|
|
@@ -26,10 +26,8 @@
|
|
|
26
26
|
* `akm sync` directly).
|
|
27
27
|
*/
|
|
28
28
|
import { defineCommand } from "citty";
|
|
29
|
-
import { getParsedInvocation } from "../../cli/invocation.js";
|
|
30
29
|
import { defineJsonCommand, EXIT_CODES, GLOBAL_OUTPUT_ARGS, output, outputWithExitCode, runWithJsonErrors, } from "../../cli/shared.js";
|
|
31
30
|
import { loadConfig } from "../../core/config/config.js";
|
|
32
|
-
import { UsageError } from "../../core/errors.js";
|
|
33
31
|
import { appendEvent } from "../../core/events.js";
|
|
34
32
|
import { resolveWritableOverride, saveGitStash } from "../../sources/providers/git.js";
|
|
35
33
|
import { pkgVersion } from "../../version.js";
|
|
@@ -40,7 +38,7 @@ export const upgradeCommand = defineJsonCommand({
|
|
|
40
38
|
meta: {
|
|
41
39
|
name: "upgrade",
|
|
42
40
|
description: "Upgrade akm to the latest release, then update the akm plugin of each installed harness " +
|
|
43
|
-
"(Claude Code, Codex, OpenCode). With
|
|
41
|
+
"(Claude Code, Codex, OpenCode 1 and 2). With an OpenCode plugin installed, akm moves to the version that plugin pins.",
|
|
44
42
|
},
|
|
45
43
|
args: {
|
|
46
44
|
check: {
|
|
@@ -126,17 +124,6 @@ export const syncCommand = defineCommand({
|
|
|
126
124
|
await runSyncBody(args);
|
|
127
125
|
},
|
|
128
126
|
});
|
|
129
|
-
/**
|
|
130
|
-
* `--target` was renamed to `--bundle` on `clone` in 0.9 (S8). citty is
|
|
131
|
-
* non-strict, so the retired spelling is silently absorbed rather than
|
|
132
|
-
* rejected — the asset then lands in the default bundle instead of the one
|
|
133
|
-
* the caller named, with exit 0 and no error. Reject it explicitly instead.
|
|
134
|
-
*/
|
|
135
|
-
function rejectRetiredCloneTargetFlag() {
|
|
136
|
-
if (!getParsedInvocation().hasFlag("--target"))
|
|
137
|
-
return;
|
|
138
|
-
throw new UsageError("`akm clone --target` was renamed to `--bundle` in 0.9. Use `--bundle <name>` instead.", "INVALID_FLAG_VALUE");
|
|
139
|
-
}
|
|
140
127
|
export const cloneCommand = defineJsonCommand({
|
|
141
128
|
meta: {
|
|
142
129
|
name: "clone",
|
|
@@ -153,7 +140,6 @@ export const cloneCommand = defineJsonCommand({
|
|
|
153
140
|
dest: { type: "string", description: "Unmanaged destination directory (cannot be combined with --bundle)" },
|
|
154
141
|
},
|
|
155
142
|
async run({ args }) {
|
|
156
|
-
rejectRetiredCloneTargetFlag();
|
|
157
143
|
const result = await akmClone({
|
|
158
144
|
sourceRef: args.ref,
|
|
159
145
|
newName: args.name,
|
|
@@ -30,22 +30,20 @@
|
|
|
30
30
|
import path from "node:path";
|
|
31
31
|
import { defineCommand } from "citty";
|
|
32
32
|
import * as p from "../../cli/clack.js";
|
|
33
|
-
import { getParsedInvocation } from "../../cli/invocation.js";
|
|
34
33
|
import { defineJsonCommand, GLOBAL_OUTPUT_ARGS, output, parseAllFlagValues, runWithJsonErrors } from "../../cli/shared.js";
|
|
35
34
|
import { assertFlatAssetName } from "../../core/asset/asset-create.js";
|
|
36
35
|
import { placementTypes } from "../../core/asset/asset-placement.js";
|
|
37
36
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
38
37
|
import { isHttpUrl, resolveStashDir } from "../../core/common.js";
|
|
39
38
|
import { loadConfig } from "../../core/config/config.js";
|
|
40
|
-
import { UsageError } from "../../core/errors.js";
|
|
41
39
|
import { appendEvent } from "../../core/events.js";
|
|
42
40
|
import { resolveBundleWriteTarget } from "../../core/mutation-target.js";
|
|
43
|
-
import {
|
|
41
|
+
import { getRunLogDir } from "../../core/paths.js";
|
|
44
42
|
import { clearLogFile, info, isVerbose, setLogFile } from "../../core/warn.js";
|
|
45
43
|
import { resolveWriteTarget } from "../../core/write-source.js";
|
|
46
44
|
import { releaseIndexRebuildLock, tryAcquireIndexRebuildLock } from "../../indexer/index-rebuild-lock.js";
|
|
47
45
|
import { akmIndex } from "../../indexer/indexer.js";
|
|
48
|
-
import {
|
|
46
|
+
import { getOutputMode } from "../../output/context.js";
|
|
49
47
|
import { pkgVersion } from "../../version.js";
|
|
50
48
|
import { inferAssetName, mergeXrefsIntoContent, readKnowledgeInput, resolveSupersedesForWrite, resolveSupersedesWriteTarget, resolveXrefsForWrite, writeMarkdownAsset, } from "../read/knowledge.js";
|
|
51
49
|
import { assembleInfo } from "./info.js";
|
|
@@ -56,7 +54,7 @@ export const indexCommand = defineCommand({
|
|
|
56
54
|
args: {
|
|
57
55
|
// R-051: `index` is a raw `defineCommand` (not `defineJsonCommand`), so it
|
|
58
56
|
// does not get `GLOBAL_OUTPUT_ARGS` for free. `--format`/`--detail`/
|
|
59
|
-
// `--
|
|
57
|
+
// `--output` already parsed correctly here (this command has no
|
|
60
58
|
// extra positional for a stray value to fall into), so this is purely a
|
|
61
59
|
// `--help` visibility / consistency fix, not a behavior change.
|
|
62
60
|
...GLOBAL_OUTPUT_ARGS,
|
|
@@ -84,12 +82,6 @@ export const indexCommand = defineCommand({
|
|
|
84
82
|
},
|
|
85
83
|
async run({ args }) {
|
|
86
84
|
await runWithJsonErrors(async () => {
|
|
87
|
-
if (getHyphenatedBoolean(args, "enrich") || getParsedInvocation().getFlagValue("--enrich") !== undefined) {
|
|
88
|
-
throw new UsageError("`akm index --enrich` has been removed. Metadata enrichment during indexing is retired; it never runs.");
|
|
89
|
-
}
|
|
90
|
-
if (getHyphenatedBoolean(args, "re-enrich") || getParsedInvocation().getFlagValue("--re-enrich") !== undefined) {
|
|
91
|
-
throw new UsageError("`akm index --re-enrich` has been removed. Metadata enrichment during indexing is retired; there is nothing to re-enrich.");
|
|
92
|
-
}
|
|
93
85
|
// #956: opt-in, non-blocking rebuild lock — never gates a human-typed
|
|
94
86
|
// `akm index` (it only warns and contends), but a scheduled/opportunistic
|
|
95
87
|
// caller can pass --skip-if-locked to step aside instead of piling up
|
|
@@ -116,7 +108,7 @@ export const indexCommand = defineCommand({
|
|
|
116
108
|
const abort = () => controller.abort(new Error("index interrupted"));
|
|
117
109
|
process.once("SIGINT", abort);
|
|
118
110
|
process.once("SIGTERM", abort);
|
|
119
|
-
const indexLogFile = path.join(
|
|
111
|
+
const indexLogFile = path.join(getRunLogDir("index"), `${new Date().toISOString().replace(/[:.]/g, "-")}.log`);
|
|
120
112
|
setLogFile(indexLogFile);
|
|
121
113
|
const verbose = isVerbose();
|
|
122
114
|
const spin = !verbose && outputMode.format === "text" ? p.spinner() : null;
|
|
@@ -229,7 +221,7 @@ export const importKnowledgeCommand = defineJsonCommand({
|
|
|
229
221
|
description: "Overwrite an existing knowledge document with the same name",
|
|
230
222
|
default: false,
|
|
231
223
|
},
|
|
232
|
-
|
|
224
|
+
bundle: {
|
|
233
225
|
type: "string",
|
|
234
226
|
description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working bundle.",
|
|
235
227
|
},
|
|
@@ -250,7 +242,7 @@ export const importKnowledgeCommand = defineJsonCommand({
|
|
|
250
242
|
// read/write so an unresolvable ref (UsageError → exit 2) leaves the
|
|
251
243
|
// stash untouched.
|
|
252
244
|
const rawSupersedes = parseAllFlagValues("--supersedes");
|
|
253
|
-
const writeTarget = resolveSupersedesWriteTarget(rawSupersedes, args.
|
|
245
|
+
const writeTarget = resolveSupersedesWriteTarget(rawSupersedes, args.bundle);
|
|
254
246
|
const xrefs = resolveXrefsForWrite(parseAllFlagValues("--xref"), writeTarget);
|
|
255
247
|
// Collect and validate --supersedes occurrences (repeatable). Same
|
|
256
248
|
// before-any-read/write contract: an unresolvable ref exits 2 with nothing
|