akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4
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 +756 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +7 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +2 -7
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +0 -17
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +363 -679
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +87 -406
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -21
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/config/retired-experimental-keys-shim.js +0 -62
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -78
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* Built-in deterministic triage policy presets (Proposal-Queue Triage, §3.1).
|
|
6
|
-
*
|
|
7
|
-
* These are the *only* "rule schema" we ship. Custom needs are served by the
|
|
8
|
-
* single `--policy <path>` escape hatch, which zod-validates an external policy
|
|
9
|
-
* file — not by a config-embedded rule engine (see §9, rejected alternatives).
|
|
10
|
-
*
|
|
11
|
-
* | preset | accepts | rejects | leaves pending |
|
|
12
|
-
* |------------------|-----------------------------------------------------------|-------------|----------------------------------------------------|
|
|
13
|
-
* | `personal-stash` | extract (real content); reflect ≤80 lines; consolidate | empty diffs | consolidate mid-band, distill dups, contradictions |
|
|
14
|
-
* | `conservative` | small extract + consolidate only | empty diffs | everything else |
|
|
15
|
-
* | `manual` | nothing | empty diffs | everything else |
|
|
16
|
-
*/
|
|
17
|
-
import fs from "node:fs";
|
|
18
|
-
import { z } from "zod";
|
|
19
|
-
import { UsageError } from "../../core/errors.js";
|
|
20
|
-
import { warnOnce } from "../../core/warn.js";
|
|
21
|
-
import { PROPOSAL_SOURCES } from "./repository.js";
|
|
22
|
-
// Valid `generator` values for a drain rule are exactly the canonical proposal
|
|
23
|
-
// `source` values (see {@link PROPOSAL_SOURCES} in src/commands/proposal/repository.ts). The
|
|
24
|
-
// engine matches rules via `policy.accept.find(r => r.generator === proposal.source)`,
|
|
25
|
-
// so a generator that is not a real source can never match — it would be a
|
|
26
|
-
// silent permanent no-op. Validate against the closed set to surface typos.
|
|
27
|
-
const GeneratorSchema = z.enum(PROPOSAL_SOURCES, {
|
|
28
|
-
errorMap: () => ({
|
|
29
|
-
message: `must be one of the known proposal sources: ${PROPOSAL_SOURCES.join(", ")}`,
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
// Built-in presets
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
/**
|
|
36
|
-
* `personal-stash` encodes the deterministic core of today's hand-rolled
|
|
37
|
-
* rubric (the editable `contradicted` memory). It is shipped as a preset, never
|
|
38
|
-
* hardcoded policy: edit a copy via `--policy <path>` to tune it.
|
|
39
|
-
*/
|
|
40
|
-
export const PERSONAL_STASH = {
|
|
41
|
-
name: "personal-stash",
|
|
42
|
-
accept: [
|
|
43
|
-
// Extract proposals carry freshly-pulled real content — accept when present,
|
|
44
|
-
// but cap the diff for parity with reflect(80)/consolidate(200): an
|
|
45
|
-
// arbitrarily large extract should not auto-promote with zero LLM calls.
|
|
46
|
-
{ generator: "extract", minContentLines: 1, maxDiffLines: 200 },
|
|
47
|
-
// Reflect refinements: accept small ones; larger refinements defer to review.
|
|
48
|
-
{ generator: "reflect", maxDiffLines: 80 },
|
|
49
|
-
// Consolidate within the diff band; mid-band lands in `defer` below.
|
|
50
|
-
{ generator: "consolidate", maxDiffLines: 200 },
|
|
51
|
-
],
|
|
52
|
-
rejectEmpty: true,
|
|
53
|
-
// Mid-band consolidate, distill duplicates, and contradiction escalations are
|
|
54
|
-
// the irreducibly-semantic tail — deferred to the (Phase 3) judgment tier.
|
|
55
|
-
defer: ["consolidate", "distill"],
|
|
56
|
-
};
|
|
57
|
-
/** `conservative` accepts only small, low-risk extract + consolidate proposals. */
|
|
58
|
-
export const CONSERVATIVE = {
|
|
59
|
-
name: "conservative",
|
|
60
|
-
accept: [
|
|
61
|
-
{ generator: "extract", maxDiffLines: 80, minContentLines: 1 },
|
|
62
|
-
{ generator: "consolidate", maxDiffLines: 80 },
|
|
63
|
-
],
|
|
64
|
-
rejectEmpty: true,
|
|
65
|
-
defer: [],
|
|
66
|
-
};
|
|
67
|
-
/** `manual` accepts nothing; it only clears empty diffs. */
|
|
68
|
-
export const MANUAL = {
|
|
69
|
-
name: "manual",
|
|
70
|
-
accept: [],
|
|
71
|
-
rejectEmpty: true,
|
|
72
|
-
defer: [],
|
|
73
|
-
};
|
|
74
|
-
const BUILTIN_POLICIES = {
|
|
75
|
-
"personal-stash": PERSONAL_STASH,
|
|
76
|
-
conservative: CONSERVATIVE,
|
|
77
|
-
manual: MANUAL,
|
|
78
|
-
};
|
|
79
|
-
/** Names of the built-in presets, for help text and validation messages. */
|
|
80
|
-
export const BUILTIN_POLICY_NAMES = Object.keys(BUILTIN_POLICIES);
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
// Custom policy file schema (`--policy <path>`)
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
const DrainAcceptRuleSchema = z
|
|
85
|
-
.object({
|
|
86
|
-
generator: GeneratorSchema,
|
|
87
|
-
maxDiffLines: z.number().int().positive().optional(),
|
|
88
|
-
minContentLines: z.number().int().nonnegative().optional(),
|
|
89
|
-
requireType: z.string().optional(),
|
|
90
|
-
})
|
|
91
|
-
.passthrough();
|
|
92
|
-
const DrainPolicySchema = z
|
|
93
|
-
.object({
|
|
94
|
-
name: z.string().min(1),
|
|
95
|
-
accept: z.array(DrainAcceptRuleSchema),
|
|
96
|
-
rejectEmpty: z.boolean(),
|
|
97
|
-
defer: z.array(GeneratorSchema),
|
|
98
|
-
})
|
|
99
|
-
.passthrough();
|
|
100
|
-
function warnIgnoredPolicyKeys(filePath, label, raw, knownKeys) {
|
|
101
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
102
|
-
return;
|
|
103
|
-
const extra = Object.keys(raw).filter((key) => !knownKeys.includes(key));
|
|
104
|
-
if (extra.length === 0)
|
|
105
|
-
return;
|
|
106
|
-
warnOnce(`drain-policy-ignored-keys:${filePath}:${label}:${extra.join(",")}`, `[proposal] Policy file "${filePath}" has ${label} field(s) akm does not recognize and ignores: ${extra.join(", ")}. Check for a typo, or the file may be written for a newer akm version.`);
|
|
107
|
-
}
|
|
108
|
-
const DRAIN_POLICY_KNOWN_KEYS = Object.keys(DrainPolicySchema.shape);
|
|
109
|
-
const DRAIN_ACCEPT_RULE_KNOWN_KEYS = Object.keys(DrainAcceptRuleSchema.shape);
|
|
110
|
-
/**
|
|
111
|
-
* Resolve a `--policy <preset|path>` argument into a {@link DrainPolicy}.
|
|
112
|
-
*
|
|
113
|
-
* - A bare preset name (`personal-stash` / `conservative` / `manual`) returns
|
|
114
|
-
* the matching built-in.
|
|
115
|
-
* - Anything else is treated as a filesystem path to a JSON policy file, which
|
|
116
|
-
* is read and zod-validated.
|
|
117
|
-
*
|
|
118
|
-
* Throws a {@link UsageError} on an unknown preset, a missing file, or a file
|
|
119
|
-
* that fails schema validation.
|
|
120
|
-
*/
|
|
121
|
-
export function resolveDrainPolicy(arg) {
|
|
122
|
-
const value = (arg ?? "personal-stash").trim();
|
|
123
|
-
const builtin = BUILTIN_POLICIES[value];
|
|
124
|
-
if (builtin)
|
|
125
|
-
return builtin;
|
|
126
|
-
// Treat as a path to a custom policy file.
|
|
127
|
-
if (!fs.existsSync(value)) {
|
|
128
|
-
throw new UsageError(`Unknown policy "${value}". Use a built-in preset (${BUILTIN_POLICY_NAMES.join(", ")}) or a path to a policy file.`, "INVALID_FLAG_VALUE");
|
|
129
|
-
}
|
|
130
|
-
let parsed;
|
|
131
|
-
try {
|
|
132
|
-
parsed = JSON.parse(fs.readFileSync(value, "utf8"));
|
|
133
|
-
}
|
|
134
|
-
catch (err) {
|
|
135
|
-
throw new UsageError(`Could not parse policy file "${value}": ${err instanceof Error ? err.message : String(err)}`, "INVALID_FLAG_VALUE");
|
|
136
|
-
}
|
|
137
|
-
const validated = DrainPolicySchema.safeParse(parsed);
|
|
138
|
-
if (!validated.success) {
|
|
139
|
-
throw new UsageError(`Invalid policy file "${value}": ${validated.error.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ")}`, "INVALID_FLAG_VALUE");
|
|
140
|
-
}
|
|
141
|
-
warnIgnoredPolicyKeys(value, "top-level", parsed, DRAIN_POLICY_KNOWN_KEYS);
|
|
142
|
-
if (parsed &&
|
|
143
|
-
typeof parsed === "object" &&
|
|
144
|
-
!Array.isArray(parsed) &&
|
|
145
|
-
Array.isArray(parsed.accept)) {
|
|
146
|
-
parsed.accept.forEach((rule, index) => {
|
|
147
|
-
warnIgnoredPolicyKeys(value, `accept[${index}]`, rule, DRAIN_ACCEPT_RULE_KNOWN_KEYS);
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
return validated.data;
|
|
151
|
-
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { randomBytes } from "node:crypto";
|
|
5
|
-
import fs from "node:fs";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import { ConfigError } from "../../core/errors.js";
|
|
8
|
-
import { warn } from "../../core/warn.js";
|
|
9
|
-
import { runGit } from "../../sources/providers/git.js";
|
|
10
|
-
import { assertNoIgnoredPathOverwrite } from "../../sources/providers/git-install.js";
|
|
11
|
-
export function prepareDirectoryPublication(stagedRoot, liveRoot) {
|
|
12
|
-
const backupRoot = `${liveRoot}.akm-update-backup-${randomBytes(6).toString("hex")}`;
|
|
13
|
-
let published = false;
|
|
14
|
-
let hadLiveRoot = false;
|
|
15
|
-
return {
|
|
16
|
-
publish() {
|
|
17
|
-
if (published)
|
|
18
|
-
throw new ConfigError(`Update content at ${liveRoot} was already published.`);
|
|
19
|
-
hadLiveRoot = fs.existsSync(liveRoot);
|
|
20
|
-
fs.mkdirSync(path.dirname(liveRoot), { recursive: true });
|
|
21
|
-
if (hadLiveRoot)
|
|
22
|
-
fs.renameSync(liveRoot, backupRoot);
|
|
23
|
-
try {
|
|
24
|
-
fs.renameSync(stagedRoot, liveRoot);
|
|
25
|
-
published = true;
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
if (hadLiveRoot && fs.existsSync(backupRoot))
|
|
29
|
-
fs.renameSync(backupRoot, liveRoot);
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
rollback() {
|
|
34
|
-
if (!published)
|
|
35
|
-
return;
|
|
36
|
-
const failedRoot = `${liveRoot}.akm-update-failed-${randomBytes(6).toString("hex")}`;
|
|
37
|
-
if (fs.existsSync(liveRoot))
|
|
38
|
-
fs.renameSync(liveRoot, failedRoot);
|
|
39
|
-
try {
|
|
40
|
-
if (hadLiveRoot && fs.existsSync(backupRoot))
|
|
41
|
-
fs.renameSync(backupRoot, liveRoot);
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
// The prior generation could not be restored. Put the published
|
|
45
|
-
// candidate back at the live path so resolution never sees a missing
|
|
46
|
-
// root, then surface the rollback failure loudly.
|
|
47
|
-
try {
|
|
48
|
-
if (!fs.existsSync(liveRoot) && fs.existsSync(failedRoot))
|
|
49
|
-
fs.renameSync(failedRoot, liveRoot);
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// Preserve the original restoration failure; both paths remain for
|
|
53
|
-
// manual recovery when even the defensive rename cannot complete.
|
|
54
|
-
}
|
|
55
|
-
published = false;
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
fs.rmSync(failedRoot, { recursive: true, force: true });
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
warn(`[akm bundle update] restored ${liveRoot}, but could not remove failed candidate ${failedRoot}: ${error instanceof Error ? error.message : String(error)}`);
|
|
63
|
-
}
|
|
64
|
-
published = false;
|
|
65
|
-
},
|
|
66
|
-
commit() {
|
|
67
|
-
if (hadLiveRoot) {
|
|
68
|
-
try {
|
|
69
|
-
fs.rmSync(backupRoot, { recursive: true, force: true });
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
warn(`[akm bundle update] update committed, but could not remove backup ${backupRoot}: ${error instanceof Error ? error.message : String(error)}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
published = false;
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function gitOutput(repoDir, args, description) {
|
|
80
|
-
const result = runGit(["-C", repoDir, ...args], { timeout: 120_000 });
|
|
81
|
-
if (result.status !== 0) {
|
|
82
|
-
throw new ConfigError(`${description}: ${result.stderr.trim() || result.stdout.trim() || "git failed"}`);
|
|
83
|
-
}
|
|
84
|
-
return result.stdout.trim();
|
|
85
|
-
}
|
|
86
|
-
function assertGitCheckoutGeneration(repoDir, expectedHead, phase) {
|
|
87
|
-
const actualHead = gitOutput(repoDir, ["rev-parse", "HEAD"], `Cannot read writable Git HEAD at ${repoDir}`);
|
|
88
|
-
if (actualHead !== expectedHead) {
|
|
89
|
-
throw new ConfigError(`Writable Git checkout at ${repoDir} changed after the update was audited (${phase}: expected ${expectedHead}, found ${actualHead}); refusing to overwrite the live commit.`);
|
|
90
|
-
}
|
|
91
|
-
const status = gitOutput(repoDir, ["status", "--porcelain=v1", "--untracked-files=all", "--ignore-submodules=none"], `Cannot inspect writable Git checkout at ${repoDir}`);
|
|
92
|
-
if (status) {
|
|
93
|
-
throw new ConfigError(`Writable Git checkout at ${repoDir} changed after the update was audited (${phase}: working tree is no longer clean); refusing to overwrite live files.`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function assertNoGitlinks(repoDir, targetHead) {
|
|
97
|
-
const tree = gitOutput(repoDir, ["ls-tree", "-r", "-z", targetHead], `Cannot inspect audited Git tree ${targetHead} at ${repoDir}`);
|
|
98
|
-
const gitlink = tree.split("\0").find((entry) => entry.startsWith("160000 "));
|
|
99
|
-
if (gitlink) {
|
|
100
|
-
const targetPath = gitlink.slice(gitlink.indexOf("\t") + 1);
|
|
101
|
-
throw new ConfigError(`Writable Git target contains unaudited submodule/gitlink ${targetPath}; refusing to materialize it.`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function copyWorktree(source, destination) {
|
|
105
|
-
fs.mkdirSync(destination, { recursive: true, mode: 0o700 });
|
|
106
|
-
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
|
|
107
|
-
if (entry.name === ".git")
|
|
108
|
-
continue;
|
|
109
|
-
fs.cpSync(path.join(source, entry.name), path.join(destination, entry.name), {
|
|
110
|
-
recursive: true,
|
|
111
|
-
preserveTimestamps: true,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function clearWorktree(repoDir) {
|
|
116
|
-
for (const entry of fs.readdirSync(repoDir, { withFileTypes: true })) {
|
|
117
|
-
if (entry.name === ".git")
|
|
118
|
-
continue;
|
|
119
|
-
fs.rmSync(path.join(repoDir, entry.name), { recursive: true, force: true });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Publish the exact audited commit into a writable checkout without replacing
|
|
124
|
-
* the checkout directory. The expected-old-HEAD and clean-tree fence runs
|
|
125
|
-
* under the caller's asset mutation lease immediately before the fast-forward.
|
|
126
|
-
*/
|
|
127
|
-
export function prepareWritableGitPublication(opts) {
|
|
128
|
-
let published = false;
|
|
129
|
-
let rollbackParent;
|
|
130
|
-
let rollbackWorktree;
|
|
131
|
-
const discardRollback = () => {
|
|
132
|
-
if (!rollbackParent)
|
|
133
|
-
return;
|
|
134
|
-
cleanupStagingParent(rollbackParent);
|
|
135
|
-
rollbackParent = undefined;
|
|
136
|
-
rollbackWorktree = undefined;
|
|
137
|
-
};
|
|
138
|
-
const restore = () => {
|
|
139
|
-
if (!rollbackWorktree)
|
|
140
|
-
return;
|
|
141
|
-
const actualHead = gitOutput(opts.liveRepo, ["rev-parse", "HEAD"], `Cannot read writable Git rollback HEAD`);
|
|
142
|
-
if (actualHead !== opts.expectedOldHead && actualHead !== opts.auditedTargetHead) {
|
|
143
|
-
throw new ConfigError(`Writable Git checkout ${opts.liveRepo} advanced concurrently to ${actualHead}; refusing to overwrite that commit during rollback.`);
|
|
144
|
-
}
|
|
145
|
-
gitOutput(opts.liveRepo, ["reset", "--hard", opts.expectedOldHead], `Cannot restore writable Git checkout ${opts.liveRepo} to ${opts.expectedOldHead}`);
|
|
146
|
-
clearWorktree(opts.liveRepo);
|
|
147
|
-
copyWorktree(rollbackWorktree, opts.liveRepo);
|
|
148
|
-
assertGitCheckoutGeneration(opts.liveRepo, opts.expectedOldHead, "rollback verification");
|
|
149
|
-
published = false;
|
|
150
|
-
discardRollback();
|
|
151
|
-
};
|
|
152
|
-
return {
|
|
153
|
-
publish() {
|
|
154
|
-
if (published)
|
|
155
|
-
throw new ConfigError(`Writable Git update at ${opts.liveRepo} was already published.`);
|
|
156
|
-
assertGitCheckoutGeneration(opts.liveRepo, opts.expectedOldHead, "pre-publish fence");
|
|
157
|
-
assertGitCheckoutGeneration(opts.stagedRepo, opts.auditedTargetHead, "staged audit fence");
|
|
158
|
-
const ancestor = runGit([
|
|
159
|
-
"-C",
|
|
160
|
-
opts.stagedRepo,
|
|
161
|
-
"merge-base",
|
|
162
|
-
"--is-ancestor",
|
|
163
|
-
opts.expectedOldHead,
|
|
164
|
-
opts.auditedTargetHead,
|
|
165
|
-
]);
|
|
166
|
-
if (ancestor.status !== 0) {
|
|
167
|
-
throw new ConfigError(`Audited Git target ${opts.auditedTargetHead} is not a fast-forward of live HEAD ${opts.expectedOldHead}; refusing writable update.`);
|
|
168
|
-
}
|
|
169
|
-
assertNoGitlinks(opts.stagedRepo, opts.auditedTargetHead);
|
|
170
|
-
gitOutput(opts.liveRepo, ["fetch", "--no-tags", opts.stagedRepo, opts.auditedTargetHead], `Cannot import audited Git target ${opts.auditedTargetHead} into ${opts.liveRepo}`);
|
|
171
|
-
// A non-cooperating local Git command may have committed while fetch ran.
|
|
172
|
-
assertGitCheckoutGeneration(opts.liveRepo, opts.expectedOldHead, "post-fetch fence");
|
|
173
|
-
assertNoIgnoredPathOverwrite(opts.liveRepo, opts.auditedTargetHead);
|
|
174
|
-
rollbackParent = createStagingParent(path.dirname(opts.liveRepo));
|
|
175
|
-
rollbackWorktree = path.join(rollbackParent, "worktree");
|
|
176
|
-
try {
|
|
177
|
-
copyWorktree(opts.liveRepo, rollbackWorktree);
|
|
178
|
-
}
|
|
179
|
-
catch (error) {
|
|
180
|
-
discardRollback();
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
try {
|
|
184
|
-
gitOutput(opts.liveRepo, ["merge", "--ff-only", "--no-overwrite-ignore", opts.auditedTargetHead], `Cannot fast-forward writable Git checkout ${opts.liveRepo}`);
|
|
185
|
-
published = true;
|
|
186
|
-
assertGitCheckoutGeneration(opts.liveRepo, opts.auditedTargetHead, "post-materialization fence");
|
|
187
|
-
}
|
|
188
|
-
catch (error) {
|
|
189
|
-
try {
|
|
190
|
-
restore();
|
|
191
|
-
}
|
|
192
|
-
catch (restoreError) {
|
|
193
|
-
throw new ConfigError(`Writable Git publication failed and its worktree could not be restored: ${restoreError instanceof Error ? restoreError.message : String(restoreError)}`);
|
|
194
|
-
}
|
|
195
|
-
throw error;
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
rollback() {
|
|
199
|
-
if (!published)
|
|
200
|
-
return;
|
|
201
|
-
restore();
|
|
202
|
-
},
|
|
203
|
-
commit() {
|
|
204
|
-
published = false;
|
|
205
|
-
discardRollback();
|
|
206
|
-
},
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
export function createStagingParent(parent) {
|
|
210
|
-
fs.mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
211
|
-
return fs.mkdtempSync(path.join(parent, ".akm-update-stage-"));
|
|
212
|
-
}
|
|
213
|
-
export function cleanupStagingParent(stagingParent) {
|
|
214
|
-
try {
|
|
215
|
-
fs.rmSync(stagingParent, { recursive: true, force: true });
|
|
216
|
-
}
|
|
217
|
-
catch (error) {
|
|
218
|
-
warn(`[akm bundle update] could not remove staging directory ${stagingParent}: ${error instanceof Error ? error.message : String(error)}`);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { defaultRendererRegistry } from "./type-presentation.js";
|
|
5
|
-
function registryActionContributor(registry) {
|
|
6
|
-
return {
|
|
7
|
-
name: "registry-action-contributor",
|
|
8
|
-
appliesTo(ctx) {
|
|
9
|
-
return registry.actionBuilderFor(ctx.type) !== undefined;
|
|
10
|
-
},
|
|
11
|
-
buildAction(ctx) {
|
|
12
|
-
return registry.actionBuilderFor(ctx.type)?.(ctx.ref);
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export function defaultActionContributors(registry = defaultRendererRegistry) {
|
|
17
|
-
return [registryActionContributor(registry)];
|
|
18
|
-
}
|
|
19
|
-
export function buildActionFromContributors(ctx, contributors = defaultActionContributors()) {
|
|
20
|
-
for (const contributor of contributors) {
|
|
21
|
-
if (!contributor.appliesTo(ctx))
|
|
22
|
-
continue;
|
|
23
|
-
const action = contributor.buildAction(ctx);
|
|
24
|
-
if (action !== undefined)
|
|
25
|
-
return action;
|
|
26
|
-
}
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* The `configVersion` read shim (#863).
|
|
6
|
-
*
|
|
7
|
-
* `configVersion` used to be a hard `z.literal(CURRENT_CONFIG_VERSION)` gate:
|
|
8
|
-
* every value other than the exact current string threw
|
|
9
|
-
* `UNSUPPORTED_CONFIG_VERSION` for every command, since every akm invocation
|
|
10
|
-
* loads config first. That is the same shape of break #858/#859 (proposal
|
|
11
|
-
* rows), the `task_history` `metadataVersion` gate, and the task-source v2/v3
|
|
12
|
-
* gate each caused in 0.9.x — a version gate with no read shim — except
|
|
13
|
-
* `configVersion`'s blast radius is the whole CLI rather than one subsystem.
|
|
14
|
-
*
|
|
15
|
-
* This module mirrors the in-tree template for that fix,
|
|
16
|
-
* `src/tasks/source/parse-task-source.ts`'s v2/v3 -> v4 shim: a known-old
|
|
17
|
-
* version routes through a pure, in-memory upgrade function to the current
|
|
18
|
-
* shape, with a one-line stderr deprecation warning; the result is never
|
|
19
|
-
* written back to disk (the on-disk rewrite already happens for free — every
|
|
20
|
-
* `saveConfig`/`mutateConfig` write forces `configVersion` to
|
|
21
|
-
* {@link CURRENT_CONFIG_VERSION}, so the very next `akm config set` or any
|
|
22
|
-
* other mutating command silences the warning permanently). A version that is
|
|
23
|
-
* neither current nor a known old version — including anything NEWER than
|
|
24
|
-
* current — still fails closed with `UNSUPPORTED_CONFIG_VERSION`:
|
|
25
|
-
* forward-incompatibility is a real hazard (an older binary must not guess at
|
|
26
|
-
* a newer, unknown shape) and this shim does not soften that.
|
|
27
|
-
*
|
|
28
|
-
* IMPORTANT — as of this writing, `"0.9.0"` is the only `configVersion` akm
|
|
29
|
-
* has ever shipped; there is no real prior release to shim. `"0.0.1"` below
|
|
30
|
-
* is a SYNTHETIC placeholder entry that exists solely to stand up and
|
|
31
|
-
* exercise this mechanism — the known-versions list, the dispatch table, the
|
|
32
|
-
* warn-once-and-upgrade behavior, the fail-closed behavior for anything
|
|
33
|
-
* else — before a real bump ever needs it (see
|
|
34
|
-
* `tests/integration/config-version-shim.test.ts` and the
|
|
35
|
-
* `previous-release-corpus.test.ts` fixture). When the first genuine
|
|
36
|
-
* `configVersion` bump ships, add its real old shape as its own entry the
|
|
37
|
-
* same way and delete the synthetic `"0.0.1"` entry (and this paragraph) in
|
|
38
|
-
* the same change.
|
|
39
|
-
*/
|
|
40
|
-
import { ConfigError } from "../errors.js";
|
|
41
|
-
import { warn } from "../warn.js";
|
|
42
|
-
import { CURRENT_CONFIG_VERSION } from "./schema/primitives.js";
|
|
43
|
-
/**
|
|
44
|
-
* Every `configVersion` this binary can still READ, other than
|
|
45
|
-
* {@link CURRENT_CONFIG_VERSION} itself — each with an in-memory upgrade
|
|
46
|
-
* function in {@link CONFIG_VERSION_UPGRADES}. Anything not in this list (and
|
|
47
|
-
* not equal to current) fails closed.
|
|
48
|
-
*/
|
|
49
|
-
export const KNOWN_OLD_CONFIG_VERSIONS = ["0.0.1"];
|
|
50
|
-
function isKnownOldConfigVersion(value) {
|
|
51
|
-
return typeof value === "string" && KNOWN_OLD_CONFIG_VERSIONS.includes(value);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* SYNTHETIC 0.0.1 -> 0.9.0 upgrade (placeholder — see module doc). Per this
|
|
55
|
-
* placeholder, 0.0.1 kept the default LLM engine name at the config root as
|
|
56
|
-
* `defaultEngine`; 0.9.0 moved it under `defaults.llmEngine`. Pure function:
|
|
57
|
-
* takes the raw parsed JSON object, returns a new raw object with the 0.9.0
|
|
58
|
-
* shape. Never touches disk.
|
|
59
|
-
*/
|
|
60
|
-
function upgradeFrom080(raw) {
|
|
61
|
-
const { defaultEngine, defaults, ...rest } = raw;
|
|
62
|
-
if (typeof defaultEngine !== "string" || defaultEngine.length === 0) {
|
|
63
|
-
return { ...rest, ...(defaults !== undefined ? { defaults } : {}), configVersion: CURRENT_CONFIG_VERSION };
|
|
64
|
-
}
|
|
65
|
-
const existingDefaults = defaults !== null && typeof defaults === "object" ? defaults : {};
|
|
66
|
-
return {
|
|
67
|
-
...rest,
|
|
68
|
-
configVersion: CURRENT_CONFIG_VERSION,
|
|
69
|
-
// An explicit `defaults.llmEngine` already present in the raw 0.0.1
|
|
70
|
-
// document (should never happen for a real 0.0.1 file, but a malformed
|
|
71
|
-
// one is possible) wins over the root-level field being migrated in.
|
|
72
|
-
defaults: { llmEngine: defaultEngine, ...existingDefaults },
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
const CONFIG_VERSION_UPGRADES = {
|
|
76
|
-
"0.0.1": upgradeFrom080,
|
|
77
|
-
};
|
|
78
|
-
function unsupportedConfigVersionError(rawVersion, sourcePath) {
|
|
79
|
-
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
80
|
-
const supported = [CURRENT_CONFIG_VERSION, ...KNOWN_OLD_CONFIG_VERSIONS].map((v) => `"${v}"`).join(", ");
|
|
81
|
-
return new ConfigError(`Unsupported configVersion${where}: got ${JSON.stringify(rawVersion)}, expected one of ${supported}.`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Route a raw parsed config object through the version shim before schema
|
|
85
|
-
* validation. Returns a raw object whose `configVersion` is
|
|
86
|
-
* {@link CURRENT_CONFIG_VERSION} — either unchanged (already current),
|
|
87
|
-
* in-memory-upgraded (a known old version, with a one-line stderr warning),
|
|
88
|
-
* or this throws `UNSUPPORTED_CONFIG_VERSION` (unknown, newer, missing, or
|
|
89
|
-
* malformed).
|
|
90
|
-
*/
|
|
91
|
-
export function upgradeConfigVersion(raw, sourcePath) {
|
|
92
|
-
const version = raw.configVersion;
|
|
93
|
-
if (version === CURRENT_CONFIG_VERSION)
|
|
94
|
-
return raw;
|
|
95
|
-
if (isKnownOldConfigVersion(version)) {
|
|
96
|
-
const upgraded = CONFIG_VERSION_UPGRADES[version](raw);
|
|
97
|
-
warn(`Config${sourcePath ? ` at ${sourcePath}` : ""} uses configVersion "${version}" — auto-upgraded to ${CURRENT_CONFIG_VERSION} in memory; the next config write (e.g. \`akm config set\`) persists this and silences the warning.`);
|
|
98
|
-
return upgraded;
|
|
99
|
-
}
|
|
100
|
-
throw unsupportedConfigVersionError(version, sourcePath);
|
|
101
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* `experimental.*` retired-key shim.
|
|
6
|
-
*
|
|
7
|
-
* `ExperimentalConfigSchema` (`./schema/experimental.ts`) moved from
|
|
8
|
-
* `.passthrough()` to `.strict()` in 0.9.16 (`cc6152e02`) so a typo in an
|
|
9
|
-
* authority flag (e.g. `improveAutonomyy`) fails loudly instead of silently
|
|
10
|
-
* doing nothing. `workflowEngine` was removed from that block earlier, in
|
|
11
|
-
* `e0655d13c`, but 0.9.15's passthrough still accepted it — so a real config
|
|
12
|
-
* written by 0.9.15 can carry `experimental.workflowEngine` and now fails
|
|
13
|
-
* every command with `Invalid config: experimental: Unrecognized key(s)`.
|
|
14
|
-
*
|
|
15
|
-
* Per AGENTS.md "Reading persisted data": a reader tolerates what older
|
|
16
|
-
* releases wrote, converts in memory, warns once, and leaves the on-disk
|
|
17
|
-
* rewrite to `akm migrate apply`. This mirrors `./legacy-source-shape-shim.ts`
|
|
18
|
-
* exactly — strip the retired key(s) before schema validation, warn once
|
|
19
|
-
* naming the key and the migrate command — rather than reintroducing
|
|
20
|
-
* `.passthrough()`, which would also let a live key typo through silently.
|
|
21
|
-
*/
|
|
22
|
-
import { isRecord } from "../common.js";
|
|
23
|
-
import { warnOnce } from "../warn.js";
|
|
24
|
-
/**
|
|
25
|
-
* Every `experimental.*` key `ExperimentalConfigSchema` has ever retired.
|
|
26
|
-
* `workflowEngine` (removed in `e0655d13c`) is the only one so far — kept as
|
|
27
|
-
* a list because the shim and `akm migrate apply`
|
|
28
|
-
* (`scripts/akm-migrate/migrate/config-retired-experimental-keys.ts`) share
|
|
29
|
-
* it.
|
|
30
|
-
*/
|
|
31
|
-
export const RETIRED_EXPERIMENTAL_KEYS = ["workflowEngine"];
|
|
32
|
-
/**
|
|
33
|
-
* Which `RETIRED_EXPERIMENTAL_KEYS` are present in a raw config's
|
|
34
|
-
* `experimental` section. Returns `[]` when `raw.experimental` is missing or
|
|
35
|
-
* not a record. Shared by `stripRetiredExperimentalKeys` below and by
|
|
36
|
-
* `akm migrate apply`'s on-disk counterpart
|
|
37
|
-
* (`scripts/akm-migrate/migrate/config-retired-experimental-keys.ts`).
|
|
38
|
-
*/
|
|
39
|
-
export function retiredExperimentalKeysIn(raw) {
|
|
40
|
-
const experimental = raw.experimental;
|
|
41
|
-
if (!isRecord(experimental))
|
|
42
|
-
return [];
|
|
43
|
-
return RETIRED_EXPERIMENTAL_KEYS.filter((key) => key in experimental);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Drop retired `experimental.*` keys from a raw parsed config object before
|
|
47
|
-
* schema validation, warning once per source when any were present. Live
|
|
48
|
-
* keys (including an unrecognized one, e.g. a typo) are left untouched for
|
|
49
|
-
* `ExperimentalConfigSchema.strict()` to reject as before.
|
|
50
|
-
*/
|
|
51
|
-
export function stripRetiredExperimentalKeys(raw, sourcePath) {
|
|
52
|
-
const present = retiredExperimentalKeysIn(raw);
|
|
53
|
-
if (present.length === 0)
|
|
54
|
-
return raw;
|
|
55
|
-
const original = raw.experimental;
|
|
56
|
-
const experimental = { ...original };
|
|
57
|
-
for (const key of present)
|
|
58
|
-
delete experimental[key];
|
|
59
|
-
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
60
|
-
warnOnce(`config:retired-experimental-key${sourcePath ? `:${sourcePath}` : ""}`, `Config${where} uses the retired experimental key(s) ${present.join(", ")} — ignored in memory. Run \`akm migrate apply\` to remove ${present.length === 1 ? "it" : "them"} from the config file and silence this warning.`);
|
|
61
|
-
return { ...raw, experimental };
|
|
62
|
-
}
|