akm-cli 0.9.17-alpha.3 → 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 +731 -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 +361 -751
- 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 -441
- 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
|
@@ -2,20 +2,14 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* Top-level `improve` config section (
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Top-level `improve` config section (salience, state GC, strategies). Retired
|
|
6
|
+
* keys (`salience.replayBudget`, `collapseDetector`, `utilityDecay`) are
|
|
7
|
+
* tolerated as unknown keys.
|
|
8
8
|
*/
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { ImproveProfileConfigSchema } from "./improve-processes.js";
|
|
11
11
|
import { engineName, nonNegativeNumber } from "./primitives.js";
|
|
12
|
-
// ── Improve top-level (
|
|
13
|
-
const ImproveUtilityDecaySchema = z
|
|
14
|
-
.object({
|
|
15
|
-
halfLifeDays: z.number().finite().min(0.1).optional(),
|
|
16
|
-
feedbackStabilityBoost: z.number().finite().min(1).optional(),
|
|
17
|
-
})
|
|
18
|
-
.passthrough();
|
|
12
|
+
// ── Improve top-level (event retention, salience, state GC) ────────────────
|
|
19
13
|
const ImproveSalienceSchema = z
|
|
20
14
|
.object({
|
|
21
15
|
/**
|
|
@@ -34,36 +28,6 @@ const ImproveSalienceSchema = z
|
|
|
34
28
|
* Default 0.75. Set to 1.0 to disable the lane entirely.
|
|
35
29
|
*/
|
|
36
30
|
salienceThreshold: z.number().min(0).max(1).optional(),
|
|
37
|
-
/**
|
|
38
|
-
* Per-run additive replay budget (#610). Up to this many top-salience refs are
|
|
39
|
-
* revisited even with no reactive signal and regardless of cooldown. Additive
|
|
40
|
-
* on top of --limit. Default 0 = no replay.
|
|
41
|
-
*/
|
|
42
|
-
replayBudget: z.number().int().min(0).optional(),
|
|
43
|
-
})
|
|
44
|
-
.passthrough();
|
|
45
|
-
// R5 — longitudinal collapse detector (observe-only; deterministic,
|
|
46
|
-
// fail-open, runs only on cycles where consolidate did work).
|
|
47
|
-
// Default ON; opt out via `improve.collapseDetector.enabled: false`.
|
|
48
|
-
// See docs/architecture/specs/improve-collapse-churn-detector-design.md.
|
|
49
|
-
// The design's CHURN alert class was removed (never fired in production —
|
|
50
|
-
// its accepted-change-volume input was always a hardcoded 0), so this schema
|
|
51
|
-
// no longer carries `churnMinAcceptedActions`.
|
|
52
|
-
const ImproveCollapseDetectorSchema = z
|
|
53
|
-
.object({
|
|
54
|
-
enabled: z.boolean().optional(),
|
|
55
|
-
// Canary set size minted on first run (owner-approved 30–50 range; default 40).
|
|
56
|
-
canaryCount: z.number().int().min(3).max(200).optional(),
|
|
57
|
-
// Top-K cutoff for canary recall/nDCG (default 10).
|
|
58
|
-
k: z.number().int().min(1).max(100).optional(),
|
|
59
|
-
// Trend window in qualifying cycles (default 5).
|
|
60
|
-
windowCycles: z.number().int().min(2).max(50).optional(),
|
|
61
|
-
// Absolute mean-recall drop vs window median that fires collapse (default 0.15).
|
|
62
|
-
recallDropThreshold: z.number().min(0).max(1).optional(),
|
|
63
|
-
// distinct-content-ratio decline over the window that fires collapse (default 0.05).
|
|
64
|
-
entropyDropThreshold: z.number().min(0).max(1).optional(),
|
|
65
|
-
// improve_cycle_metrics retention (default 365 days, owner-approved).
|
|
66
|
-
retentionDays: z.number().int().min(1).optional(),
|
|
67
31
|
})
|
|
68
32
|
.passthrough();
|
|
69
33
|
// #733 — orphan-GC pass (Workstream C, lean by design: one config gate).
|
|
@@ -85,10 +49,8 @@ const ImproveStateGcSchema = z
|
|
|
85
49
|
export const ImproveConfigSchema = z
|
|
86
50
|
.object({
|
|
87
51
|
strategies: z.record(engineName, ImproveProfileConfigSchema).optional(),
|
|
88
|
-
utilityDecay: ImproveUtilityDecaySchema.optional(),
|
|
89
52
|
eventRetentionDays: nonNegativeNumber.optional(),
|
|
90
53
|
salience: ImproveSalienceSchema.optional(),
|
|
91
|
-
collapseDetector: ImproveCollapseDetectorSchema.optional(),
|
|
92
54
|
stateGc: ImproveStateGcSchema.optional(),
|
|
93
55
|
})
|
|
94
56
|
.passthrough();
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { nonEmptyString } from "./primitives.js";
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
.object({
|
|
9
|
-
|
|
10
|
-
ref
|
|
11
|
-
/** Identity of the configured source this host approved, not merely its mutable bundle name. */
|
|
12
|
-
sourceId: z.string().regex(/^sha256:[0-9a-f]{64}$/),
|
|
13
|
-
})
|
|
14
|
-
.strict();
|
|
15
|
-
/** Absence from this allow-list means disabled. */
|
|
6
|
+
/** A 0.9.17-alpha `{kind, ref, sourceId}` activation, read as its ref. */
|
|
7
|
+
const LegacySchedulerActivationSchema = z
|
|
8
|
+
.object({ ref: nonEmptyString })
|
|
9
|
+
.passthrough()
|
|
10
|
+
.transform((activation) => activation.ref);
|
|
16
11
|
export const SchedulerConfigSchema = z
|
|
17
12
|
.object({
|
|
18
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Fully-qualified refs (`bundle//tasks/x`, `bundle//workflows/y`) this host
|
|
15
|
+
* schedules. Absent when the host has never chosen: `akm task sync` then
|
|
16
|
+
* takes the akm-written rows already installed as the choice and writes it.
|
|
17
|
+
*/
|
|
18
|
+
enabled: z.array(z.union([nonEmptyString, LegacySchedulerActivationSchema])).optional(),
|
|
19
19
|
})
|
|
20
|
-
.
|
|
20
|
+
.passthrough();
|
|
@@ -2,29 +2,15 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* `search` config section
|
|
6
|
-
*
|
|
5
|
+
* `search` config section: default type exclusion and the optional curate
|
|
6
|
+
* reranker.
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { httpUrl, nonEmptyString,
|
|
9
|
+
import { httpUrl, nonEmptyString, positiveInt, symbolicOrWarnApiKey } from "./primitives.js";
|
|
10
10
|
// ── Search ──────────────────────────────────────────────────────────────────
|
|
11
|
-
const SearchGraphBoostSchema = z
|
|
12
|
-
.object({
|
|
13
|
-
directBoostPerEntity: nonNegativeNumber.optional(),
|
|
14
|
-
directBoostCap: nonNegativeNumber.optional(),
|
|
15
|
-
hopBoostPerEntity: nonNegativeNumber.optional(),
|
|
16
|
-
hopBoostCap: nonNegativeNumber.optional(),
|
|
17
|
-
/** Hard-capped at 3; values > 3 hard-error so users see the typo. */
|
|
18
|
-
maxHops: positiveInt.max(3).optional(),
|
|
19
|
-
/** Only "blend" is exercised; "off"/"multiply" were never set in practice and were removed. */
|
|
20
|
-
confidenceMode: z.enum(["blend"]).default("blend").optional(),
|
|
21
|
-
/** Range [0, 1]; values > 1 hard-error (no silent clamp). */
|
|
22
|
-
confidenceWeight: z.number().finite().min(0).max(1).default(0.2).optional(),
|
|
23
|
-
})
|
|
24
|
-
.passthrough();
|
|
25
11
|
/**
|
|
26
12
|
* `search.curateRerank` (#951) — an optional cross-encoder rerank pass over
|
|
27
|
-
* `akm curate`'s
|
|
13
|
+
* `akm curate`'s top fused candidates.
|
|
28
14
|
*
|
|
29
15
|
* Deliberately its own small config arm rather than a third member of the
|
|
30
16
|
* `engines` map (`EngineConfigSchema` in ./engines.ts): that union's "llm" /
|
|
@@ -48,15 +34,13 @@ export const CurateRerankConfigSchema = z
|
|
|
48
34
|
model: nonEmptyString.optional(),
|
|
49
35
|
apiKey: symbolicOrWarnApiKey("search.curateRerank.apiKey").optional(),
|
|
50
36
|
timeoutMs: positiveInt.optional(),
|
|
51
|
-
/** How many of
|
|
37
|
+
/** How many of the top fused search candidates curate sends to the reranker. Default 30. */
|
|
52
38
|
topN: positiveInt.max(50).optional(),
|
|
53
39
|
})
|
|
54
|
-
.
|
|
40
|
+
.passthrough();
|
|
55
41
|
export const SearchConfigSchema = z
|
|
56
42
|
.object({
|
|
57
|
-
minScore: nonNegativeNumber.optional(),
|
|
58
43
|
defaultExcludeTypes: z.array(nonEmptyString).optional(),
|
|
59
|
-
graphBoost: SearchGraphBoostSchema.optional(),
|
|
60
44
|
curateRerank: CurateRerankConfigSchema.optional(),
|
|
61
45
|
})
|
|
62
46
|
.passthrough();
|
|
@@ -271,7 +271,6 @@ export function resolveSecretWriteTarget(ref, writeTarget, create) {
|
|
|
271
271
|
*/
|
|
272
272
|
export function withEnvSecretWrite(target, ref, op, paths, mutate) {
|
|
273
273
|
return withWriteTargetMutation(target, paths, {
|
|
274
|
-
ignored: "local-only",
|
|
275
274
|
purpose: `${ref.type}-${op.toLowerCase()}`,
|
|
276
275
|
message: `${op} ${formatRefForMessage({ type: ref.type, name: ref.name, origin: target.source.name })}`,
|
|
277
276
|
}, mutate);
|
package/dist/core/errors.js
CHANGED
|
@@ -11,13 +11,13 @@ const CONFIG_HINTS = {
|
|
|
11
11
|
STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update the default bundle path.",
|
|
12
12
|
DATA_DIR_UNREADABLE: "The data directory is not readable by the user running akm. Check its owner and mode, or point AKM_DATA_DIR / XDG_DATA_HOME somewhere this user owns.",
|
|
13
13
|
INDEX_SCHEMA_INCOMPATIBLE: "Run `akm index --full` to rebuild the derived index from the currently materialized sources.",
|
|
14
|
-
EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
|
|
15
14
|
LLM_NOT_CONFIGURED: 'Run `akm setup` or configure an `engines` entry with `kind: "llm"`, then select it with `defaults.llmEngine`.',
|
|
16
15
|
TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
|
|
17
16
|
UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
|
|
18
17
|
UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
|
|
19
18
|
EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry.",
|
|
20
19
|
SECRET_REFERENCE_UNRESOLVED: "Check the secret exists (`akm secret list`) and the name after `secret://` matches, or run `akm secret set <name> <value>` to store it.",
|
|
20
|
+
REGISTRY_URL_INVALID: "Registry URLs must be credential-free http(s) URLs. Fix the entry with `akm registry list` / `akm registry add`, or the AKM_REGISTRY_URL / AKM_NPM_REGISTRY variable that supplied it.",
|
|
21
21
|
};
|
|
22
22
|
// Code-review finding: COMPOSITION_INVALID covers several unrelated causes
|
|
23
23
|
// (a rejected with:, a multi-job source, a composition cycle/depth/size
|
|
@@ -56,7 +56,7 @@ const USAGE_HINTS = {
|
|
|
56
56
|
//
|
|
57
57
|
// Code-review finding: this default is reached ONLY by with:-rejection
|
|
58
58
|
// throw sites (the ones above, plus task.ts's noDeclaredInputsError and
|
|
59
|
-
//
|
|
59
|
+
// freeze.ts's resolveStep) — every other
|
|
60
60
|
// COMPOSITION_INVALID throw site (multi-job source, composition
|
|
61
61
|
// cycle/depth/size, invalid child-output reference, an env: on a
|
|
62
62
|
// composing step) passes its own explicit constructor hint instead of
|
|
@@ -72,19 +72,17 @@ const USAGE_HINTS = {
|
|
|
72
72
|
WORKFLOW_SOURCE_INVALID: "Run `akm lint` to see the failing source location, or `akm workflow plan <ref>` to compile it without writing.",
|
|
73
73
|
INPUT_BINDING_INVALID: "Check the step's with: keys against the target's declared inputs.",
|
|
74
74
|
TASK_TARGET_UNSUPPORTED: "Task definitions support command, script, workflow, and shell (run:) targets; akm/command is layered by callers.",
|
|
75
|
-
// P3a (docs/plans/specs/p3a-plan-v5-child-freeze.md §3.2, A-N2): the
|
|
76
|
-
// complete-or-abandon policy for a stored pre-irVersion-5 run.
|
|
77
|
-
WORKFLOW_IR_VERSION_UNSUPPORTED: "Abandon the run with `akm workflow abandon <id>`, then start it again from the workflow source — a frozen plan this akm cannot execute is not re-executable in place.",
|
|
78
|
-
// P3b (docs/plans/specs/p3b-child-executor.md §4.3).
|
|
79
|
-
WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes.",
|
|
80
75
|
};
|
|
81
76
|
/** Default hint for each TransientErrorCode. */
|
|
82
77
|
const TRANSIENT_HINTS = {
|
|
83
|
-
RUN_LEASE_HELD: "Wait for the
|
|
78
|
+
RUN_LEASE_HELD: "Wait for the akm process driving this run (the named pid) to finish, then retry.",
|
|
84
79
|
STATE_DB_CONTENDED: "Another akm process is writing state.db right now. Wait a few seconds and retry; commands that support --skip-if-locked can skip instead of failing.",
|
|
85
80
|
INDEX_DB_CONTENDED: "Another akm process is writing index.db; retry shortly, or pass --skip-if-locked on scheduled runs.",
|
|
86
|
-
MAINTENANCE_BARRIER_BUSY: "Another akm process is registering a lock or lease right now. Retry shortly, or pass --skip-if-locked on scheduled index/improve/workflow runs.",
|
|
87
81
|
IMPROVE_LOCK_HELD: "Another akm improve run holds the whole-run lock right now. Wait for it to finish and retry, or pass --skip-if-locked on scheduled runs.",
|
|
82
|
+
LOCKFILE_CONTENDED: "Another akm process is updating its bundle lockfile right now. Wait a few seconds and retry.",
|
|
83
|
+
ASSET_MUTATION_LEASE_HELD: "Another akm process is writing bundle content right now. Wait for it to finish and retry.",
|
|
84
|
+
SCHEDULER_LOCK_HELD: "Another `akm task sync`, `add`, `enable`, `disable` or `prune` is writing the scheduler right now. Wait for it to finish and retry.",
|
|
85
|
+
REGISTRY_UNREACHABLE: "The registry did not answer in time. Check the network and the registry URL (`akm registry list`), then retry.",
|
|
88
86
|
};
|
|
89
87
|
/** Default hint for each NotFoundError code. */
|
|
90
88
|
const NOT_FOUND_HINTS = {
|
|
@@ -97,6 +95,7 @@ const NOT_FOUND_HINTS = {
|
|
|
97
95
|
PROPOSAL_NOT_FOUND: "Run `akm proposal list` to see pending proposals and their ids.",
|
|
98
96
|
FILE_NOT_FOUND: "Check the path exists and is readable.",
|
|
99
97
|
IMPROVE_RUN_NOT_FOUND: "Run `akm improve` first, or `akm improve report --since 30d` to see recent run ids in `runIds`.",
|
|
98
|
+
REGISTRY_NOT_FOUND: "Check the ref's spelling and version; `akm search <query> --from registry` lists installable refs.",
|
|
100
99
|
};
|
|
101
100
|
/**
|
|
102
101
|
* Base class for all akm-thrown, classified errors. Carries the `kind`
|
package/dist/core/file-lock.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* PID-stamped exclusive lock files.
|
|
6
|
+
*
|
|
7
|
+
* A lock is one file created with `O_EXCL` (`wx`), which the filesystem
|
|
8
|
+
* makes atomic: exactly one creator wins, so no further mutex or barrier is
|
|
9
|
+
* needed around acquisition. The payload records the holder's PID (and the
|
|
10
|
+
* launcher PID under a scheduler) so a probe can tell a live holder from a
|
|
11
|
+
* dead one; only a verifiably dead holder — or, when the caller opts in via
|
|
12
|
+
* `staleAfterMs`, an over-age one — is ever reclaimed. Reclaim moves the
|
|
13
|
+
* stale file aside, re-verifies it is the very file that was probed, and only
|
|
14
|
+
* then unlinks it, so two reclaimers cannot both "win" the same stale lock.
|
|
15
|
+
*/
|
|
4
16
|
import { randomUUID } from "node:crypto";
|
|
5
17
|
import fs from "node:fs";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import { sleepSync } from "../runtime.js";
|
|
8
|
-
import { openDatabase } from "../storage/database.js";
|
|
9
18
|
import { isProcessAlive, MAX_LOCK_METADATA_BYTES, readTextFileDescriptorWithLimit } from "./common.js";
|
|
10
19
|
function readLockSnapshot(lockPath) {
|
|
11
20
|
let fd;
|
|
@@ -32,51 +41,16 @@ function readLockSnapshot(lockPath) {
|
|
|
32
41
|
function sameIdentity(left, right) {
|
|
33
42
|
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
34
43
|
}
|
|
35
|
-
function
|
|
36
|
-
// `.sensitive` is an established non-asset suffix across stash walkers. The
|
|
37
|
-
// mutex may sit beside a secret/env lock and must never surface as an asset.
|
|
38
|
-
return path.join(path.dirname(lockPath), `.${path.basename(lockPath)}.operations.sensitive`);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Serialize every mutation of one canonical lock path. SQLite's write lock is
|
|
42
|
-
* released by the OS when a process dies, so this mutex needs no stale-owner
|
|
43
|
-
* deletion protocol (which would reproduce the same check/rename race it is
|
|
44
|
-
* meant to prevent).
|
|
45
|
-
*/
|
|
46
|
-
function withLockOperationMutex(lockPath, run) {
|
|
47
|
-
const db = openDatabase(operationMutexPath(lockPath));
|
|
48
|
-
let began = false;
|
|
44
|
+
function releaseLockRaw(lockPath) {
|
|
49
45
|
try {
|
|
50
|
-
|
|
51
|
-
for (let attempt = 0; attempt < 5 && !began; attempt += 1) {
|
|
52
|
-
db.exec("BEGIN IMMEDIATE");
|
|
53
|
-
began = db.inTransaction;
|
|
54
|
-
if (!began)
|
|
55
|
-
sleepSync(2 ** attempt);
|
|
56
|
-
}
|
|
57
|
-
if (!began)
|
|
58
|
-
throw new Error(`Could not acquire lock operation mutex for ${lockPath}.`);
|
|
59
|
-
const result = run();
|
|
60
|
-
db.exec("COMMIT");
|
|
61
|
-
began = false;
|
|
62
|
-
return result;
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
if (began && db.inTransaction) {
|
|
66
|
-
try {
|
|
67
|
-
db.exec("ROLLBACK");
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
// Preserve the operation failure.
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
throw error;
|
|
46
|
+
fs.unlinkSync(lockPath);
|
|
74
47
|
}
|
|
75
|
-
|
|
76
|
-
|
|
48
|
+
catch {
|
|
49
|
+
// Already gone.
|
|
77
50
|
}
|
|
78
51
|
}
|
|
79
|
-
|
|
52
|
+
/** Create the lock file atomically; `undefined` when another holder already has it. */
|
|
53
|
+
export function tryAcquireLockSync(lockPath, payload) {
|
|
80
54
|
try {
|
|
81
55
|
fs.writeFileSync(lockPath, payload, { flag: "wx" });
|
|
82
56
|
}
|
|
@@ -99,35 +73,6 @@ function tryAcquireLockRaw(lockPath, payload) {
|
|
|
99
73
|
}
|
|
100
74
|
return { lockPath, ...snapshot };
|
|
101
75
|
}
|
|
102
|
-
function releaseLockRaw(lockPath) {
|
|
103
|
-
try {
|
|
104
|
-
fs.unlinkSync(lockPath);
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
// Sentinel already gone — fine.
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Atomically create a sentinel at `lockPath` with `payload` as the body.
|
|
112
|
-
* Returns an exact ownership handle if we now own the lock, or undefined if a sentinel already
|
|
113
|
-
* exists (EEXIST). Throws any other error (permissions, missing parent
|
|
114
|
-
* dir, etc.) — callers must ensure the parent directory exists.
|
|
115
|
-
*
|
|
116
|
-
* `payload` is typically `String(process.pid)` for the simple cases or
|
|
117
|
-
* a small JSON envelope for callers that want richer metadata
|
|
118
|
-
* (improve.ts records pid + startedAt so audit can correlate runs).
|
|
119
|
-
*/
|
|
120
|
-
export function tryAcquireLockSync(lockPath, payload) {
|
|
121
|
-
return withLockOperationMutex(lockPath, () => tryAcquireLockRaw(lockPath, payload));
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Best-effort launcher pid from `AKM_LAUNCHER_PID` (set by
|
|
125
|
-
* `scripts/node-runtime/akm`/`akm-migrate`, #956) — undefined when unset,
|
|
126
|
-
* empty, or not a positive integer (never trust an ambient env var blindly
|
|
127
|
-
* into a lock message). Also the gate the parent-death watchdog
|
|
128
|
-
* (`core/parent-watchdog.ts`) uses to stay inert outside a launcher-managed
|
|
129
|
-
* run.
|
|
130
|
-
*/
|
|
131
76
|
export function launcherPidFromEnv() {
|
|
132
77
|
const raw = process.env.AKM_LAUNCHER_PID;
|
|
133
78
|
if (!raw)
|
|
@@ -135,13 +80,6 @@ export function launcherPidFromEnv() {
|
|
|
135
80
|
const pid = Number.parseInt(raw, 10);
|
|
136
81
|
return Number.isInteger(pid) && pid > 0 ? pid : undefined;
|
|
137
82
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Build a PID-bearing payload with a unique token for one acquisition attempt.
|
|
140
|
-
* Adds `launcherPid` (#956) whenever this process is running under the
|
|
141
|
-
* published launcher, so a lock's holder can be identified by the pid every
|
|
142
|
-
* process listing and task log actually shows (the launcher's) as well as
|
|
143
|
-
* the pid that holds the lock (the bun/node child).
|
|
144
|
-
*/
|
|
145
83
|
export function createLockPayload(metadata = {}) {
|
|
146
84
|
const launcherPid = launcherPidFromEnv();
|
|
147
85
|
return JSON.stringify({
|
|
@@ -151,26 +89,12 @@ export function createLockPayload(metadata = {}) {
|
|
|
151
89
|
lockId: randomUUID(),
|
|
152
90
|
});
|
|
153
91
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Inspect an existing sentinel at `lockPath` without modifying it.
|
|
156
|
-
* Returns:
|
|
157
|
-
* - `absent` if the file does not exist.
|
|
158
|
-
* - `stale` if the file is present but should be reclaimed (the holding
|
|
159
|
-
* PID is dead, the content is unparseable, or the lock has exceeded
|
|
160
|
-
* `staleAfterMs`). Includes the failure reason so callers can log it.
|
|
161
|
-
* - `held` if the lock has a live holder and is not yet age-expired.
|
|
162
|
-
*
|
|
163
|
-
* Does NOT remove the file. Callers decide recovery policy.
|
|
164
|
-
*/
|
|
165
92
|
export function probeLock(lockPath, opts) {
|
|
166
93
|
let snapshot;
|
|
167
94
|
try {
|
|
168
95
|
snapshot = readLockSnapshot(lockPath);
|
|
169
96
|
}
|
|
170
97
|
catch (error) {
|
|
171
|
-
// A permission error means the lock may be genuinely HELD by someone we
|
|
172
|
-
// cannot see. Reporting it as stale would invite a caller to steal a live
|
|
173
|
-
// lease (#791) — `unreadable` stays for the corrupt/undecodable case.
|
|
174
98
|
const code = error?.code;
|
|
175
99
|
if (code === "EACCES" || code === "EPERM")
|
|
176
100
|
return { state: "inaccessible", code };
|
|
@@ -193,102 +117,81 @@ export function probeLock(lockPath, opts) {
|
|
|
193
117
|
return { state: "held", holderPid, launcherPid, ageMs, rawContent, identity };
|
|
194
118
|
}
|
|
195
119
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* has completed.
|
|
120
|
+
* Remove a lock that `probeLock` reported stale. Returns `false` when the file
|
|
121
|
+
* changed since the probe (someone else reclaimed or re-acquired it) so the
|
|
122
|
+
* caller re-probes instead of assuming the path is free.
|
|
200
123
|
*/
|
|
201
124
|
export function reclaimStaleLock(lockPath, probe, options) {
|
|
202
125
|
if (probe.rawContent === undefined || probe.identity === undefined)
|
|
203
126
|
return false;
|
|
204
127
|
const expectedContent = probe.rawContent;
|
|
205
128
|
const expectedIdentity = probe.identity;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
129
|
+
let current;
|
|
130
|
+
try {
|
|
131
|
+
current = readLockSnapshot(lockPath);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (!current || current.rawContent !== expectedContent || !sameIdentity(current.identity, expectedIdentity)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const quarantinePath = `${lockPath}.stale-${process.pid}-${randomUUID()}`;
|
|
140
|
+
try {
|
|
141
|
+
fs.renameSync(lockPath, quarantinePath);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
if (err.code === "ENOENT")
|
|
215
145
|
return false;
|
|
216
|
-
|
|
217
|
-
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
let quarantined;
|
|
149
|
+
try {
|
|
150
|
+
quarantined = readLockSnapshot(quarantinePath);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
quarantined = undefined;
|
|
154
|
+
}
|
|
155
|
+
if (!quarantined ||
|
|
156
|
+
quarantined.rawContent !== expectedContent ||
|
|
157
|
+
!sameIdentity(quarantined.identity, expectedIdentity)) {
|
|
158
|
+
// The file we moved aside is not the one we probed: a fresh holder took
|
|
159
|
+
// the path in between. Put it back and report no reclaim.
|
|
218
160
|
try {
|
|
219
|
-
fs.
|
|
161
|
+
fs.linkSync(quarantinePath, lockPath);
|
|
220
162
|
}
|
|
221
163
|
catch (err) {
|
|
222
|
-
if (err.code
|
|
223
|
-
|
|
224
|
-
throw err;
|
|
164
|
+
if (err.code !== "EEXIST")
|
|
165
|
+
throw err;
|
|
225
166
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
// Restore without replacing a non-cooperating lock installed after quarantine.
|
|
238
|
-
fs.linkSync(quarantinePath, lockPath);
|
|
239
|
-
}
|
|
240
|
-
catch (err) {
|
|
241
|
-
if (err.code !== "EEXIST")
|
|
242
|
-
throw err;
|
|
243
|
-
}
|
|
244
|
-
releaseLockRaw(quarantinePath);
|
|
167
|
+
releaseLockRaw(quarantinePath);
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
options?.afterQuarantineVerified?.();
|
|
171
|
+
try {
|
|
172
|
+
fs.unlinkSync(quarantinePath);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
if (err.code === "ENOENT")
|
|
245
177
|
return false;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
fs.unlinkSync(quarantinePath);
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
catch (err) {
|
|
253
|
-
if (err.code === "ENOENT")
|
|
254
|
-
return false;
|
|
255
|
-
throw err;
|
|
256
|
-
}
|
|
257
|
-
});
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
258
180
|
}
|
|
259
|
-
/**
|
|
260
|
-
* Release only the exact sentinel returned by `tryAcquireLockSync`. Content and
|
|
261
|
-
* file identity are revalidated while holding the acquisition operation mutex,
|
|
262
|
-
* so a stale holder cannot remove a successor. Synchronous and idempotent so it
|
|
263
|
-
* is safe in both `finally` blocks and process exit handlers.
|
|
264
|
-
*/
|
|
181
|
+
/** Unlink the lock only while it is still the exact file this owner created. */
|
|
265
182
|
export function releaseLock(ownership) {
|
|
266
183
|
const { lockPath } = ownership;
|
|
267
|
-
|
|
184
|
+
let current;
|
|
185
|
+
try {
|
|
186
|
+
current = readLockSnapshot(lockPath);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
268
189
|
return;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
catch {
|
|
275
|
-
// Absent or unreadable — nothing of ours to release.
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
|
|
279
|
-
releaseLockRaw(lockPath);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
190
|
+
}
|
|
191
|
+
if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
|
|
192
|
+
releaseLockRaw(lockPath);
|
|
193
|
+
}
|
|
282
194
|
}
|
|
283
|
-
/**
|
|
284
|
-
* Extract a holder pid, and (#956) a launcher pid when the payload recorded
|
|
285
|
-
* one, from a sentinel body. Accepts the two shapes used across the
|
|
286
|
-
* codebase: a bare numeric string (config-io, vault, lockfile — never
|
|
287
|
-
* carries a `launcherPid`) and a JSON object with `pid`/`launcherPid` fields
|
|
288
|
-
* (`createLockPayload`). `holderPid` is undefined when the body is
|
|
289
|
-
* unparseable or yields a non-positive integer; `launcherPid` is undefined
|
|
290
|
-
* whenever the payload has none, independent of whether `holderPid` parsed.
|
|
291
|
-
*/
|
|
292
195
|
function extractLockIdentity(content) {
|
|
293
196
|
const trimmed = content.trim();
|
|
294
197
|
if (!trimmed)
|
package/dist/core/logs-db.js
CHANGED
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
* ## Schema evolution
|
|
34
34
|
*
|
|
35
35
|
* Same migration-safety contract as state.db: append-only `MIGRATIONS` applied
|
|
36
|
-
* through the shared runner in src/storage/
|
|
36
|
+
* through the shared runner in src/storage/sqlite-migrations.ts.
|
|
37
37
|
*
|
|
38
38
|
* @module logs-db
|
|
39
39
|
*/
|
|
40
40
|
import path from "node:path";
|
|
41
|
-
import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/engines/sqlite-migrations.js";
|
|
42
41
|
import { openManagedDatabase } from "../storage/managed-db.js";
|
|
42
|
+
import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/sqlite-migrations.js";
|
|
43
43
|
import { getDataDir } from "./paths.js";
|
|
44
44
|
// ── Path helper ──────────────────────────────────────────────────────────────
|
|
45
45
|
/**
|
package/dist/core/paths.js
CHANGED
|
@@ -245,9 +245,6 @@ export function getIndexWriterLockPath() {
|
|
|
245
245
|
export function getIndexRebuildLockPath() {
|
|
246
246
|
return path.join(getDataDir(), "index.rebuild.lock");
|
|
247
247
|
}
|
|
248
|
-
export function getMaintenanceBarrierPath() {
|
|
249
|
-
return path.join(getDataDir(), "maintenance.barrier.lock");
|
|
250
|
-
}
|
|
251
248
|
/** Path to the state.db file in $DATA. */
|
|
252
249
|
export function getStateDbPathInDataDir() {
|
|
253
250
|
return path.join(getDataDir(), "state.db");
|
|
@@ -339,30 +336,6 @@ export function getStashStateKey(stashDir) {
|
|
|
339
336
|
function stashScopedDir(base, stashDir) {
|
|
340
337
|
return path.join(base, getStashStateKey(stashDir));
|
|
341
338
|
}
|
|
342
|
-
/**
|
|
343
|
-
* `$STATE/improve/distill-rejected/<stash>/` — lessons that failed the
|
|
344
|
-
* distill quality gate. Moved out of `$STASH/.akm/distill-rejected/`
|
|
345
|
-
* (itlackey/akm#890): nothing reads it to resolve bundle content, so it does
|
|
346
|
-
* not meet the "must travel with the content" rule.
|
|
347
|
-
*/
|
|
348
|
-
export function getDistillRejectedDir(stashDir) {
|
|
349
|
-
return stashScopedDir(path.join(getStateDir(), "improve", "distill-rejected"), stashDir);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* `$STATE/improve/eval-cases/<stash>/` — regression eval cases captured from
|
|
353
|
-
* rejected distill/proposal output. Moved out of `$STASH/.akm/eval-cases/`
|
|
354
|
-
* (itlackey/akm#890).
|
|
355
|
-
*
|
|
356
|
-
* R10: the writer (`src/commands/improve/eval-cases.ts`) was removed —
|
|
357
|
-
* nothing ever read the files it wrote, and a rejected proposal row now
|
|
358
|
-
* carries the same information (see `quality-gate.ts`'s
|
|
359
|
-
* `writeQualityRejection`). This resolver stays: `scripts/akm-migrate/migrate/
|
|
360
|
-
* writer-relocation.ts` still uses it to relocate pre-existing eval-case
|
|
361
|
-
* files an older release wrote to the legacy `$STASH/.akm/eval-cases/` path.
|
|
362
|
-
*/
|
|
363
|
-
export function getEvalCasesDir(stashDir) {
|
|
364
|
-
return stashScopedDir(path.join(getStateDir(), "improve", "eval-cases"), stashDir);
|
|
365
|
-
}
|
|
366
339
|
/**
|
|
367
340
|
* `$STATE/improve/measurement/verdicts/<stash>/` — `akm-eval-proactive-verdict`
|
|
368
341
|
* reports. Moved out of `$STASH/.akm/measurement/verdicts/` (itlackey/akm#890);
|