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
|
@@ -7,7 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
8
8
|
import { resolveStashDir } from "../core/common.js";
|
|
9
9
|
import { ConfigError } from "../core/errors.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getTaskContextDir } from "../core/paths.js";
|
|
11
11
|
import { INPUT_NAME_PATTERN } from "../execution/input-contract.js";
|
|
12
12
|
import { normaliseTaskConceptId } from "./task-id.js";
|
|
13
13
|
export const SCHEDULED_TASK_CONTEXT_KEYS = [
|
|
@@ -17,6 +17,17 @@ export const SCHEDULED_TASK_CONTEXT_KEYS = [
|
|
|
17
17
|
"AKM_CACHE_DIR",
|
|
18
18
|
"AKM_STATE_DIR",
|
|
19
19
|
];
|
|
20
|
+
/**
|
|
21
|
+
* Directories a descriptor carries ONLY when the process that ran `task sync`
|
|
22
|
+
* had them set explicitly in its environment. They are never resolved from
|
|
23
|
+
* defaults: a descriptor written from inside an app whose environment pointed
|
|
24
|
+
* `$STATE` somewhere private (an OpenCode desktop session, 2026-08 → 2026-09)
|
|
25
|
+
* froze that directory into eight cron rows, and the scheduled improve runs
|
|
26
|
+
* then held their locks in a `locks/` directory no interactive command could
|
|
27
|
+
* see. At fire time an absent key resolves exactly as it does for an
|
|
28
|
+
* interactive command on the same host.
|
|
29
|
+
*/
|
|
30
|
+
const EXPLICIT_CONTEXT_KEYS = ["AKM_CONFIG_DIR", "AKM_DATA_DIR", "AKM_CACHE_DIR", "AKM_STATE_DIR"];
|
|
20
31
|
/**
|
|
21
32
|
* The AKM directory context currently restored from a scheduler descriptor.
|
|
22
33
|
* Child environments that are built from an allowlist must forward this
|
|
@@ -32,16 +43,20 @@ export function scheduledTaskContextEnv(env = process.env) {
|
|
|
32
43
|
return out;
|
|
33
44
|
}
|
|
34
45
|
export const SCHEDULER_CONTEXT_ARG = "--scheduler-context";
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The directory context a scheduler descriptor carries: the resolved bundle
|
|
48
|
+
* path, plus whichever `AKM_*_DIR` overrides the syncing process had set
|
|
49
|
+
* explicitly. Resolved defaults are deliberately not captured — see
|
|
50
|
+
* {@link EXPLICIT_CONTEXT_KEYS}.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveScheduledTaskContext(env = process.env) {
|
|
53
|
+
const context = { AKM_BUNDLE_DIR: path.resolve(resolveStashDir(env)) };
|
|
54
|
+
for (const key of EXPLICIT_CONTEXT_KEYS) {
|
|
55
|
+
const value = env[key]?.trim();
|
|
56
|
+
if (value)
|
|
57
|
+
context[key] = path.resolve(value);
|
|
58
|
+
}
|
|
59
|
+
return canonicalContext(context);
|
|
45
60
|
}
|
|
46
61
|
/** Build an installed argv from one already-validated public scheduler tail. */
|
|
47
62
|
export function buildScheduledBindingInvocation(akmArgv, contextPath, invocation) {
|
|
@@ -52,16 +67,15 @@ export function buildScheduledBindingInvocation(akmArgv, contextPath, invocation
|
|
|
52
67
|
argv: [...akmArgv, SCHEDULER_CONTEXT_ARG, assertAbsolutePath(contextPath), ...parsed.invocation],
|
|
53
68
|
};
|
|
54
69
|
}
|
|
55
|
-
export function schedulerContextDescriptor(context = resolveScheduledTaskContext()
|
|
56
|
-
return {
|
|
57
|
-
version: 1,
|
|
58
|
-
environment: { ...canonicalContext(context), PATH: validatePathValue(envPath) },
|
|
59
|
-
};
|
|
70
|
+
export function schedulerContextDescriptor(context = resolveScheduledTaskContext()) {
|
|
71
|
+
return { version: 1, environment: canonicalContext(context) };
|
|
60
72
|
}
|
|
61
73
|
export function schedulerContextPath(descriptor) {
|
|
62
74
|
const bytes = serializeDescriptor(descriptor);
|
|
63
75
|
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
64
|
-
|
|
76
|
+
// The descriptor lives under the data directory it names when it names
|
|
77
|
+
// one, otherwise under this process's own.
|
|
78
|
+
return path.join(getTaskContextDir({ ...process.env, ...descriptor.environment }), `${digest}.json`);
|
|
65
79
|
}
|
|
66
80
|
/** Write a content-addressed descriptor without ever replacing existing content. */
|
|
67
81
|
export function writeSchedulerContextDescriptor(descriptor = schedulerContextDescriptor()) {
|
|
@@ -96,9 +110,13 @@ export function writeSchedulerContextDescriptor(descriptor = schedulerContextDes
|
|
|
96
110
|
}
|
|
97
111
|
export function loadSchedulerContextDescriptor(file, env = process.env) {
|
|
98
112
|
const descriptor = validateSchedulerContextDescriptor(file);
|
|
99
|
-
for (const key of SCHEDULED_TASK_CONTEXT_KEYS)
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
for (const key of SCHEDULED_TASK_CONTEXT_KEYS) {
|
|
114
|
+
const value = descriptor.environment[key];
|
|
115
|
+
if (value !== undefined)
|
|
116
|
+
env[key] = value;
|
|
117
|
+
}
|
|
118
|
+
if (descriptor.environment.PATH !== undefined)
|
|
119
|
+
env.PATH = descriptor.environment.PATH;
|
|
102
120
|
}
|
|
103
121
|
export function validateSchedulerContextDescriptor(file) {
|
|
104
122
|
const absolute = assertAbsolutePath(file);
|
|
@@ -291,14 +309,17 @@ function isValidSchedulerInputFlagTail(tail) {
|
|
|
291
309
|
return true;
|
|
292
310
|
}
|
|
293
311
|
function canonicalContext(input) {
|
|
294
|
-
|
|
295
|
-
if (inputKeys.length !== SCHEDULED_TASK_CONTEXT_KEYS.length ||
|
|
296
|
-
inputKeys.some((key) => !SCHEDULED_TASK_CONTEXT_KEYS.includes(key))) {
|
|
312
|
+
if (Object.keys(input).some((key) => !SCHEDULED_TASK_CONTEXT_KEYS.includes(key))) {
|
|
297
313
|
throw invalidSchedulerContext();
|
|
298
314
|
}
|
|
299
315
|
const context = {};
|
|
300
316
|
for (const key of SCHEDULED_TASK_CONTEXT_KEYS) {
|
|
301
317
|
const value = input[key];
|
|
318
|
+
if (value === undefined) {
|
|
319
|
+
if (key === "AKM_BUNDLE_DIR")
|
|
320
|
+
throw invalidSchedulerContext();
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
302
323
|
if (typeof value !== "string" ||
|
|
303
324
|
value.trim().length === 0 ||
|
|
304
325
|
containsControlCharacter(value) ||
|
|
@@ -319,12 +340,12 @@ function canonicalDescriptor(input) {
|
|
|
319
340
|
if (typeof rawEnvironment !== "object" || rawEnvironment === null || Array.isArray(rawEnvironment)) {
|
|
320
341
|
throw invalidSchedulerContext();
|
|
321
342
|
}
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
343
|
+
const { PATH, ...rawContext } = rawEnvironment;
|
|
344
|
+
const context = canonicalContext(rawContext);
|
|
345
|
+
return {
|
|
346
|
+
version: 1,
|
|
347
|
+
environment: PATH === undefined ? context : { ...context, PATH: validatePathValue(PATH) },
|
|
348
|
+
};
|
|
328
349
|
}
|
|
329
350
|
function serializeDescriptor(descriptor) {
|
|
330
351
|
return `${JSON.stringify(canonicalDescriptor(descriptor))}\n`;
|
|
@@ -365,30 +386,9 @@ function containsControlCharacter(value) {
|
|
|
365
386
|
}
|
|
366
387
|
return false;
|
|
367
388
|
}
|
|
368
|
-
function resolveStateDir(env, platform) {
|
|
369
|
-
const override = env.AKM_STATE_DIR?.trim();
|
|
370
|
-
if (override)
|
|
371
|
-
return override;
|
|
372
|
-
if (platform === "win32") {
|
|
373
|
-
const localAppData = env.LOCALAPPDATA?.trim();
|
|
374
|
-
if (localAppData)
|
|
375
|
-
return path.join(localAppData, "akm", "state");
|
|
376
|
-
const userProfile = env.USERPROFILE?.trim();
|
|
377
|
-
if (userProfile)
|
|
378
|
-
return path.join(userProfile, "AppData", "Local", "akm", "state");
|
|
379
|
-
const appData = env.APPDATA?.trim();
|
|
380
|
-
if (appData)
|
|
381
|
-
return path.join(appData, "..", "Local", "akm", "state");
|
|
382
|
-
throw new ConfigError("Unable to determine state directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
383
|
-
}
|
|
384
|
-
const xdgStateHome = env.XDG_STATE_HOME?.trim();
|
|
385
|
-
if (xdgStateHome)
|
|
386
|
-
return path.join(xdgStateHome, "akm");
|
|
387
|
-
const home = env.HOME?.trim();
|
|
388
|
-
return home ? path.join(home, ".local", "state", "akm") : path.join("/tmp", "akm-state");
|
|
389
|
-
}
|
|
390
389
|
function invalidSchedulerContext() {
|
|
391
|
-
return new ConfigError(
|
|
390
|
+
return new ConfigError("Invalid scheduler context; expected AKM_BUNDLE_DIR as an absolute path, " +
|
|
391
|
+
`optionally with ${EXPLICIT_CONTEXT_KEYS.join(", ")} as absolute paths.`, "INVALID_CONFIG_FILE");
|
|
392
392
|
}
|
|
393
393
|
function invalidSchedulerInvocation() {
|
|
394
394
|
return new ConfigError("Invalid scheduler invocation; expected public " +
|
|
@@ -0,0 +1,53 @@
|
|
|
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 one process lock around native scheduler writes.
|
|
6
|
+
*
|
|
7
|
+
* `task sync|add|enable|disable|prune --yes` read the installed rows, plan,
|
|
8
|
+
* and apply under it, so two akm processes never interleave their writes to
|
|
9
|
+
* the same crontab or LaunchAgents directory. It is an `O_EXCL` lock file
|
|
10
|
+
* under `$STATE/locks`, reclaimed only from a verifiably dead holder, and
|
|
11
|
+
* re-entrant within one process (`add` runs `sync` inside it).
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { TransientError } from "../core/errors.js";
|
|
16
|
+
import { createLockPayload, probeLock, reclaimStaleLock, releaseLock, tryAcquireLockSync } from "../core/file-lock.js";
|
|
17
|
+
import { getStateDir } from "../core/paths.js";
|
|
18
|
+
export function schedulerLockPath() {
|
|
19
|
+
return path.join(getStateDir(), "locks", "scheduler.lock");
|
|
20
|
+
}
|
|
21
|
+
let depth = 0;
|
|
22
|
+
export async function withSchedulerLock(fn) {
|
|
23
|
+
if (depth > 0) {
|
|
24
|
+
depth += 1;
|
|
25
|
+
try {
|
|
26
|
+
return await fn();
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
depth -= 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const lockPath = schedulerLockPath();
|
|
33
|
+
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
34
|
+
const acquire = () => tryAcquireLockSync(lockPath, createLockPayload({ purpose: "scheduler" }));
|
|
35
|
+
let ownership = acquire();
|
|
36
|
+
if (!ownership) {
|
|
37
|
+
const probe = probeLock(lockPath);
|
|
38
|
+
if (probe.state === "absent" || (probe.state === "stale" && reclaimStaleLock(lockPath, probe))) {
|
|
39
|
+
ownership = acquire();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!ownership) {
|
|
43
|
+
throw new TransientError("Another akm process is syncing the scheduler right now.", "SCHEDULER_LOCK_HELD");
|
|
44
|
+
}
|
|
45
|
+
depth = 1;
|
|
46
|
+
try {
|
|
47
|
+
return await fn();
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
depth = 0;
|
|
51
|
+
releaseLock(ownership);
|
|
52
|
+
}
|
|
53
|
+
}
|