akm-cli 0.9.0-rc.1 → 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 +1190 -52
- 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/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 +13 -9
- package/dist/commands/env/env-cli.js +76 -159
- 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/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 +75 -228
- 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 -855
- 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/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 -73
- 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 -58
- 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 +8 -3
- package/dist/integrations/agent/profiles.js +6 -99
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +78 -13
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +48 -279
- package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
- package/dist/integrations/harnesses/aider/index.js +2 -12
- package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
- package/dist/integrations/harnesses/amazonq/index.js +3 -17
- package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +1 -14
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
- package/dist/integrations/harnesses/codex/index.js +2 -13
- package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
- package/dist/integrations/harnesses/copilot/index.js +1 -13
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
- package/dist/integrations/harnesses/gemini/index.js +1 -13
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +31 -33
- 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 +1 -18
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
- package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
- package/dist/integrations/harnesses/openhands/index.js +2 -12
- package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
- package/dist/integrations/harnesses/pi/index.js +3 -16
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +38 -34
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +24 -40
- 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 +15 -281
- 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 +8 -40
- 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 -1375
- 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 +1 -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 +68 -35
- 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/workflows/authoring/authoring.js +96 -148
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -20
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +25 -59
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +157 -94
- package/dist/workflows/exec/report.js +365 -200
- package/dist/workflows/exec/run-workflow.js +46 -40
- package/dist/workflows/exec/scheduler.js +12 -41
- package/dist/workflows/exec/step-work.js +239 -205
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/ir/compile.js +141 -283
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/plan-hash.js +40 -5
- package/dist/workflows/ir/schema.js +537 -1
- package/dist/workflows/parser.js +878 -306
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +99 -121
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +200 -113
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +4 -26
- 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/{dist/schemas → schemas}/akm-workflow.json +127 -82
- 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 -316
- 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 -1414
- 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 -25
- 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/schemas/akm-config.json +0 -14225
- package/dist/scripts/migrate-storage.js +0 -13169
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
- 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/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/db.js +0 -350
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -760
- package/dist/workflows/program/project.js +0 -105
- package/docs/data-and-telemetry.md +0 -227
- package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
|
@@ -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
|
+
}
|
|
@@ -2,86 +2,57 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* Dispatch resolver for the standards prompt seam
|
|
6
|
-
* standards features fires for a given write target, mutually exclusively:
|
|
5
|
+
* Dispatch resolver for the standards prompt seam.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* missing/malformed input and never throw, so this resolver never throws.
|
|
7
|
+
* The wiki `schema.md` injection (former "Feature A") was collapsed in chunk 4
|
|
8
|
+
* with the wiki asset-type death (plan §11 Chunk 4): LLM Wiki content is served
|
|
9
|
+
* by the `llm-wiki` adapter, which owns its own `schema.md` contract. What
|
|
10
|
+
* remains is **stash standards**: for any write target, return the concatenated
|
|
11
|
+
* `category: convention`/`meta` fact bodies plus the per-type SOFT conventions
|
|
12
|
+
* layer (#646), type-scoped to the write target. The underlying readers degrade
|
|
13
|
+
* to `""` on missing/malformed input and never throw, so this resolver never
|
|
14
|
+
* throws.
|
|
17
15
|
*/
|
|
18
|
-
import {
|
|
16
|
+
import { typeNameFromConceptId } from "../asset/resolve-ref.js";
|
|
19
17
|
import { resolveStashStandards } from "./resolve-stash-standards.js";
|
|
20
18
|
import { resolveTypeConventions, typeConventionRef } from "./resolve-type-conventions.js";
|
|
21
|
-
/** Wiki infra files that are not authored pages (relative to the wiki root). */
|
|
22
|
-
const WIKI_INFRA_BASENAMES = new Set([SCHEMA_MD, INDEX_MD, LOG_MD]);
|
|
23
19
|
/**
|
|
24
|
-
* Extract the asset type from a
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
20
|
+
* Extract the asset type from a write-target ref without throwing. Returns
|
|
21
|
+
* `undefined` for refs that carry no recognizable type. Kept local and lenient —
|
|
22
|
+
* the per-type resolver validates the result against `placementTypes()`, so a
|
|
23
|
+
* bogus prefix here simply yields no convention.
|
|
28
24
|
*/
|
|
29
25
|
function refType(ref) {
|
|
30
26
|
if (!ref)
|
|
31
27
|
return undefined;
|
|
32
28
|
const body = ref.includes("//") ? ref.slice(ref.indexOf("//") + 2) : ref;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return body.slice(0, colon).trim() || undefined;
|
|
29
|
+
// 0.9.0 conceptId `<stash-subdir>/<name>`: delegate to the D-R2 reverse table
|
|
30
|
+
// so the leading stash subdir maps back to its asset type (the canonical path).
|
|
31
|
+
return typeNameFromConceptId(body)?.type;
|
|
37
32
|
}
|
|
38
33
|
/**
|
|
39
34
|
* Resolve the standards context for a write target identified by its asset ref.
|
|
40
35
|
*
|
|
41
|
-
* @param ref Canonical asset ref of the write target (e.g. `
|
|
42
|
-
*
|
|
43
|
-
* non-wiki authoring flow → stash standards.
|
|
36
|
+
* @param ref Canonical asset ref of the write target (e.g. `skills/foo`).
|
|
37
|
+
* When undefined, the target is a general authoring flow.
|
|
44
38
|
* @param stashRoot Stash root directory.
|
|
45
39
|
*/
|
|
46
40
|
export function resolveStandardsContext(ref, stashRoot) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
].join("\n");
|
|
65
|
-
return general ? `${general}\n\n${softSection}` : softSection;
|
|
66
|
-
}
|
|
67
|
-
// Wiki target. Extract the page path after `wiki:<name>/`.
|
|
68
|
-
const prefix = `wiki:${wikiName}/`;
|
|
69
|
-
const pagePath = ref?.startsWith(prefix) ? ref.slice(prefix.length) : "";
|
|
70
|
-
// `wiki:<name>` with no page, a `raw/` file, or a wiki infra file → neither
|
|
71
|
-
// feature fires.
|
|
72
|
-
if (!pagePath)
|
|
73
|
-
return "";
|
|
74
|
-
if (pagePath === "raw" || pagePath.startsWith("raw/"))
|
|
75
|
-
return "";
|
|
76
|
-
// Infra files (`schema`/`index`/`log`) are only special at the WIKI ROOT.
|
|
77
|
-
// A nested page like `wiki:research/analysis/schema` is a genuine page and
|
|
78
|
-
// must NOT be suppressed, so only check when the page is at root depth.
|
|
79
|
-
if (!pagePath.includes("/")) {
|
|
80
|
-
// Refs drop the `.md` extension; compare against both forms defensively.
|
|
81
|
-
if (WIKI_INFRA_BASENAMES.has(pagePath) || WIKI_INFRA_BASENAMES.has(`${pagePath}.md`)) {
|
|
82
|
-
return "";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// A genuine wiki page → Feature A (that wiki's schema body).
|
|
86
|
-
return loadWikiSchema(stashRoot, wikiName).body;
|
|
41
|
+
// General stash standards plus the per-type SOFT conventions layer (#646),
|
|
42
|
+
// type-scoped to the write target.
|
|
43
|
+
const general = resolveStashStandards(stashRoot);
|
|
44
|
+
const type = refType(ref);
|
|
45
|
+
// A non-empty body here guarantees `type` is a `placementTypes()`-validated
|
|
46
|
+
// string (the resolver returns "" otherwise).
|
|
47
|
+
const typeConventions = type ? resolveTypeConventions(stashRoot, type) : "";
|
|
48
|
+
if (!typeConventions || !type)
|
|
49
|
+
return general;
|
|
50
|
+
// Soft, type-scoped guidance — clearly labeled and kept separate from the
|
|
51
|
+
// HARD (validator-enforced) rules that `authoringRulesForType` injects
|
|
52
|
+
// downstream. These facts are advice only; they never weaken the gate.
|
|
53
|
+
const softSection = [
|
|
54
|
+
`# ${typeConventionRef(type)} (soft per-type conventions — guidance, not enforced)`,
|
|
55
|
+
typeConventions,
|
|
56
|
+
].join("\n");
|
|
57
|
+
return general ? `${general}\n\n${softSection}` : softSection;
|
|
87
58
|
}
|
|
@@ -53,14 +53,14 @@ function collectMarkdownFiles(dir) {
|
|
|
53
53
|
return results;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Derive a fact ref (`
|
|
56
|
+
* Derive a fact ref (`facts/conventions/naming`) from an absolute markdown path
|
|
57
57
|
* relative to the facts root. Mirrors the canonical-name derivation in
|
|
58
58
|
* `asset-spec.ts` (POSIX separators, `.md` stripped).
|
|
59
59
|
*/
|
|
60
60
|
function toFactRef(factsRoot, absPath) {
|
|
61
61
|
const rel = path.relative(factsRoot, absPath).split(path.sep).join("/");
|
|
62
62
|
const name = rel.endsWith(".md") ? rel.slice(0, -3) : rel;
|
|
63
|
-
return
|
|
63
|
+
return `${FACTS_SUBDIR}/${name}`;
|
|
64
64
|
}
|
|
65
65
|
export function resolveStashStandards(stashRoot) {
|
|
66
66
|
const factsRoot = path.join(stashRoot, FACTS_SUBDIR);
|