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
package/dist/core/paths.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import os from "node:os";
|
|
12
12
|
import path from "node:path";
|
|
13
|
-
import { IS_WINDOWS } from "./common.js";
|
|
14
13
|
import { ConfigError } from "./errors.js";
|
|
14
|
+
import { IS_WINDOWS } from "./platform.js";
|
|
15
15
|
/**
|
|
16
16
|
* Returns true when the current process appears to be running under
|
|
17
17
|
* `bun test` (either via the BUN_TEST sentinel Bun sets on the test
|
|
@@ -30,10 +30,10 @@ function isUnderBunTest(env) {
|
|
|
30
30
|
* Returns true when the given path is in a directory family the OS may
|
|
31
31
|
* reap (or that the user has clearly designated as a sandbox by virtue
|
|
32
32
|
* of placing it under `/tmp` or a macOS per-user temp dir). Used to
|
|
33
|
-
* decide whether `
|
|
33
|
+
* decide whether `AKM_BUNDLE_DIR=$tmpdir` should also isolate config +
|
|
34
34
|
* cache writes (so a test harness's `akm setup --yes --dir .` cannot
|
|
35
35
|
* silently clobber the user's `~/.config/akm/config.json`). See
|
|
36
|
-
*
|
|
36
|
+
* the 2026-05-23 setup-clobbers-user-config incident
|
|
37
37
|
* for the incident that motivated this.
|
|
38
38
|
*
|
|
39
39
|
* Both `/var/folders/*` and `/private/var/folders/*` are matched because
|
|
@@ -67,7 +67,7 @@ export function getConfigDir(env = process.env, platform = process.platform) {
|
|
|
67
67
|
return override;
|
|
68
68
|
// Explicit XDG override wins next — tests and operators that pre-arrange
|
|
69
69
|
// an isolated config dir via XDG_CONFIG_HOME (or %APPDATA% on Windows)
|
|
70
|
-
// must be honored as set, so the
|
|
70
|
+
// must be honored as set, so the AKM_BUNDLE_DIR transient-isolation rule
|
|
71
71
|
// below does not silently move config away from where they pointed it.
|
|
72
72
|
if (platform === "win32") {
|
|
73
73
|
const appData = env.APPDATA?.trim();
|
|
@@ -79,16 +79,16 @@ export function getConfigDir(env = process.env, platform = process.platform) {
|
|
|
79
79
|
if (xdgConfigHome)
|
|
80
80
|
return path.join(xdgConfigHome, "akm");
|
|
81
81
|
}
|
|
82
|
-
// Isolation safety: when
|
|
82
|
+
// Isolation safety: when AKM_BUNDLE_DIR points at a transient/sandbox path
|
|
83
83
|
// (/tmp, /var/tmp, /private/var/folders) AND no explicit config dir
|
|
84
|
-
// override is set, route config writes into `${
|
|
84
|
+
// override is set, route config writes into `${AKM_BUNDLE_DIR}/.akm`
|
|
85
85
|
// instead of the user's host ~/.config/akm. This prevents the documented
|
|
86
86
|
// isolation pattern
|
|
87
|
-
// AKM_DATA_DIR=/tmp/x
|
|
87
|
+
// AKM_DATA_DIR=/tmp/x AKM_BUNDLE_DIR=/tmp/x akm setup --yes --dir .
|
|
88
88
|
// from silently clobbering the host config. See
|
|
89
|
-
//
|
|
90
|
-
// Daily users with a persistent
|
|
91
|
-
const stashOverride = env.
|
|
89
|
+
// the 2026-05-23 setup-clobbers-user-config incident.
|
|
90
|
+
// Daily users with a persistent AKM_BUNDLE_DIR=~/my-stash are unaffected.
|
|
91
|
+
const stashOverride = env.AKM_BUNDLE_DIR?.trim();
|
|
92
92
|
if (stashOverride && isTransientStashPath(stashOverride)) {
|
|
93
93
|
return path.join(stashOverride, ".akm");
|
|
94
94
|
}
|
|
@@ -122,7 +122,7 @@ export function getCacheDir(env = process.env) {
|
|
|
122
122
|
// Explicit XDG/platform overrides win before the transient-stash isolation
|
|
123
123
|
// rule below — tests and operators that pre-arrange XDG_CACHE_HOME (or
|
|
124
124
|
// %LOCALAPPDATA% / %USERPROFILE% / %APPDATA% on Windows) must be honored
|
|
125
|
-
// as set, so the
|
|
125
|
+
// as set, so the AKM_BUNDLE_DIR transient rule does not silently move cache
|
|
126
126
|
// writes away from where they pointed them.
|
|
127
127
|
if (IS_WINDOWS) {
|
|
128
128
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
@@ -145,12 +145,12 @@ export function getCacheDir(env = process.env) {
|
|
|
145
145
|
if (xdgCacheHome)
|
|
146
146
|
return path.join(xdgCacheHome, "akm");
|
|
147
147
|
}
|
|
148
|
-
// Isolation safety (mirrors getConfigDir): when
|
|
148
|
+
// Isolation safety (mirrors getConfigDir): when AKM_BUNDLE_DIR points at a
|
|
149
149
|
// transient path AND no explicit cache override is set, route cache writes
|
|
150
|
-
// into `${
|
|
150
|
+
// into `${AKM_BUNDLE_DIR}/.akm/cache` so that config backups, registry-index
|
|
151
151
|
// cache, and other regenerable artifacts do not pollute the user's host
|
|
152
152
|
// ~/.cache/akm directory.
|
|
153
|
-
const stashOverride = env.
|
|
153
|
+
const stashOverride = env.AKM_BUNDLE_DIR?.trim();
|
|
154
154
|
if (stashOverride && isTransientStashPath(stashOverride)) {
|
|
155
155
|
return path.join(stashOverride, ".akm", "cache");
|
|
156
156
|
}
|
|
@@ -184,7 +184,7 @@ export function getDataDir(env = process.env, platform = process.platform) {
|
|
|
184
184
|
// user's real $XDG_DATA_HOME / ~/.local/share/akm under any condition.
|
|
185
185
|
// Any test that needs a data dir must point it at a mktemp-d directory
|
|
186
186
|
// via XDG_DATA_HOME (or AKM_DATA_DIR). The previous carve-out that only
|
|
187
|
-
// fired when
|
|
187
|
+
// fired when AKM_BUNDLE_DIR was set was a loophole: tests calling
|
|
188
188
|
// openDatabase() or getDbPath() without overriding any env var silently
|
|
189
189
|
// wrote into ~/.local/share/akm/index.db (observed: 4,183-row
|
|
190
190
|
// registry-cache pollution). Item 5 of the 0.8.x critical-review plan.
|
|
@@ -218,16 +218,16 @@ export function getDbPath(env = process.env) {
|
|
|
218
218
|
export function getIndexWriterLockPath() {
|
|
219
219
|
return path.join(getDataDir(), "index.db.write.lock");
|
|
220
220
|
}
|
|
221
|
-
export function
|
|
222
|
-
return path.join(getDataDir(), "
|
|
221
|
+
export function getMaintenanceBarrierPath() {
|
|
222
|
+
return path.join(getDataDir(), "maintenance.barrier.lock");
|
|
223
223
|
}
|
|
224
224
|
/** Path to the state.db file in $DATA. */
|
|
225
225
|
export function getStateDbPathInDataDir() {
|
|
226
226
|
return path.join(getDataDir(), "state.db");
|
|
227
227
|
}
|
|
228
|
-
/**
|
|
229
|
-
export function
|
|
230
|
-
return path.join(getDataDir(), "tasks", "
|
|
228
|
+
/** Content-addressed scheduler runtime descriptors. */
|
|
229
|
+
export function getTaskContextDir(env = process.env) {
|
|
230
|
+
return path.join(getDataDir(env), "tasks", "context");
|
|
231
231
|
}
|
|
232
232
|
/** Path to the akm.lock file in $DATA. */
|
|
233
233
|
export function getLockfilePath() {
|
|
@@ -246,9 +246,6 @@ export function getRegistryCacheDir() {
|
|
|
246
246
|
export function getRegistryIndexCacheDir() {
|
|
247
247
|
return path.join(getCacheDir(), "registry-index");
|
|
248
248
|
}
|
|
249
|
-
export function getBinDir() {
|
|
250
|
-
return path.join(getCacheDir(), "bin");
|
|
251
|
-
}
|
|
252
249
|
// ── Scheduled-task runtime directories (logs + history) ──────────────────────
|
|
253
250
|
export function getTaskLogDir() {
|
|
254
251
|
return path.join(getCacheDir(), "tasks", "logs");
|
|
@@ -258,7 +255,7 @@ export function getTaskHistoryDir() {
|
|
|
258
255
|
}
|
|
259
256
|
// ── Default stash directory ──────────────────────────────────────────────────
|
|
260
257
|
export function getDefaultStashDir(env = process.env) {
|
|
261
|
-
const override = env.
|
|
258
|
+
const override = env.AKM_BUNDLE_DIR?.trim();
|
|
262
259
|
if (override)
|
|
263
260
|
return override;
|
|
264
261
|
if (IS_WINDOWS) {
|
|
@@ -269,7 +266,7 @@ export function getDefaultStashDir(env = process.env) {
|
|
|
269
266
|
}
|
|
270
267
|
const home = env.HOME?.trim();
|
|
271
268
|
if (!home) {
|
|
272
|
-
throw new ConfigError("Unable to determine default
|
|
269
|
+
throw new ConfigError("Unable to determine default bundle directory. Set HOME.", "STASH_DIR_NOT_FOUND");
|
|
273
270
|
}
|
|
274
271
|
return path.join(home, "akm");
|
|
275
272
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
* Platform detection leaf (chunk-8 WI-8.6, DoD 11). Imports NOTHING so both
|
|
6
|
+
* `common.ts` and `paths.ts` can depend on it — extracting IS_WINDOWS here
|
|
7
|
+
* broke the `common.ts ↔ paths.ts` import cycle (paths needed only this
|
|
8
|
+
* constant from common).
|
|
9
|
+
*/
|
|
10
|
+
export const IS_WINDOWS = process.platform === "win32";
|
|
@@ -0,0 +1,128 @@
|
|
|
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 util home for recognition/grammar constants shared across the asset,
|
|
6
|
+
* indexer, and workflow layers (chunk 1, D1-4).
|
|
7
|
+
*
|
|
8
|
+
* INVARIANT (D1-5, cycle-safety): this module MUST import NOTHING from
|
|
9
|
+
* `src/` (no relative `./`/`../` imports into the tree). All four symbols
|
|
10
|
+
* below are self-contained literals/pure functions today, so this file is a
|
|
11
|
+
* pure sink — everything imports FROM it, it imports from nothing internal.
|
|
12
|
+
* The import-cycle ratchet (`scripts/lint-import-cycles.ts`) is shrink-only:
|
|
13
|
+
* a 29th cycle participant is a hard failure, so this file must never gain
|
|
14
|
+
* an internal import that could pull it into an existing knot. Enforced
|
|
15
|
+
* mechanically by `tests/core/recognition-util.test.ts`.
|
|
16
|
+
*/
|
|
17
|
+
/** All recognized script extensions for the script asset type. */
|
|
18
|
+
export const SCRIPT_EXTENSIONS = new Set([
|
|
19
|
+
".sh",
|
|
20
|
+
".ts",
|
|
21
|
+
".js",
|
|
22
|
+
".ps1",
|
|
23
|
+
".cmd",
|
|
24
|
+
".bat",
|
|
25
|
+
".py",
|
|
26
|
+
".rb",
|
|
27
|
+
".go",
|
|
28
|
+
".pl",
|
|
29
|
+
".php",
|
|
30
|
+
".lua",
|
|
31
|
+
".r",
|
|
32
|
+
".swift",
|
|
33
|
+
".kt",
|
|
34
|
+
".kts",
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Recognized workflow asset extensions. One format now (workflow-format-
|
|
38
|
+
* unification): orchestration graph in frontmatter, prose in the body.
|
|
39
|
+
* `workflows/<name>` refs resolve against this list.
|
|
40
|
+
*/
|
|
41
|
+
export const WORKFLOW_EXTENSIONS = [".md"];
|
|
42
|
+
/**
|
|
43
|
+
* Strip the recognized workflow extension (`.md`) from a workflow asset
|
|
44
|
+
* *name* so `foo` and `foo.md` collapse to one canonical identity — the same
|
|
45
|
+
* collapse `workflowSpec.toCanonicalName` performs on a resolved file path.
|
|
46
|
+
* Callers that turn a `workflows/<name>` ref into run identity (the
|
|
47
|
+
* active-run guard, list/status filters) MUST route the name through this so
|
|
48
|
+
* an aliased spelling (`workflows/foo.md`) and the canonical `workflows/foo`
|
|
49
|
+
* cannot start or hide parallel runs of the same workflow. Names without the
|
|
50
|
+
* extension pass through unchanged.
|
|
51
|
+
*/
|
|
52
|
+
export function canonicalizeWorkflowName(name) {
|
|
53
|
+
const lower = name.toLowerCase();
|
|
54
|
+
for (const ext of WORKFLOW_EXTENSIONS) {
|
|
55
|
+
if (lower.endsWith(ext))
|
|
56
|
+
return name.slice(0, -ext.length);
|
|
57
|
+
}
|
|
58
|
+
return name;
|
|
59
|
+
}
|
|
60
|
+
/** Structural marker suffix for a derived (inferred) memory's canonical name. */
|
|
61
|
+
export const DERIVED_SUFFIX = ".derived";
|
|
62
|
+
// ── Known-type taxonomy (chunk 1.5, D1.5-4) ─────────────────────────────────
|
|
63
|
+
//
|
|
64
|
+
// `KNOWN_TYPES` replaces the deleted `common.ts` closed asset-type union.
|
|
65
|
+
// It is a HINT/exhaustiveness tuple, NOT a validation gate: unknown/foreign
|
|
66
|
+
// `type` strings are still valid `IndexDocument`/`IndexDocument`/`AssetRef` DATA
|
|
67
|
+
// (plan §2.3/§15.4) — this tuple only anchors compile-time completeness for
|
|
68
|
+
// AKM's OWN presentation/ranking tables (`Record<KnownType, X>` fails to
|
|
69
|
+
// compile if a key is missing). A plain `as const` literal tuple adds no
|
|
70
|
+
// import, so it lives here without breaking the D1-5 import-free invariant.
|
|
71
|
+
/**
|
|
72
|
+
* The AKM-owned built-in asset type keys — the deleted `common.ts` `ASSET_TYPES`
|
|
73
|
+
* set (same order) minus the retired `wiki` type (chunk 4); `instruction`
|
|
74
|
+
* (CLAUDE.md / AGENTS.md project-instruction files) is the newest, added for the
|
|
75
|
+
* format-family adapters (spec §6/§7 instruction row, maintainer resolution
|
|
76
|
+
* 2026-07). An instruction file is a read-like-knowledge markdown document, so
|
|
77
|
+
* it reuses knowledge's presentation shape (label "Instruction", `knowledge-md`
|
|
78
|
+
* renderer, a "read the project instructions" action) rather than the generic
|
|
79
|
+
* fallback. `wiki` was removed here in chunk 4 ("the wiki ASSET-TYPE dies", plan
|
|
80
|
+
* §11 Chunk 4 / §7.4): the LLM Wiki structure now lives in the first-class
|
|
81
|
+
* `llm-wiki` adapter whose page kinds are open (foreign) types, not AKM-owned.
|
|
82
|
+
*/
|
|
83
|
+
export const KNOWN_TYPES = [
|
|
84
|
+
"skill",
|
|
85
|
+
"command",
|
|
86
|
+
"agent",
|
|
87
|
+
"knowledge",
|
|
88
|
+
"workflow",
|
|
89
|
+
"script",
|
|
90
|
+
"memory",
|
|
91
|
+
"env",
|
|
92
|
+
"secret",
|
|
93
|
+
"lesson",
|
|
94
|
+
"task",
|
|
95
|
+
"session",
|
|
96
|
+
"fact",
|
|
97
|
+
"instruction",
|
|
98
|
+
];
|
|
99
|
+
/**
|
|
100
|
+
* Returns true when `type` is one of AKM's own known type keys
|
|
101
|
+
* ({@link KNOWN_TYPES}). Unlike the deleted `isAssetType`, this is NOT a
|
|
102
|
+
* validation gate — a `false` result does not mean `type` is invalid data,
|
|
103
|
+
* only that it is not AKM-owned (a foreign/adapter type is still a valid
|
|
104
|
+
* ref/entry). Used to index `Record<KnownType, X>` tables safely from an
|
|
105
|
+
* open `string` and, later, for cross-surface known-type spelling checks.
|
|
106
|
+
*/
|
|
107
|
+
export function isKnownType(type) {
|
|
108
|
+
return KNOWN_TYPES.includes(type);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Type keys deliberately REMOVED from AKM (chunk 1.5, D1.5-6 — the key
|
|
112
|
+
* correctness call in the open-token change). The open type token accepts
|
|
113
|
+
* any non-empty string as valid ref/entry DATA except this set: silently
|
|
114
|
+
* re-admitting a retired type as an ordinary "foreign" type would defeat the
|
|
115
|
+
* guard that removed it in the first place.
|
|
116
|
+
*
|
|
117
|
+
* - `vault` — removed in 0.9.0 in favor of `env`/`secret`; carries its own
|
|
118
|
+
* migration-hint `UsageError` in `asset-ref.ts` (checked before this
|
|
119
|
+
* set) and interacts with the dangerous-env-key lint
|
|
120
|
+
* (`commands/lint/env-key-rules.ts`) — vaults must never be silently
|
|
121
|
+
* re-admitted as an ordinary indexed/ref-able type.
|
|
122
|
+
* - `tool` — retired outright, no replacement.
|
|
123
|
+
*
|
|
124
|
+
* Consulted by the ref parser and `metadata.ts`'s
|
|
125
|
+
* `validateStashEntry` gate (and the `akm` adapter's `recognize`) so the
|
|
126
|
+
* rejection lives in one place instead of three closed-union-shaped copies.
|
|
127
|
+
*/
|
|
128
|
+
export const DEPRECATED_REJECTED_TYPES = new Set(["tool", "vault"]);
|
|
@@ -0,0 +1,392 @@
|
|
|
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
|
+
const ENV_PASSTHROUGH_REDACTION_POLICY = {
|
|
5
|
+
HOME: "path",
|
|
6
|
+
PATH: "path",
|
|
7
|
+
USER: "identifier",
|
|
8
|
+
LANG: "identifier",
|
|
9
|
+
LC_ALL: "identifier",
|
|
10
|
+
TERM: "identifier",
|
|
11
|
+
TMPDIR: "path",
|
|
12
|
+
SYSTEMROOT: "path",
|
|
13
|
+
COMSPEC: "path",
|
|
14
|
+
PATHEXT: "path",
|
|
15
|
+
WINDIR: "path",
|
|
16
|
+
TEMP: "path",
|
|
17
|
+
TMP: "path",
|
|
18
|
+
AKM_EVENT_SOURCE: "identifier",
|
|
19
|
+
OPENCODE_CONFIG: "path",
|
|
20
|
+
CLAUDE_CONFIG: "path",
|
|
21
|
+
CODEX_CONFIG: "path",
|
|
22
|
+
AWS_PROFILE: "identifier",
|
|
23
|
+
AWS_REGION: "identifier",
|
|
24
|
+
LLM_MODEL: "identifier",
|
|
25
|
+
LLM_BASE_URL: "url",
|
|
26
|
+
};
|
|
27
|
+
/** Environment names whose ordinary values identify runtime configuration rather than credentials. */
|
|
28
|
+
export const ENV_PASSTHROUGH_REDACTION_ALLOWLIST = new Set(Object.keys(ENV_PASSTHROUGH_REDACTION_POLICY));
|
|
29
|
+
const SIGNED_QUERY_KEYS = new Set([
|
|
30
|
+
"accesskey",
|
|
31
|
+
"accesskeyid",
|
|
32
|
+
"accesstoken",
|
|
33
|
+
"actortoken",
|
|
34
|
+
"apikey",
|
|
35
|
+
"assertion",
|
|
36
|
+
"authorization",
|
|
37
|
+
"authorizationcode",
|
|
38
|
+
"authreqid",
|
|
39
|
+
"clientassertion",
|
|
40
|
+
"clientsecret",
|
|
41
|
+
"code",
|
|
42
|
+
"codeverifier",
|
|
43
|
+
"credential",
|
|
44
|
+
"devicecode",
|
|
45
|
+
"googleaccessid",
|
|
46
|
+
"idtoken",
|
|
47
|
+
"idtokenhint",
|
|
48
|
+
"initialaccesstoken",
|
|
49
|
+
"key",
|
|
50
|
+
"loginhinttoken",
|
|
51
|
+
"logouthint",
|
|
52
|
+
"logouttoken",
|
|
53
|
+
"nonce",
|
|
54
|
+
"oauthcode",
|
|
55
|
+
"oauthtoken",
|
|
56
|
+
"oauthverifier",
|
|
57
|
+
"password",
|
|
58
|
+
"refreshtoken",
|
|
59
|
+
"registrationaccesstoken",
|
|
60
|
+
"requesturi",
|
|
61
|
+
"response",
|
|
62
|
+
"secret",
|
|
63
|
+
"sessiontoken",
|
|
64
|
+
"sharedaccesssignature",
|
|
65
|
+
"sig",
|
|
66
|
+
"signature",
|
|
67
|
+
"softwarestatement",
|
|
68
|
+
"state",
|
|
69
|
+
"subjecttoken",
|
|
70
|
+
"token",
|
|
71
|
+
"usercode",
|
|
72
|
+
"verifier",
|
|
73
|
+
"xamzcredential",
|
|
74
|
+
"xamzsecuritytoken",
|
|
75
|
+
"xamzsignature",
|
|
76
|
+
"xgoogcredential",
|
|
77
|
+
"xgoogsignature",
|
|
78
|
+
]);
|
|
79
|
+
function normalizedQueryKey(key) {
|
|
80
|
+
return key.toLowerCase().replaceAll(/[^a-z0-9]/g, "");
|
|
81
|
+
}
|
|
82
|
+
function collectCredentialParameters(params, values) {
|
|
83
|
+
let found = false;
|
|
84
|
+
for (const [key, value] of params) {
|
|
85
|
+
if (!SIGNED_QUERY_KEYS.has(normalizedQueryKey(key)))
|
|
86
|
+
continue;
|
|
87
|
+
found = true;
|
|
88
|
+
if (value)
|
|
89
|
+
values?.add(value);
|
|
90
|
+
}
|
|
91
|
+
return found;
|
|
92
|
+
}
|
|
93
|
+
function addEncodedCredentialVariants(rawValue, values) {
|
|
94
|
+
if (!rawValue || !values)
|
|
95
|
+
return;
|
|
96
|
+
values.add(rawValue);
|
|
97
|
+
let decoded;
|
|
98
|
+
try {
|
|
99
|
+
decoded = decodeURIComponent(rawValue.replaceAll("+", " "));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (!decoded)
|
|
105
|
+
return;
|
|
106
|
+
values.add(decoded);
|
|
107
|
+
const encoded = encodeURIComponent(decoded);
|
|
108
|
+
values.add(encoded);
|
|
109
|
+
values.add(encoded.replaceAll("%20", "+"));
|
|
110
|
+
values.add(encoded.replace(/%[0-9A-F]{2}/g, (sequence) => sequence.toLowerCase()));
|
|
111
|
+
}
|
|
112
|
+
function collectEncodedCredentialParameters(raw, values) {
|
|
113
|
+
let found = false;
|
|
114
|
+
for (const part of raw.split("&")) {
|
|
115
|
+
const separator = part.indexOf("=");
|
|
116
|
+
if (separator < 0)
|
|
117
|
+
continue;
|
|
118
|
+
const rawKey = part.slice(0, separator);
|
|
119
|
+
const rawValue = part.slice(separator + 1);
|
|
120
|
+
let key = rawKey;
|
|
121
|
+
try {
|
|
122
|
+
key = decodeURIComponent(rawKey.replaceAll("+", " "));
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Keep the raw key so malformed credential-shaped input still fails closed.
|
|
126
|
+
}
|
|
127
|
+
if (!SIGNED_QUERY_KEYS.has(normalizedQueryKey(key)))
|
|
128
|
+
continue;
|
|
129
|
+
found = true;
|
|
130
|
+
addEncodedCredentialVariants(rawValue, values);
|
|
131
|
+
}
|
|
132
|
+
return found;
|
|
133
|
+
}
|
|
134
|
+
function collectCredentialFragment(fragment, values) {
|
|
135
|
+
const directDecoded = fragment.includes("=") && collectCredentialParameters(new URLSearchParams(fragment), values);
|
|
136
|
+
const directEncoded = fragment.includes("=") && collectEncodedCredentialParameters(fragment, values);
|
|
137
|
+
let found = directDecoded || directEncoded;
|
|
138
|
+
const nestedQuery = fragment.indexOf("?");
|
|
139
|
+
if (nestedQuery >= 0) {
|
|
140
|
+
const query = fragment.slice(nestedQuery + 1);
|
|
141
|
+
const decoded = collectCredentialParameters(new URLSearchParams(query), values);
|
|
142
|
+
const encoded = collectEncodedCredentialParameters(query, values);
|
|
143
|
+
found = decoded || encoded || found;
|
|
144
|
+
}
|
|
145
|
+
return found;
|
|
146
|
+
}
|
|
147
|
+
function inspectCredentialBearingUrl(value, values) {
|
|
148
|
+
const trimmed = value.trim();
|
|
149
|
+
if (!trimmed)
|
|
150
|
+
return false;
|
|
151
|
+
try {
|
|
152
|
+
const url = new URL(trimmed);
|
|
153
|
+
let found = false;
|
|
154
|
+
for (const userInfo of [url.username, url.password]) {
|
|
155
|
+
if (!userInfo)
|
|
156
|
+
continue;
|
|
157
|
+
found = true;
|
|
158
|
+
values?.add(userInfo);
|
|
159
|
+
try {
|
|
160
|
+
values?.add(decodeURIComponent(userInfo));
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
values?.add(userInfo);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const decodedQuery = collectCredentialParameters(url.searchParams, values);
|
|
167
|
+
const encodedQuery = collectEncodedCredentialParameters(url.search.slice(1), values);
|
|
168
|
+
found = decodedQuery || encodedQuery || found;
|
|
169
|
+
return collectCredentialFragment(url.hash.slice(1), values) || found;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Fail closed for malformed URL-like values carrying the same credential shapes.
|
|
173
|
+
let found = /^[a-z][a-z0-9+.-]*:\/\/[^/\s?#]*@/i.test(trimmed);
|
|
174
|
+
const query = trimmed.indexOf("?");
|
|
175
|
+
const fragment = trimmed.indexOf("#");
|
|
176
|
+
if (query >= 0) {
|
|
177
|
+
const queryText = trimmed.slice(query + 1, fragment >= 0 ? fragment : undefined);
|
|
178
|
+
const decodedQuery = collectCredentialParameters(new URLSearchParams(queryText), values);
|
|
179
|
+
const encodedQuery = collectEncodedCredentialParameters(queryText, values);
|
|
180
|
+
found = decodedQuery || encodedQuery || found;
|
|
181
|
+
}
|
|
182
|
+
if (fragment >= 0) {
|
|
183
|
+
const fragmentText = trimmed.slice(fragment + 1);
|
|
184
|
+
found = collectCredentialFragment(fragmentText, values) || found;
|
|
185
|
+
}
|
|
186
|
+
return found;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Collect exact secrets plus decoded values embedded in credential-bearing URLs. */
|
|
190
|
+
export function collectSensitiveValues(rawValues) {
|
|
191
|
+
const values = new Set();
|
|
192
|
+
for (const value of rawValues) {
|
|
193
|
+
if (value === undefined || value.length === 0)
|
|
194
|
+
continue;
|
|
195
|
+
values.add(value);
|
|
196
|
+
const trimmed = value.trim();
|
|
197
|
+
if (inspectCredentialBearingUrl(value, values) && trimmed)
|
|
198
|
+
values.add(trimmed);
|
|
199
|
+
}
|
|
200
|
+
return [...values];
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Decide whether an allowlisted passthrough value may cross an output boundary.
|
|
204
|
+
* The name allowlist never overrides value inspection: URL userinfo and signed
|
|
205
|
+
* query credentials remain secret even under ordinarily non-secret names.
|
|
206
|
+
*/
|
|
207
|
+
export function isEnvPassthroughValueSafeToExpose(name, value) {
|
|
208
|
+
if (value === undefined)
|
|
209
|
+
return true;
|
|
210
|
+
const policy = ENV_PASSTHROUGH_REDACTION_POLICY[name];
|
|
211
|
+
if (!policy)
|
|
212
|
+
return false;
|
|
213
|
+
const classifiedPolicy = policy;
|
|
214
|
+
switch (classifiedPolicy) {
|
|
215
|
+
case "identifier":
|
|
216
|
+
case "path":
|
|
217
|
+
case "url":
|
|
218
|
+
return !inspectCredentialBearingUrl(value);
|
|
219
|
+
default: {
|
|
220
|
+
const exhaustive = classifiedPolicy;
|
|
221
|
+
return exhaustive;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function utf8SequenceLength(firstByte) {
|
|
226
|
+
if (firstByte <= 0x7f)
|
|
227
|
+
return 1;
|
|
228
|
+
if (firstByte >= 0xc2 && firstByte <= 0xdf)
|
|
229
|
+
return 2;
|
|
230
|
+
if (firstByte >= 0xe0 && firstByte <= 0xef)
|
|
231
|
+
return 3;
|
|
232
|
+
if (firstByte >= 0xf0 && firstByte <= 0xf4)
|
|
233
|
+
return 4;
|
|
234
|
+
return 0;
|
|
235
|
+
}
|
|
236
|
+
function normalizeEncodedText(value, plusAsSpace) {
|
|
237
|
+
let text = "";
|
|
238
|
+
const starts = new Int32Array(value.length);
|
|
239
|
+
let mappingLength = 0;
|
|
240
|
+
const append = (decoded, start) => {
|
|
241
|
+
text += decoded;
|
|
242
|
+
for (let index = 0; index < decoded.length; index++) {
|
|
243
|
+
starts[mappingLength] = start;
|
|
244
|
+
mappingLength++;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
for (let index = 0; index < value.length;) {
|
|
248
|
+
if (value[index] === "%" && /^[0-9a-f]{2}$/i.test(value.slice(index + 1, index + 3))) {
|
|
249
|
+
const start = index;
|
|
250
|
+
const firstByte = Number.parseInt(value.slice(index + 1, index + 3), 16);
|
|
251
|
+
const sequenceLength = utf8SequenceLength(firstByte);
|
|
252
|
+
if (sequenceLength > 0) {
|
|
253
|
+
const bytes = [firstByte];
|
|
254
|
+
let cursor = index + 3;
|
|
255
|
+
while (bytes.length < sequenceLength &&
|
|
256
|
+
value[cursor] === "%" &&
|
|
257
|
+
/^[0-9a-f]{2}$/i.test(value.slice(cursor + 1, cursor + 3))) {
|
|
258
|
+
bytes.push(Number.parseInt(value.slice(cursor + 1, cursor + 3), 16));
|
|
259
|
+
cursor += 3;
|
|
260
|
+
}
|
|
261
|
+
if (bytes.length === sequenceLength) {
|
|
262
|
+
try {
|
|
263
|
+
const decoded = new TextDecoder("utf-8", { fatal: true }).decode(Uint8Array.from(bytes));
|
|
264
|
+
index = cursor;
|
|
265
|
+
append(decoded, start);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// Treat invalid UTF-8 percent sequences as literal text.
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const start = index;
|
|
275
|
+
const codePoint = value.codePointAt(index);
|
|
276
|
+
if (codePoint === undefined)
|
|
277
|
+
break;
|
|
278
|
+
const character = String.fromCodePoint(codePoint);
|
|
279
|
+
index += character.length;
|
|
280
|
+
append(plusAsSpace && character === "+" ? " " : character, start);
|
|
281
|
+
}
|
|
282
|
+
return { text, starts, sourceLength: value.length };
|
|
283
|
+
}
|
|
284
|
+
function addMappedMatches(coverageDelta, haystack, needle) {
|
|
285
|
+
if (!needle)
|
|
286
|
+
return;
|
|
287
|
+
let offset = 0;
|
|
288
|
+
while (offset <= haystack.text.length - needle.length) {
|
|
289
|
+
const match = haystack.text.indexOf(needle, offset);
|
|
290
|
+
if (match < 0)
|
|
291
|
+
break;
|
|
292
|
+
const start = haystack.starts[match];
|
|
293
|
+
const normalizedEnd = match + needle.length;
|
|
294
|
+
const end = normalizedEnd < haystack.text.length ? haystack.starts[normalizedEnd] : haystack.sourceLength;
|
|
295
|
+
coverageDelta[start] = coverageDelta[start] + 1;
|
|
296
|
+
coverageDelta[end] = coverageDelta[end] - 1;
|
|
297
|
+
offset = match + Math.max(needle.length, 1);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Redact credential-shaped substrings from arbitrary text by pattern alone —
|
|
302
|
+
* unlike {@link redactSensitiveText}, which requires the exact secret value
|
|
303
|
+
* up front, this catches credentials no caller ever knew to list. No
|
|
304
|
+
* truncation is applied; callers that need a length cap (e.g.
|
|
305
|
+
* {@link redactErrorBody} in src/llm/client.ts) apply it themselves.
|
|
306
|
+
*
|
|
307
|
+
* Targets:
|
|
308
|
+
* - `Bearer <token>` headers echoed back by a provider
|
|
309
|
+
* - `sk-…` / `sk_…` style API keys (OpenAI / Anthropic-shaped)
|
|
310
|
+
* - `key-…` / `key_…` shorthand keys
|
|
311
|
+
* - `"api_key": "…"` / `"apiKey": "…"` JSON fields
|
|
312
|
+
* - Discord webhook URLs (`discord.com/api/webhooks/<id>/<token>`) — the id
|
|
313
|
+
* is kept, only the token segment is redacted
|
|
314
|
+
* - Slack incoming-webhook URLs (`hooks.slack.com/services/<team>/<channel>/<token>`)
|
|
315
|
+
* — the team/channel ids are kept, only the trailing token is redacted
|
|
316
|
+
*/
|
|
317
|
+
export function redactCredentialPatterns(input) {
|
|
318
|
+
if (!input)
|
|
319
|
+
return "";
|
|
320
|
+
return (input
|
|
321
|
+
// Bearer tokens (case-insensitive)
|
|
322
|
+
.replace(/\bBearer\s+[A-Za-z0-9._\-+/=]+/gi, "Bearer [REDACTED]")
|
|
323
|
+
// sk-/sk_ style keys
|
|
324
|
+
.replace(/\bsk[-_][A-Za-z0-9._-]{6,}/g, "[REDACTED]")
|
|
325
|
+
// key-/key_ shorthand keys
|
|
326
|
+
.replace(/\bkey[-_][A-Za-z0-9._-]{6,}/g, "[REDACTED]")
|
|
327
|
+
// JSON-style "api_key": "...", "apiKey": "...", "api-key": "..."
|
|
328
|
+
.replace(/("(?:api[_-]?key|apiKey|authorization|token)"\s*:\s*")([^"]*)(")/gi, "$1[REDACTED]$3")
|
|
329
|
+
// Discord webhook URLs: keep the webhook id, redact the token segment.
|
|
330
|
+
.replace(/(discord(?:app)?\.com\/api\/webhooks\/\d+\/)[A-Za-z0-9_-]+/gi, "$1[REDACTED]")
|
|
331
|
+
// Slack incoming-webhook URLs: keep the team/channel ids, redact the token.
|
|
332
|
+
.replace(/(hooks\.slack\.com\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/)[A-Za-z0-9]+/gi, "$1[REDACTED]"));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Replace exact sensitive values in text. Longer values are replaced first so
|
|
336
|
+
* an overlapping prefix cannot expose the suffix of a longer credential.
|
|
337
|
+
*/
|
|
338
|
+
export function redactSensitiveText(text, sensitiveValues) {
|
|
339
|
+
const values = [...new Set(sensitiveValues)]
|
|
340
|
+
.filter((value) => value.length > 0)
|
|
341
|
+
.sort((a, b) => b.length - a.length || a.localeCompare(b));
|
|
342
|
+
if (values.length === 0)
|
|
343
|
+
return text;
|
|
344
|
+
if (!text.includes("%") && !text.includes("+")) {
|
|
345
|
+
let redacted = text;
|
|
346
|
+
for (const value of values)
|
|
347
|
+
redacted = redacted.replaceAll(value, "[REDACTED]");
|
|
348
|
+
return redacted;
|
|
349
|
+
}
|
|
350
|
+
const coverageDelta = new Int32Array(text.length + 1);
|
|
351
|
+
const addMatchesForMode = (plusAsSpace) => {
|
|
352
|
+
const haystack = normalizeEncodedText(text, plusAsSpace);
|
|
353
|
+
for (const value of values) {
|
|
354
|
+
addMappedMatches(coverageDelta, haystack, normalizeEncodedText(value, plusAsSpace).text);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
addMatchesForMode(false);
|
|
358
|
+
if (text.includes("+"))
|
|
359
|
+
addMatchesForMode(true);
|
|
360
|
+
let redacted = "";
|
|
361
|
+
let coverage = 0;
|
|
362
|
+
let offset = 0;
|
|
363
|
+
let found = false;
|
|
364
|
+
for (let index = 0; index <= text.length; index++) {
|
|
365
|
+
const wasCovered = coverage > 0;
|
|
366
|
+
coverage += coverageDelta[index];
|
|
367
|
+
const isCovered = coverage > 0;
|
|
368
|
+
if (!wasCovered && isCovered) {
|
|
369
|
+
redacted += `${text.slice(offset, index)}[REDACTED]`;
|
|
370
|
+
found = true;
|
|
371
|
+
}
|
|
372
|
+
else if (wasCovered && !isCovered) {
|
|
373
|
+
offset = index;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return found ? redacted + text.slice(offset) : text;
|
|
377
|
+
}
|
|
378
|
+
/** Recursively redact string leaves before a structured value crosses a durable/output boundary. */
|
|
379
|
+
export function redactSensitiveValue(value, sensitiveValues) {
|
|
380
|
+
const values = [...sensitiveValues];
|
|
381
|
+
const redact = (entry) => {
|
|
382
|
+
if (typeof entry === "string")
|
|
383
|
+
return redactSensitiveText(entry, values);
|
|
384
|
+
if (Array.isArray(entry))
|
|
385
|
+
return entry.map(redact);
|
|
386
|
+
if (entry && typeof entry === "object") {
|
|
387
|
+
return Object.fromEntries(Object.entries(entry).map(([key, child]) => [redactSensitiveText(key, values), redact(child)]));
|
|
388
|
+
}
|
|
389
|
+
return entry;
|
|
390
|
+
};
|
|
391
|
+
return redact(value);
|
|
392
|
+
}
|