akm-cli 0.9.0-rc.0 → 0.9.0-rc.13
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 +1283 -22
- package/README.md +62 -37
- package/SECURITY.md +46 -31
- package/dist/akm +162 -38
- package/dist/akm-migrate +44 -0
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/hints/cli-hints-full.md +268 -118
- package/dist/assets/hints/cli-hints-short.md +87 -24
- package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
- package/dist/assets/improve-strategies/frequent.json +15 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
- package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
- package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
- package/dist/assets/improve-strategies/reflect-distill.json +30 -0
- package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +5 -5
- package/dist/assets/prompts/extract-session.md +2 -6
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
- package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
- package/dist/assets/prompts/reflect-output-repair.md +3 -0
- package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
- package/dist/assets/stash-skeleton/README.md +38 -10
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
- package/dist/assets/tasks/core/extract.yml +3 -2
- package/dist/assets/tasks/core/improve.yml +2 -1
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +2 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
- package/dist/assets/templates/html/health.html +5 -4
- package/dist/assets/workflows/workflow-template.md +31 -15
- package/dist/cli/invocation.js +279 -0
- package/dist/cli/parse-args.js +5 -90
- package/dist/cli/retired-commands.js +78 -0
- package/dist/cli/shared.js +158 -48
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +747 -293
- package/dist/commands/agent/agent-dispatch.js +19 -18
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +43 -97
- package/dist/commands/completions.js +80 -23
- package/dist/commands/config-cli.js +44 -281
- package/dist/commands/env/env-binding.js +99 -0
- package/dist/commands/env/env-cli.js +84 -224
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +45 -61
- package/dist/commands/env/secret.js +32 -62
- package/dist/commands/feedback-cli.js +179 -85
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +7 -8
- package/dist/commands/health/checks.js +279 -94
- package/dist/commands/health/html-report.js +197 -578
- package/dist/commands/health/improve-metrics.js +277 -246
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +16 -7
- package/dist/commands/health/metrics.js +67 -32
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +508 -0
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +16 -56
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
- package/dist/commands/health/types-improve.js +29 -0
- package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
- package/dist/commands/health/types-result.js +7 -0
- package/dist/commands/health/types-runs.js +4 -0
- package/dist/commands/health/types-session-log.js +4 -0
- package/dist/commands/health/types-windows.js +4 -0
- package/dist/commands/health/types.js +26 -21
- package/dist/commands/health/windows.js +2 -3
- package/dist/commands/health.js +296 -167
- package/dist/commands/improve/anti-collapse.js +5 -5
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +65 -52
- package/dist/commands/improve/consolidate/chunking.js +9 -7
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +454 -1354
- package/dist/commands/improve/content-hash.js +39 -0
- package/dist/commands/improve/distill/content-repair.js +4 -10
- package/dist/commands/improve/distill/promote-memory.js +89 -64
- package/dist/commands/improve/distill/quality-gate.js +118 -42
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +33 -888
- package/dist/commands/improve/distill.js +607 -363
- package/dist/commands/improve/eligibility.js +165 -79
- package/dist/commands/improve/extract-cli.js +35 -126
- package/dist/commands/improve/extract-prompt.js +6 -35
- package/dist/commands/improve/extract.js +640 -391
- package/dist/commands/improve/feedback-valence.js +2 -12
- package/dist/commands/improve/improve-cli.js +134 -135
- package/dist/commands/improve/improve-result-file.js +30 -50
- package/dist/commands/improve/improve-run-types.js +4 -0
- package/dist/commands/improve/improve-strategies.js +135 -0
- package/dist/commands/improve/improve.js +904 -701
- package/dist/commands/improve/locks.js +64 -111
- package/dist/commands/improve/loop-stages.js +1110 -923
- package/dist/commands/improve/memory/derived-ref.js +124 -0
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
- package/dist/commands/improve/memory/memory-improve.js +25 -37
- package/dist/commands/improve/outcome-loop.js +25 -88
- package/dist/commands/improve/preparation.js +1034 -813
- package/dist/commands/improve/proactive-maintenance.js +34 -9
- package/dist/commands/improve/proposal-envelope.js +31 -0
- package/dist/commands/improve/reflect.js +983 -794
- package/dist/commands/improve/run-context.js +119 -0
- package/dist/commands/improve/salience.js +24 -127
- package/dist/commands/improve/session-asset.js +7 -3
- package/dist/commands/improve/shared.js +14 -34
- package/dist/commands/improve/source-identity.js +28 -0
- package/dist/commands/improve/triage.js +20 -17
- package/dist/commands/lint/base-linter.js +340 -313
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +185 -30
- package/dist/commands/{events.js → log.js} +28 -38
- package/dist/commands/migrate-cli.js +54 -0
- package/dist/commands/migration-tool.js +55 -0
- package/dist/commands/observability-cli.js +70 -208
- package/dist/commands/proposal/diff-format.js +50 -0
- package/dist/commands/proposal/drain-policies.js +0 -6
- package/dist/commands/proposal/drain.js +91 -40
- package/dist/commands/proposal/proposal-cli.js +134 -132
- package/dist/commands/proposal/proposal-types.js +56 -0
- package/dist/commands/proposal/proposal.js +83 -65
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +105 -88
- package/dist/commands/proposal/repository.js +1303 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
- package/dist/commands/proposal/validators/proposal-validators.js +61 -12
- package/dist/commands/proposal/validators/proposals.js +6 -8
- package/dist/commands/read/curate.js +78 -73
- package/dist/commands/read/knowledge.js +510 -13
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +84 -15
- package/dist/commands/read/search-cli.js +203 -96
- package/dist/commands/read/search.js +126 -94
- package/dist/commands/read/show.js +226 -250
- package/dist/commands/registry-cli.js +34 -60
- package/dist/commands/remember.js +18 -57
- package/dist/commands/sources/add-cli.js +104 -49
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +63 -0
- package/dist/commands/sources/info.js +27 -15
- package/dist/commands/sources/init.js +30 -40
- package/dist/commands/sources/installed-stashes.js +469 -172
- package/dist/commands/sources/migration-help.js +7 -4
- package/dist/commands/sources/schema-repair.js +10 -9
- package/dist/commands/sources/self-update.js +182 -121
- package/dist/commands/sources/source-add.js +169 -178
- package/dist/commands/sources/source-clone.js +144 -41
- package/dist/commands/sources/source-manage.js +94 -59
- package/dist/commands/sources/sources-cli.js +64 -205
- package/dist/commands/sources/stash-cli.js +91 -54
- package/dist/commands/sources/stash-skeleton.js +1 -1
- package/dist/commands/tasks/tasks-cli.js +106 -104
- package/dist/commands/tasks/tasks.js +445 -262
- package/dist/commands/workflow-cli.js +232 -121
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/activation-policy.js +49 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
- package/dist/core/adapter/adapters/akm-adapter.js +528 -0
- package/dist/core/adapter/adapters/akm-lint.js +392 -0
- package/dist/core/adapter/adapters/akm-metadata.js +387 -0
- package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
- package/dist/core/adapter/adapters/claude-adapter.js +61 -0
- package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
- package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
- package/dist/core/adapter/adapters/index.js +80 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
- package/dist/core/adapter/adapters/okf-adapter.js +391 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
- package/dist/core/adapter/adapters/shared.js +286 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
- package/dist/core/adapter/bundle-adapter.js +4 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +44 -0
- package/dist/core/adapter/registry.js +56 -0
- package/dist/core/adapter/types.js +4 -0
- package/dist/core/asset/akm-markdown.js +30 -0
- package/dist/core/asset/asset-placement.js +243 -0
- package/dist/core/asset/asset-ref.js +110 -79
- package/dist/core/asset/asset-serialize.js +20 -0
- package/dist/core/asset/frontmatter.js +28 -12
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +274 -0
- package/dist/core/asset/stash-meta.js +2 -2
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +281 -86
- package/dist/core/config/config-io.js +42 -128
- package/dist/core/config/config-schema.js +233 -834
- package/dist/core/config/config-sources.js +162 -39
- package/dist/core/config/config-types.js +16 -11
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +126 -37
- package/dist/core/config/config.js +154 -331
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +28 -0
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +38 -0
- package/dist/core/config/schema/engines.js +116 -0
- package/dist/core/config/schema/experimental.js +47 -0
- package/dist/core/config/schema/feedback.js +31 -0
- package/dist/core/config/schema/improve-processes.js +389 -0
- package/dist/core/config/schema/improve.js +94 -0
- package/dist/core/config/schema/index-config.js +176 -0
- package/dist/core/config/schema/output.js +18 -0
- package/dist/core/config/schema/primitives.js +94 -0
- package/dist/core/config/schema/search.js +30 -0
- package/dist/core/config/schema/setup.js +18 -0
- package/dist/core/config/schema/sources-bundles.js +169 -0
- package/dist/core/config/schema/workflow.js +29 -0
- package/dist/core/env-secret-ref.js +155 -20
- package/dist/core/errors.js +17 -15
- package/dist/core/events-types.js +4 -0
- package/dist/core/events.js +46 -128
- package/dist/core/extra-params.js +62 -0
- package/dist/core/file-change.js +17 -0
- package/dist/core/file-lock.js +202 -57
- package/dist/core/fs-txn.js +392 -0
- package/dist/core/git-message.js +59 -0
- package/dist/core/improve-result.js +167 -0
- package/dist/core/json-schema.js +142 -0
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +1 -1
- package/dist/core/maintenance-barrier.js +135 -0
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/paths.js +22 -25
- package/dist/core/platform.js +10 -0
- package/dist/core/recognition-util.js +128 -0
- package/dist/core/redaction.js +392 -0
- package/dist/core/standards/resolve-standards-context.js +36 -65
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +5 -5
- package/dist/core/state/migrations.js +242 -11
- package/dist/core/state-db.js +98 -10
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +303 -0
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/time.js +20 -0
- package/dist/core/type-presentation.js +130 -0
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +834 -118
- package/dist/indexer/bundle-identity-guard.js +92 -0
- package/dist/indexer/db/graph-db.js +1 -25
- package/dist/indexer/db/llm-cache.js +1 -1
- package/dist/indexer/ensure-index.js +30 -9
- package/dist/indexer/graph/graph-boost.js +9 -30
- package/dist/indexer/graph/graph-extraction.js +41 -27
- package/dist/indexer/graph/graph-types.js +4 -0
- package/dist/indexer/index-writer-lock.js +93 -49
- package/dist/indexer/index-written-assets.js +100 -53
- package/dist/indexer/indexer.js +746 -329
- package/dist/indexer/init.js +18 -25
- package/dist/indexer/installations.js +142 -0
- package/dist/indexer/passes/dir-staleness.js +18 -10
- package/dist/indexer/passes/memory-inference.js +25 -15
- package/dist/indexer/passes/metadata.js +412 -243
- package/dist/indexer/scan/doc-to-entry.js +160 -0
- package/dist/indexer/scan/drain-dir.js +134 -0
- package/dist/indexer/search/db-search.js +292 -108
- package/dist/indexer/search/fts-query.js +64 -0
- package/dist/indexer/search/ranking-contributors.js +145 -25
- package/dist/indexer/search/ranking-types.js +4 -0
- package/dist/indexer/search/ranking.js +28 -71
- package/dist/indexer/search/search-attribution.js +67 -0
- package/dist/indexer/search/search-fields.js +18 -3
- package/dist/indexer/search/search-hit-enrichers.js +30 -40
- package/dist/indexer/search/search-source.js +157 -111
- package/dist/indexer/search/semantic-status.js +4 -1
- package/dist/indexer/usage/usage-events.js +10 -30
- package/dist/indexer/walk/file-context.js +3 -45
- package/dist/indexer/walk/matchers.js +42 -34
- package/dist/indexer/walk/path-resolver.js +11 -5
- package/dist/indexer/walk/walker.js +42 -14
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -56
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +231 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +16 -2
- package/dist/integrations/agent/profiles.js +36 -62
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +93 -4
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +88 -196
- package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
- package/dist/integrations/harnesses/aider/index.js +48 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
- package/dist/integrations/harnesses/amazonq/index.js +45 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +24 -35
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
- package/dist/integrations/harnesses/codex/index.js +52 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
- package/dist/integrations/harnesses/copilot/index.js +48 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
- package/dist/integrations/harnesses/gemini/index.js +48 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +54 -34
- package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
- package/dist/integrations/harnesses/opencode/config-import.js +1 -3
- package/dist/integrations/harnesses/opencode/index.js +14 -32
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
- package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
- package/dist/integrations/harnesses/openhands/index.js +48 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
- package/dist/integrations/harnesses/pi/index.js +45 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +43 -32
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +36 -39
- package/dist/integrations/session-logs/provider-base.js +113 -0
- package/dist/llm/client.js +182 -110
- package/dist/llm/embedders/deterministic.js +2 -2
- package/dist/llm/embedders/remote.js +21 -9
- package/dist/llm/feature-gate.js +17 -57
- package/dist/llm/graph-extract.js +12 -13
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +45 -30
- package/dist/llm/structured-call.js +16 -8
- package/dist/llm/usage-persist.js +30 -5
- package/dist/llm/usage-telemetry.js +59 -6
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/command-registry.js +27 -0
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +251 -0
- package/dist/output/html-render.js +11 -16
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -279
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +58 -84
- package/dist/output/shapes/passthrough.js +11 -39
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes/registry.js +12 -6
- package/dist/output/shapes.js +0 -9
- package/dist/output/text/{init.js → bundle-create.js} +3 -1
- package/dist/output/text/bundle-show.js +7 -0
- package/dist/output/text/command-format.js +562 -0
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/helpers.js +15 -1164
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +202 -0
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/registry.js +12 -6
- package/dist/output/text/show-directives.js +117 -0
- package/dist/output/text/show-format.js +103 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +332 -0
- package/dist/output/text/workflow.js +3 -2
- package/dist/output/text.js +10 -19
- package/dist/registry/factory.js +4 -6
- package/dist/registry/origin-resolve.js +16 -27
- package/dist/registry/providers/skills-sh.js +3 -3
- package/dist/registry/providers/static-index.js +15 -25
- package/dist/registry/resolve.js +43 -94
- package/dist/registry/semver.js +43 -0
- package/dist/runtime.js +81 -12
- package/dist/scripts/akm-migrate.js +35529 -0
- package/dist/setup/detect.js +5 -7
- package/dist/setup/detected-engines.js +136 -0
- package/dist/setup/engine-config.js +100 -0
- package/dist/setup/registry-stash-loader.js +3 -3
- package/dist/setup/semantic-assets.js +12 -9
- package/dist/setup/setup.js +444 -208
- package/dist/setup/steps/connection-shared.js +120 -0
- package/dist/setup/steps/connection.js +108 -305
- package/dist/setup/steps/platforms.js +13 -12
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +21 -15
- package/dist/setup/steps/stashdir.js +6 -4
- package/dist/setup/steps/tasks.js +236 -119
- package/dist/setup/steps.js +3 -2
- package/dist/sources/freshness.js +39 -0
- package/dist/sources/provider-factory.js +11 -17
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +278 -34
- package/dist/sources/providers/git-provider.js +54 -56
- package/dist/sources/providers/git-stash.js +420 -91
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +47 -22
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +11 -10
- package/dist/sources/snapshot-fetchers/types.js +4 -0
- package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
- package/dist/storage/database.js +60 -4
- package/dist/storage/engines/sqlite-migrations.js +156 -5
- package/dist/storage/locations.js +1 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +51 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -32
- package/dist/storage/repositories/index-connection.js +79 -0
- package/dist/storage/repositories/index-db.js +4 -3
- package/dist/storage/repositories/index-entries-repository.js +863 -0
- package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
- package/dist/storage/repositories/index-entry-types.js +4 -0
- package/dist/storage/repositories/index-fts-repository.js +167 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
- package/dist/storage/repositories/index-meta-repository.js +49 -0
- package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
- package/dist/storage/repositories/index-sql.js +12 -0
- package/dist/storage/repositories/index-utility-repository.js +356 -0
- package/dist/storage/repositories/index-vec-repository.js +250 -0
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +317 -75
- package/dist/storage/repositories/registry-cache.js +1 -1
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +110 -3
- package/dist/storage/repositories/workflow-runs-repository.js +240 -19
- package/dist/tasks/backends/cron.js +169 -46
- package/dist/tasks/backends/exec-utils.js +76 -3
- package/dist/tasks/backends/index.js +6 -9
- package/dist/tasks/backends/launchd.js +292 -55
- package/dist/tasks/backends/schtasks.js +557 -70
- package/dist/tasks/backends/types.js +4 -0
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +56 -38
- package/dist/tasks/parser.js +156 -64
- package/dist/tasks/resolve-akm-bin.js +144 -51
- package/dist/tasks/runner.js +377 -209
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +296 -0
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/task-id.js +35 -0
- package/dist/tasks/validator.js +30 -16
- package/dist/text-import-hook.mjs +1 -1
- package/dist/workflows/authoring/authoring.js +104 -43
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -16
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +450 -0
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +1038 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1460 -0
- package/dist/workflows/exec/run-workflow.js +602 -0
- package/dist/workflows/exec/scheduler.js +71 -0
- package/dist/workflows/exec/step-work.js +1190 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +246 -0
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +68 -0
- package/dist/workflows/ir/schema.js +540 -0
- package/dist/workflows/parser.js +878 -304
- package/dist/workflows/program/expressions.js +181 -0
- package/dist/workflows/program/schema.js +51 -0
- package/dist/workflows/renderer.js +100 -45
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +376 -119
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +2 -3
- package/dist/workflows/validator.js +52 -30
- package/docs/README.md +42 -78
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +9 -8
- package/docs/migration/release-notes/0.9.0.md +158 -14
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +844 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/data-and-telemetry.md +333 -0
- package/package.json +21 -17
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +4636 -0
- package/schemas/akm-task.json +87 -0
- package/schemas/akm-workflow.json +373 -0
- package/dist/akm-migrate-storage +0 -38
- package/dist/assets/help/help-accept.md +0 -12
- package/dist/assets/help/help-improve.md +0 -84
- package/dist/assets/help/help-proposals.md +0 -17
- package/dist/assets/help/help-propose.md +0 -17
- package/dist/assets/help/help-reject.md +0 -11
- package/dist/assets/profiles/frequent.json +0 -13
- package/dist/assets/profiles/recombine-only.json +0 -21
- package/dist/assets/profiles/reflect-distill.json +0 -30
- package/dist/assets/profiles/synthesize.json +0 -15
- package/dist/assets/prompts/procedural-system.md +0 -44
- package/dist/assets/prompts/recombine-system.md +0 -40
- package/dist/assets/prompts/staleness-detect-system.md +0 -6
- package/dist/assets/tasks/core/backup.yml +0 -4
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/assets/templates/html/default.html +0 -78
- package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
- package/dist/assets/wiki/index-template.md +0 -12
- package/dist/assets/wiki/ingest-workflow-template.md +0 -83
- package/dist/assets/wiki/log-template.md +0 -8
- package/dist/assets/wiki/schema-template.md +0 -61
- package/dist/cli/config-migrate.js +0 -150
- package/dist/cli/config-validate.js +0 -39
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -487
- package/dist/commands/improve/calibration.js +0 -161
- package/dist/commands/improve/dedup.js +0 -482
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/improve/hot-probation.js +0 -45
- package/dist/commands/improve/improve-auto-accept.js +0 -276
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/commands/improve/procedural.js +0 -398
- package/dist/commands/improve/recombine.js +0 -818
- package/dist/commands/improve/schema-similarity-gate.js +0 -168
- package/dist/commands/lint/agent-linter.js +0 -44
- package/dist/commands/lint/command-linter.js +0 -44
- package/dist/commands/lint/default-linter.js +0 -16
- package/dist/commands/lint/fact-linter.js +0 -39
- package/dist/commands/lint/knowledge-linter.js +0 -16
- package/dist/commands/lint/memory-linter.js +0 -61
- package/dist/commands/lint/registry.js +0 -41
- package/dist/commands/lint/skill-linter.js +0 -45
- package/dist/commands/lint/task-linter.js +0 -50
- package/dist/commands/lint/workflow-linter.js +0 -81
- package/dist/commands/proposal/legacy-import.js +0 -115
- package/dist/commands/sources/history.js +0 -196
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/commands/wiki-cli.js +0 -292
- package/dist/core/asset/asset-registry.js +0 -76
- package/dist/core/asset/asset-spec.js +0 -259
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/core/eval/rank-metrics.js +0 -113
- package/dist/core/ripgrep/install.js +0 -163
- package/dist/core/ripgrep/resolve.js +0 -81
- package/dist/indexer/db/db.js +0 -1413
- package/dist/indexer/manifest.js +0 -170
- package/dist/indexer/passes/metadata-contributors.js +0 -31
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
- package/dist/llm/call-ai.js +0 -62
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/output/shapes/distill.js +0 -14
- package/dist/output/shapes/history.js +0 -11
- package/dist/output/text/distill.js +0 -6
- package/dist/output/text/enable-disable.js +0 -8
- package/dist/output/text/history.js +0 -6
- package/dist/output/text/wiki.js +0 -16
- package/dist/registry/build-index.js +0 -386
- package/dist/scripts/migrate-storage.js +0 -19108
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
- package/dist/scripts/migrations/v16-to-v17.js +0 -141
- package/dist/setup/legacy-config.js +0 -106
- package/dist/storage/repositories/consolidation-repository.js +0 -38
- package/dist/storage/repositories/recombine-repository.js +0 -213
- package/dist/wiki/wiki-templates.js +0 -15
- package/dist/wiki/wiki.js +0 -1012
- package/dist/workflows/db.js +0 -215
- package/docs/data-and-telemetry.md +0 -226
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
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
|
-
// crontab backend for `akm
|
|
4
|
+
// crontab backend for `akm task` (Linux default).
|
|
5
5
|
//
|
|
6
6
|
// Each akm-owned entry is wrapped in markers so a hand-edited crontab keeps
|
|
7
7
|
// its other lines untouched:
|
|
8
8
|
//
|
|
9
9
|
// # akm:task <id> BEGIN
|
|
10
|
-
// [SCHED] /abs/akm
|
|
10
|
+
// [SCHED] /abs/akm task run <id> >> /home/.../tasks/logs/<id>.log 2>&1
|
|
11
11
|
// # akm:task <id> END
|
|
12
12
|
//
|
|
13
13
|
// The backend reads/writes the user's crontab via `crontab -l` and
|
|
@@ -25,59 +25,100 @@
|
|
|
25
25
|
//
|
|
26
26
|
// Tests inject a fake exec so unit tests don't touch the real crontab.
|
|
27
27
|
import { spawnSync } from "node:child_process";
|
|
28
|
-
import fs from "node:fs";
|
|
29
28
|
import path from "node:path";
|
|
30
29
|
import { ConfigError } from "../../core/errors.js";
|
|
31
30
|
import { getTaskLogDir } from "../../core/paths.js";
|
|
32
31
|
import { resolveAkmInvocation } from "../resolve-akm-bin.js";
|
|
33
32
|
import { parseSchedule, translateToCron } from "../schedule.js";
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
import { buildScheduledTaskInvocation, parseScheduledTaskArgv, resolveScheduledTaskContext, schedulerContextDescriptor, schedulerContextPath, } from "../scheduler-invocation.js";
|
|
34
|
+
import { nodeFs, throwIfNotOk } from "./exec-utils.js";
|
|
35
|
+
const BEGIN = (id) => `# akm:task ${assertCronValue(id)} BEGIN`;
|
|
36
|
+
const END = (id) => `# akm:task ${assertCronValue(id)} END`;
|
|
36
37
|
const DISABLED_PREFIX = "# akm:disabled ";
|
|
37
38
|
const BLOCK_RE = /^# akm:task ([\w.@:_-]+) BEGIN$/;
|
|
39
|
+
const BLOCK_END_RE = /^# akm:task ([\w.@:_-]+) END$/;
|
|
40
|
+
export const PORTABLE_CRON_LINE_LIMIT = 1000;
|
|
38
41
|
export function CRON_BACKEND(options = {}) {
|
|
39
42
|
const exec = options.exec ?? defaultCronExec();
|
|
43
|
+
const fsLike = options.fs ?? nodeFs();
|
|
40
44
|
const logDir = options.logDir ?? getTaskLogDir();
|
|
41
45
|
const akmArgv = options.akmArgv ?? resolveAkmInvocation().argv;
|
|
46
|
+
const envPath = options.envPath === false ? undefined : (options.envPath ?? process.env.PATH);
|
|
47
|
+
const scheduledContext = options.scheduledContext ?? resolveScheduledTaskContext();
|
|
48
|
+
const defaultContextPath = schedulerContextPath(schedulerContextDescriptor(scheduledContext, envPath ?? ""));
|
|
42
49
|
return {
|
|
43
50
|
name: "cron",
|
|
44
|
-
install(task) {
|
|
51
|
+
install(task, opts) {
|
|
45
52
|
// Create the log directory before writing the crontab line — cron
|
|
46
53
|
// appends with `>>` and the surrounding shell will fail the entire
|
|
47
54
|
// entry if the parent directory doesn't exist.
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
const cronLine = buildCronLine(task, [...(opts?.binding ?? akmArgv)], logDir, opts?.contextPath ?? defaultContextPath, opts?.target);
|
|
56
|
+
assertPortableCronLine(cronLine);
|
|
57
|
+
fsLike.ensureDir(logDir);
|
|
50
58
|
const existing = readCrontab(exec);
|
|
51
59
|
const block = renderBlock(task.id, cronLine, task.enabled);
|
|
52
60
|
const next = upsertBlock(existing, task.id, block);
|
|
53
|
-
|
|
61
|
+
replaceCrontab(exec, existing, next);
|
|
54
62
|
},
|
|
55
63
|
uninstall(id) {
|
|
56
64
|
const existing = readCrontab(exec);
|
|
57
65
|
const next = removeBlock(existing, id);
|
|
58
|
-
|
|
66
|
+
replaceCrontab(exec, existing, next);
|
|
59
67
|
},
|
|
60
68
|
setEnabled(id, enabled) {
|
|
61
69
|
const existing = readCrontab(exec);
|
|
62
70
|
const next = toggleBlock(existing, id, enabled);
|
|
63
|
-
|
|
71
|
+
replaceCrontab(exec, existing, next);
|
|
64
72
|
},
|
|
65
73
|
list() {
|
|
66
74
|
const existing = readCrontab(exec);
|
|
67
|
-
|
|
75
|
+
const refs = [];
|
|
76
|
+
for (const { id, body } of listBlocks(existing)) {
|
|
77
|
+
const installed = extractCronInvocation(body);
|
|
78
|
+
// An invocation that no longer parses (e.g. a pre-0.9 `tasks run`
|
|
79
|
+
// entry surviving the scheduler-ABI respelling, or any other
|
|
80
|
+
// foreign/malformed line between our markers) is an orphan of its
|
|
81
|
+
// marker id, not a hard failure: omit it here so `akmTasksSync`
|
|
82
|
+
// treats the id as "not present" and reinstalls it from the current
|
|
83
|
+
// task file — going through the normal eligibility/`--rebind` gate
|
|
84
|
+
// exactly like a fresh install.
|
|
85
|
+
if (!installed)
|
|
86
|
+
continue;
|
|
87
|
+
refs.push({
|
|
88
|
+
id,
|
|
89
|
+
signature: normalizeSignature(body),
|
|
90
|
+
...(installed.target !== undefined ? { target: installed.target } : {}),
|
|
91
|
+
binding: installed.binding,
|
|
92
|
+
contextPath: installed.contextPath,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return refs;
|
|
96
|
+
},
|
|
97
|
+
listForRebind() {
|
|
98
|
+
const existing = readCrontab(exec);
|
|
99
|
+
return listBlocks(existing).map(({ id, body }) => {
|
|
100
|
+
const installed = extractCronInvocation(body);
|
|
101
|
+
return {
|
|
102
|
+
id,
|
|
103
|
+
signature: normalizeSignature(body),
|
|
104
|
+
...(installed?.target !== undefined ? { target: installed.target } : {}),
|
|
105
|
+
};
|
|
106
|
+
});
|
|
68
107
|
},
|
|
69
|
-
expectedSignature(task) {
|
|
70
|
-
const cronLine = buildCronLine(task, akmArgv, logDir);
|
|
108
|
+
expectedSignature(task, opts) {
|
|
109
|
+
const cronLine = buildCronLine(task, [...(opts?.binding ?? akmArgv)], logDir, opts?.contextPath ?? defaultContextPath, opts?.target);
|
|
110
|
+
assertPortableCronLine(cronLine);
|
|
71
111
|
return normalizeSignature(cronBlockBody(cronLine, task.enabled));
|
|
72
112
|
},
|
|
73
113
|
};
|
|
74
114
|
}
|
|
75
115
|
// ── helpers (exported for tests) ────────────────────────────────────────────
|
|
76
|
-
export function buildCronLine(task, akmArgv, logDir) {
|
|
116
|
+
export function buildCronLine(task, akmArgv, logDir, contextPath, target) {
|
|
77
117
|
const spec = parseSchedule(task.schedule, "cron");
|
|
78
118
|
const cronExpr = translateToCron(spec);
|
|
79
119
|
const logPath = path.join(logDir, `${task.id}.log`);
|
|
80
|
-
const
|
|
120
|
+
const invocation = buildScheduledTaskInvocation(akmArgv, task.id, contextPath, target);
|
|
121
|
+
const cmd = invocation.argv.map((part) => quoteForCron(part)).join(" ");
|
|
81
122
|
return `${cronExpr} ${cmd} >> ${quoteForCron(logPath)} 2>&1`;
|
|
82
123
|
}
|
|
83
124
|
/** The crontab line as it appears inside a block — commented when disabled. */
|
|
@@ -93,28 +134,97 @@ export function renderBlock(id, cronLine, enabled) {
|
|
|
93
134
|
* drift signature, and exported for tests.
|
|
94
135
|
*/
|
|
95
136
|
export function listBlocks(existing) {
|
|
137
|
+
return parseBlocks(existing).map(({ id, body }) => ({ id, body }));
|
|
138
|
+
}
|
|
139
|
+
function parseBlocks(existing) {
|
|
96
140
|
const out = [];
|
|
97
141
|
const lines = existing.split(/\r?\n/);
|
|
98
142
|
let currentId = null;
|
|
143
|
+
let start = -1;
|
|
99
144
|
let body = [];
|
|
100
|
-
for (const line of lines) {
|
|
145
|
+
for (const [index, line] of lines.entries()) {
|
|
101
146
|
const begin = line.match(BLOCK_RE);
|
|
102
147
|
if (begin) {
|
|
148
|
+
if (currentId !== null)
|
|
149
|
+
throw malformedBlockError(currentId);
|
|
103
150
|
currentId = begin[1];
|
|
151
|
+
start = index;
|
|
104
152
|
body = [];
|
|
105
153
|
continue;
|
|
106
154
|
}
|
|
107
|
-
|
|
108
|
-
|
|
155
|
+
const end = line.match(BLOCK_END_RE);
|
|
156
|
+
if (end) {
|
|
157
|
+
if (currentId === null || end[1] !== currentId)
|
|
158
|
+
throw malformedBlockError(currentId ?? end[1]);
|
|
159
|
+
out.push({ id: currentId, body: body.join("\n"), start, end: index });
|
|
109
160
|
currentId = null;
|
|
161
|
+
start = -1;
|
|
110
162
|
body = [];
|
|
111
163
|
continue;
|
|
112
164
|
}
|
|
113
165
|
if (currentId !== null)
|
|
114
166
|
body.push(line);
|
|
115
167
|
}
|
|
168
|
+
if (currentId !== null)
|
|
169
|
+
throw malformedBlockError(currentId);
|
|
116
170
|
return out;
|
|
117
171
|
}
|
|
172
|
+
function malformedBlockError(id) {
|
|
173
|
+
return new ConfigError(`Crontab contains a malformed akm task block for "${id}"; refusing to modify it.`, "INVALID_CONFIG_FILE");
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Recover the bundle name from an installed cron block body by reading the
|
|
177
|
+
* `--bundle <bundle>` token embedded in the scheduled `akm task run …`
|
|
178
|
+
* invocation. Returns undefined for the byte-identical primary/default form
|
|
179
|
+
* (no `--bundle`). Bundle slugs never contain whitespace (config-schema
|
|
180
|
+
* `isBundleSlug`), so the quoted token is a single whitespace-delimited field
|
|
181
|
+
* even when cron-quoted — a plain field split recovers it, and
|
|
182
|
+
* the shell-word parser below reverses the quoting.
|
|
183
|
+
*/
|
|
184
|
+
export function extractInstalledTarget(body) {
|
|
185
|
+
return extractCronInvocation(body)?.target;
|
|
186
|
+
}
|
|
187
|
+
export function extractCronInvocation(body) {
|
|
188
|
+
const line = body.startsWith(DISABLED_PREFIX) ? body.slice(DISABLED_PREFIX.length) : body;
|
|
189
|
+
const fields = splitCronShellWords(line);
|
|
190
|
+
if (fields.length < 6)
|
|
191
|
+
return undefined;
|
|
192
|
+
let commandStart = 5;
|
|
193
|
+
while (commandStart < fields.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(fields[commandStart]))
|
|
194
|
+
commandStart += 1;
|
|
195
|
+
const redirectIndex = fields.indexOf(">>", commandStart);
|
|
196
|
+
if (redirectIndex === -1)
|
|
197
|
+
return undefined;
|
|
198
|
+
return parseScheduledTaskArgv(fields.slice(commandStart, redirectIndex));
|
|
199
|
+
}
|
|
200
|
+
/** Reverse {@link quoteForCron} for a single whitespace-free token. */
|
|
201
|
+
function splitCronShellWords(value) {
|
|
202
|
+
const words = [];
|
|
203
|
+
let current = "";
|
|
204
|
+
let quoted = false;
|
|
205
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
206
|
+
const char = value[index];
|
|
207
|
+
if (char === "'") {
|
|
208
|
+
quoted = !quoted;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (char === "\\" && index + 1 < value.length) {
|
|
212
|
+
current += value[index + 1];
|
|
213
|
+
index += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (!quoted && /\s/.test(char)) {
|
|
217
|
+
if (current)
|
|
218
|
+
words.push(current);
|
|
219
|
+
current = "";
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
current += char;
|
|
223
|
+
}
|
|
224
|
+
if (current)
|
|
225
|
+
words.push(current);
|
|
226
|
+
return words;
|
|
227
|
+
}
|
|
118
228
|
/** Collapse incidental whitespace so signature comparison ignores it. */
|
|
119
229
|
function normalizeSignature(body) {
|
|
120
230
|
return body
|
|
@@ -131,27 +241,17 @@ export function upsertBlock(existing, id, block) {
|
|
|
131
241
|
}
|
|
132
242
|
export function removeBlock(existing, id) {
|
|
133
243
|
const lines = existing.split(/\r?\n/);
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
inBlock = true;
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (inBlock && line === END(id)) {
|
|
142
|
-
inBlock = false;
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
if (inBlock)
|
|
146
|
-
continue;
|
|
147
|
-
out.push(line);
|
|
148
|
-
}
|
|
244
|
+
const blocks = parseBlocks(existing).filter((block) => block.id === id);
|
|
245
|
+
if (blocks.length === 0)
|
|
246
|
+
return existing;
|
|
247
|
+
const out = lines.filter((_, index) => !blocks.some((block) => index >= block.start && index <= block.end));
|
|
149
248
|
// Collapse trailing blank lines.
|
|
150
249
|
while (out.length > 0 && out[out.length - 1] === "")
|
|
151
250
|
out.pop();
|
|
152
251
|
return out.join("\n");
|
|
153
252
|
}
|
|
154
253
|
export function toggleBlock(existing, id, enabled) {
|
|
254
|
+
parseBlocks(existing);
|
|
155
255
|
const lines = existing.split(/\r?\n/);
|
|
156
256
|
const out = [];
|
|
157
257
|
let inBlock = false;
|
|
@@ -184,12 +284,29 @@ export function toggleBlock(existing, id, enabled) {
|
|
|
184
284
|
return out.join("\n");
|
|
185
285
|
}
|
|
186
286
|
function quoteForCron(part) {
|
|
287
|
+
assertCronValue(part);
|
|
187
288
|
// crontab passes the rest of the line to /bin/sh -c, so quote anything that
|
|
188
289
|
// isn't a plain shell-safe token. Single-quote and escape embedded single
|
|
189
|
-
// quotes via the standard shell idiom: `'foo'\''bar'`.
|
|
290
|
+
// quotes via the standard shell idiom: `'foo'\''bar'`. Cron interprets `%`
|
|
291
|
+
// before the shell, even inside quotes, so close the quote around its escape.
|
|
190
292
|
if (/^[A-Za-z0-9_\-./@:%=+,]+$/.test(part))
|
|
191
|
-
return part;
|
|
192
|
-
return `'${part.replace(/'/g, `'\\''`)}'`;
|
|
293
|
+
return part.replaceAll("%", "\\%");
|
|
294
|
+
return `'${part.replace(/'/g, `'\\''`).replace(/%/g, `'\\%'`)}'`;
|
|
295
|
+
}
|
|
296
|
+
function assertCronValue(value) {
|
|
297
|
+
for (const char of value) {
|
|
298
|
+
const code = char.codePointAt(0) ?? 0;
|
|
299
|
+
if (code < 0x20 || (code >= 0x7f && code <= 0x9f)) {
|
|
300
|
+
throw new ConfigError("Cron values must not contain control characters.", "INVALID_CONFIG_FILE");
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return value;
|
|
304
|
+
}
|
|
305
|
+
function assertPortableCronLine(line) {
|
|
306
|
+
const bytes = Buffer.byteLength(line, "utf8");
|
|
307
|
+
if (bytes > PORTABLE_CRON_LINE_LIMIT) {
|
|
308
|
+
throw new ConfigError(`Generated cron definition is ${bytes} bytes; portable cron command lines are limited to ${PORTABLE_CRON_LINE_LIMIT} bytes.`, "INVALID_CONFIG_FILE");
|
|
309
|
+
}
|
|
193
310
|
}
|
|
194
311
|
function readCrontab(exec) {
|
|
195
312
|
const result = exec.read();
|
|
@@ -204,18 +321,24 @@ function readCrontab(exec) {
|
|
|
204
321
|
}
|
|
205
322
|
function writeCrontab(exec, content) {
|
|
206
323
|
const normalised = content.endsWith("\n") || content.length === 0 ? content : `${content}\n`;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
324
|
+
throwIfNotOk(exec.write(normalised), {
|
|
325
|
+
message: (r) => `crontab - failed (exit ${r.status}): ${r.stderr || r.stdout || "no output"}.`,
|
|
326
|
+
hint: "Ensure the `crontab` binary is on PATH and your shell can write the user crontab.",
|
|
327
|
+
});
|
|
211
328
|
}
|
|
212
|
-
function
|
|
329
|
+
function replaceCrontab(exec, existing, next) {
|
|
213
330
|
try {
|
|
214
|
-
|
|
331
|
+
writeCrontab(exec, next);
|
|
215
332
|
}
|
|
216
|
-
catch {
|
|
217
|
-
|
|
218
|
-
|
|
333
|
+
catch (err) {
|
|
334
|
+
try {
|
|
335
|
+
writeCrontab(exec, existing);
|
|
336
|
+
}
|
|
337
|
+
catch (rollbackError) {
|
|
338
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
339
|
+
throw new AggregateError([err, rollbackError], `${message}; restoring the prior crontab also failed.`);
|
|
340
|
+
}
|
|
341
|
+
throw err;
|
|
219
342
|
}
|
|
220
343
|
}
|
|
221
344
|
function defaultCronExec() {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
+
import { ConfigError } from "../../core/errors.js";
|
|
6
7
|
/**
|
|
7
8
|
* Default exec strategy: run commands synchronously via {@link spawnCommand}.
|
|
8
9
|
*
|
|
@@ -40,13 +41,85 @@ export function nodeFs() {
|
|
|
40
41
|
*/
|
|
41
42
|
export function spawnCommand(args) {
|
|
42
43
|
const [bin, ...rest] = args;
|
|
43
|
-
const r = spawnSync(bin, rest
|
|
44
|
+
const r = spawnSync(bin, rest);
|
|
44
45
|
return {
|
|
45
46
|
status: r.status ?? 1,
|
|
46
|
-
stdout: r.stdout
|
|
47
|
-
stderr: r.stderr
|
|
47
|
+
stdout: decodeCommandOutput(r.stdout),
|
|
48
|
+
stderr: decodeCommandOutput(r.stderr),
|
|
48
49
|
};
|
|
49
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Throw a `ConfigError` (code `INVALID_CONFIG_FILE`) when `result` doesn't
|
|
53
|
+
* satisfy `isOk` (default: `status === 0`); otherwise return `result`
|
|
54
|
+
* unchanged. Factors out the "run a native scheduler command, throw a
|
|
55
|
+
* formatted error on a bad exit" idiom repeated across the cron/launchd/
|
|
56
|
+
* schtasks backends — NOT the accumulate-into-`rollbackErrors`-and-continue
|
|
57
|
+
* idiom used during rollback, which stays inline (throwing there would
|
|
58
|
+
* change control flow: rollback needs to keep trying its remaining steps).
|
|
59
|
+
*/
|
|
60
|
+
export function throwIfNotOk(result, options) {
|
|
61
|
+
const ok = options.isOk ? options.isOk(result) : result.status === 0;
|
|
62
|
+
if (!ok) {
|
|
63
|
+
throw new ConfigError(options.message(result), "INVALID_CONFIG_FILE", options.hint);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
/** {@link throwIfNotOk} for the common case of running `args` via `exec` first. */
|
|
68
|
+
export function runOrThrow(exec, args, options) {
|
|
69
|
+
return throwIfNotOk(exec.run(args), options);
|
|
70
|
+
}
|
|
71
|
+
/** Decode native command output, including the UTF-16 XML emitted by schtasks. */
|
|
72
|
+
export function decodeCommandOutput(output) {
|
|
73
|
+
if (output === null || output === undefined)
|
|
74
|
+
return "";
|
|
75
|
+
if (typeof output === "string")
|
|
76
|
+
return output.replace(/^\uFEFF/, "");
|
|
77
|
+
if (output.length === 0)
|
|
78
|
+
return "";
|
|
79
|
+
if (output[0] === 0xef && output[1] === 0xbb && output[2] === 0xbf) {
|
|
80
|
+
return output.toString("utf8", 3);
|
|
81
|
+
}
|
|
82
|
+
if (output[0] === 0xff && output[1] === 0xfe) {
|
|
83
|
+
return output.subarray(2).toString("utf16le");
|
|
84
|
+
}
|
|
85
|
+
if (output[0] === 0xfe && output[1] === 0xff) {
|
|
86
|
+
return decodeUtf16Be(output.subarray(2));
|
|
87
|
+
}
|
|
88
|
+
const pairs = Math.floor(output.length / 2);
|
|
89
|
+
if (pairs > 1) {
|
|
90
|
+
let evenNuls = 0;
|
|
91
|
+
let oddNuls = 0;
|
|
92
|
+
for (let i = 0; i < pairs * 2; i += 2) {
|
|
93
|
+
if (output[i] === 0)
|
|
94
|
+
evenNuls += 1;
|
|
95
|
+
if (output[i + 1] === 0)
|
|
96
|
+
oddNuls += 1;
|
|
97
|
+
}
|
|
98
|
+
if (oddNuls / pairs > 0.6)
|
|
99
|
+
return output.toString("utf16le");
|
|
100
|
+
if (evenNuls / pairs > 0.6)
|
|
101
|
+
return decodeUtf16Be(output);
|
|
102
|
+
}
|
|
103
|
+
return output.toString("utf8");
|
|
104
|
+
}
|
|
105
|
+
/** Return XML with the declaration required by Task Scheduler's UTF-16 input. */
|
|
106
|
+
export function normalizeXmlForUtf16File(xml) {
|
|
107
|
+
const source = xml.replace(/^\uFEFF/, "");
|
|
108
|
+
const declaration = '<?xml version="1.0" encoding="UTF-16"?>';
|
|
109
|
+
if (/^<\?xml\b[^?]*\?>/i.test(source)) {
|
|
110
|
+
return source.replace(/^<\?xml\b[^?]*\?>/i, declaration);
|
|
111
|
+
}
|
|
112
|
+
return `${declaration}\n${source}`;
|
|
113
|
+
}
|
|
114
|
+
function decodeUtf16Be(output) {
|
|
115
|
+
const evenLength = output.length - (output.length % 2);
|
|
116
|
+
const swapped = Buffer.allocUnsafe(evenLength);
|
|
117
|
+
for (let i = 0; i < evenLength; i += 2) {
|
|
118
|
+
swapped[i] = output[i + 1];
|
|
119
|
+
swapped[i + 1] = output[i];
|
|
120
|
+
}
|
|
121
|
+
return swapped.toString("utf16le");
|
|
122
|
+
}
|
|
50
123
|
/**
|
|
51
124
|
* Escape a string for safe embedding in an XML attribute or text node.
|
|
52
125
|
*/
|
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
import { CRON_BACKEND } from "./cron.js";
|
|
5
5
|
import { LAUNCHD_BACKEND } from "./launchd.js";
|
|
6
6
|
import { SCHTASKS_BACKEND } from "./schtasks.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// WI-9.10e: the former `_setBackendsForTests` module-mutation seam was retired.
|
|
8
|
+
// Tests inject a fake `TaskBackend` directly via the `deps.backend` parameter
|
|
9
|
+
// the `akm task` mutation entries already accept (the backend carries its own
|
|
10
|
+
// `name`), so no module-level override binding is needed. `selectBackend`'s
|
|
11
|
+
// `options.platform` covers the platform-steering the seam's second override
|
|
12
|
+
// used to provide.
|
|
12
13
|
export function selectBackend(options = {}) {
|
|
13
|
-
if (backendsOverrides?.selectBackend)
|
|
14
|
-
return backendsOverrides.selectBackend(options);
|
|
15
14
|
const platform = options.platform ?? process.platform;
|
|
16
15
|
switch (platform) {
|
|
17
16
|
case "win32":
|
|
@@ -23,8 +22,6 @@ export function selectBackend(options = {}) {
|
|
|
23
22
|
}
|
|
24
23
|
}
|
|
25
24
|
export function backendNameForPlatform(platform = process.platform) {
|
|
26
|
-
if (backendsOverrides?.backendNameForPlatform)
|
|
27
|
-
return backendsOverrides.backendNameForPlatform(platform);
|
|
28
25
|
if (platform === "win32")
|
|
29
26
|
return "schtasks";
|
|
30
27
|
if (platform === "darwin")
|