akm-cli 0.9.0-rc.8 → 0.9.0
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 +1063 -44
- package/README.md +51 -25
- package/SECURITY.md +14 -1
- package/STABILITY.md +497 -0
- package/dist/akm +148 -35
- package/dist/{akm-migrate-storage → akm-migrate} +6 -9
- package/dist/assets/hints/cli-hints-full.md +223 -95
- package/dist/assets/hints/cli-hints-short.md +85 -22
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/stash-skeleton/README.md +6 -5
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
- package/dist/assets/tasks/core/extract.yml +1 -1
- package/dist/assets/tasks/core/version-check.yml +1 -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 +1 -3
- package/dist/assets/workflows/workflow-template.md +32 -15
- package/dist/cli/invocation.js +40 -15
- package/dist/cli/parse-args.js +0 -22
- package/dist/cli/retired-commands.js +121 -0
- package/dist/cli/shared.js +154 -22
- package/dist/cli/unknown-flags.js +236 -0
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +696 -258
- package/dist/commands/agent/agent-dispatch.js +14 -3
- package/dist/commands/agent/contribute-cli.js +73 -88
- package/dist/commands/completions.js +79 -22
- package/dist/commands/config-cli.js +17 -150
- package/dist/commands/env/env-cli.js +59 -143
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +36 -66
- package/dist/commands/env/secret.js +24 -57
- package/dist/commands/feedback-cli.js +141 -87
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +3 -4
- package/dist/commands/health/checks.js +85 -23
- package/dist/commands/health/html-report.js +7 -10
- package/dist/commands/health/improve-metrics.js +25 -83
- package/dist/commands/health/md-report.js +5 -9
- package/dist/commands/health/metrics.js +62 -20
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +4 -5
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +3 -48
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/commands/health/types-improve.js +7 -0
- package/dist/commands/health.js +99 -28
- package/dist/commands/improve/anti-collapse.js +2 -2
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +41 -40
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +140 -1000
- package/dist/commands/improve/distill/promote-memory.js +12 -12
- package/dist/commands/improve/distill/quality-gate.js +6 -6
- package/dist/commands/improve/distill.js +58 -69
- package/dist/commands/improve/eligibility.js +105 -57
- package/dist/commands/improve/extract-cli.js +14 -133
- package/dist/commands/improve/improve-cli.js +98 -114
- package/dist/commands/improve/improve-result-file.js +1 -28
- package/dist/commands/improve/improve-strategies.js +8 -5
- package/dist/commands/improve/improve.js +128 -91
- package/dist/commands/improve/loop-stages.js +182 -20
- package/dist/commands/improve/memory/derived-ref.js +45 -43
- package/dist/commands/improve/memory/memory-belief.js +1 -1
- package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
- package/dist/commands/improve/memory/memory-improve.js +6 -5
- package/dist/commands/improve/outcome-loop.js +22 -65
- package/dist/commands/improve/preparation.js +114 -123
- package/dist/commands/improve/proactive-maintenance.js +2 -5
- package/dist/commands/improve/reflect.js +56 -160
- package/dist/commands/improve/salience.js +11 -122
- package/dist/commands/improve/source-identity.js +10 -38
- package/dist/commands/lint/base-linter.js +20 -124
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +249 -43
- package/dist/commands/{events.js → log.js} +33 -38
- package/dist/commands/migrate-cli.js +92 -12
- package/dist/commands/migration-tool.js +46 -0
- package/dist/commands/observability-cli.js +70 -209
- package/dist/commands/proposal/drain.js +101 -29
- package/dist/commands/proposal/proposal-cli.js +76 -48
- package/dist/commands/proposal/proposal.js +54 -18
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +23 -15
- package/dist/commands/proposal/repository.js +701 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
- package/dist/commands/proposal/validators/proposal-validators.js +55 -7
- package/dist/commands/proposal/validators/proposals.js +4 -7
- package/dist/commands/read/curate.js +34 -53
- package/dist/commands/read/knowledge.js +150 -95
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +42 -15
- package/dist/commands/read/search-cli.js +180 -78
- package/dist/commands/read/search.js +58 -43
- package/dist/commands/read/show.js +197 -141
- package/dist/commands/registry-cli.js +12 -51
- package/dist/commands/remember.js +14 -57
- package/dist/commands/sources/add-cli.js +100 -31
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +7 -2
- package/dist/commands/sources/info.js +18 -5
- package/dist/commands/sources/init.js +12 -12
- package/dist/commands/sources/installed-stashes.js +382 -98
- package/dist/commands/sources/schema-repair.js +3 -2
- package/dist/commands/sources/self-update.js +131 -38
- package/dist/commands/sources/source-add.js +72 -17
- package/dist/commands/sources/source-clone.js +129 -45
- package/dist/commands/sources/source-manage.js +43 -23
- package/dist/commands/sources/sources-cli.js +57 -208
- package/dist/commands/sources/stash-cli.js +46 -53
- package/dist/commands/tasks/tasks-cli.js +91 -97
- package/dist/commands/tasks/tasks.js +276 -421
- package/dist/commands/workflow-cli.js +175 -450
- package/dist/core/adapter/adapters/akm-adapter.js +47 -28
- package/dist/core/adapter/adapters/akm-lint.js +42 -27
- package/dist/core/adapter/adapters/akm-metadata.js +15 -44
- package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
- package/dist/core/adapter/adapters/index.js +6 -6
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
- package/dist/core/adapter/adapters/okf-adapter.js +187 -19
- package/dist/core/adapter/adapters/shared.js +3 -19
- package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +6 -4
- package/dist/core/adapter/validate-context.js +214 -0
- package/dist/core/asset/akm-markdown.js +63 -0
- package/dist/core/asset/asset-placement.js +20 -6
- package/dist/core/asset/asset-ref.js +11 -9
- package/dist/core/asset/frontmatter-lint.js +30 -0
- package/dist/core/asset/frontmatter.js +37 -9
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +89 -18
- package/dist/core/asset/stash-meta.js +1 -1
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +152 -38
- package/dist/core/config/config-io.js +12 -1
- package/dist/core/config/config-schema.js +35 -8
- package/dist/core/config/config-sources.js +55 -11
- package/dist/core/config/config-walker.js +25 -9
- package/dist/core/config/config.js +9 -48
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +5 -1
- package/dist/core/config/schema/experimental.js +30 -0
- package/dist/core/config/schema/improve-processes.js +0 -6
- package/dist/core/config/schema/improve.js +21 -3
- package/dist/core/config/schema/index-config.js +8 -15
- package/dist/core/config/schema/output.js +4 -1
- package/dist/core/config/schema/setup.js +9 -18
- package/dist/core/config/schema/sources-bundles.js +49 -33
- package/dist/core/config/schema/workflow.js +3 -3
- package/dist/core/env-secret-ref.js +76 -46
- package/dist/core/errors.js +18 -12
- package/dist/core/events.js +46 -128
- package/dist/core/file-change.js +6 -5
- package/dist/core/fs-txn.js +83 -7
- package/dist/core/git-message.js +2 -2
- package/dist/core/improve-result.js +1 -100
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +2 -1
- package/dist/core/migration-operation.js +16 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/parse.js +4 -1
- package/dist/core/paths.js +17 -20
- package/dist/core/recognition-util.js +12 -14
- package/dist/core/redaction.js +34 -0
- package/dist/core/standards/resolve-standards-context.js +2 -14
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +2 -2
- package/dist/core/state/migrations.js +41 -18
- package/dist/core/state-db.js +5 -14
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +6 -4
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/type-presentation.js +3 -3
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +771 -95
- package/dist/indexer/bundle-identity-guard.js +3 -2
- package/dist/indexer/db/graph-db.js +0 -24
- package/dist/indexer/ensure-index.js +1 -0
- package/dist/indexer/graph/graph-boost.js +9 -34
- package/dist/indexer/graph/graph-extraction.js +8 -5
- package/dist/indexer/index-writer-lock.js +53 -17
- package/dist/indexer/index-written-assets.js +16 -22
- package/dist/indexer/indexer.js +497 -239
- package/dist/indexer/installations.js +14 -96
- package/dist/indexer/passes/dir-staleness.js +16 -9
- package/dist/indexer/passes/memory-inference.js +11 -9
- package/dist/indexer/passes/metadata.js +113 -47
- package/dist/indexer/scan/doc-to-entry.js +38 -1
- package/dist/indexer/scan/drain-dir.js +13 -23
- package/dist/indexer/search/db-search.js +99 -54
- package/dist/indexer/search/fts-query.js +47 -24
- package/dist/indexer/search/ranking-contributors.js +42 -20
- package/dist/indexer/search/ranking.js +18 -99
- package/dist/indexer/search/search-fields.js +7 -2
- package/dist/indexer/search/search-source.js +82 -93
- package/dist/indexer/usage/usage-events.js +0 -89
- package/dist/indexer/walk/file-context.js +2 -1
- package/dist/indexer/walk/matchers.js +30 -43
- package/dist/indexer/walk/path-resolver.js +7 -2
- package/dist/indexer/walk/walker.js +38 -12
- package/dist/integrations/agent/builders.js +0 -6
- package/dist/integrations/agent/config.js +2 -2
- package/dist/integrations/agent/detect.js +49 -19
- package/dist/integrations/agent/engine-fallback.js +76 -0
- package/dist/integrations/agent/profiles.js +14 -0
- package/dist/integrations/agent/prompts.js +12 -8
- package/dist/integrations/agent/runner-dispatch.js +4 -2
- package/dist/integrations/agent/runner.js +0 -1
- package/dist/integrations/agent/spawn.js +5 -6
- package/dist/integrations/github.js +1 -1
- package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
- package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
- package/dist/integrations/harnesses/claude/session-log.js +0 -10
- package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
- package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
- package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
- package/dist/integrations/harnesses/index.js +3 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
- package/dist/integrations/harnesses/opencode/session-log.js +0 -15
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
- package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
- package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
- package/dist/integrations/lockfile.js +101 -6
- package/dist/integrations/session-logs/index.js +3 -28
- package/dist/llm/client.js +136 -100
- package/dist/llm/embedders/remote.js +13 -5
- package/dist/llm/feature-gate.js +4 -12
- package/dist/llm/graph-extract.js +5 -11
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +5 -7
- package/dist/llm/structured-call.js +1 -1
- package/dist/llm/usage-persist.js +26 -5
- package/dist/llm/usage-telemetry.js +25 -2
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +259 -0
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -36
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +56 -83
- package/dist/output/shapes/migrate.js +8 -0
- package/dist/output/shapes/passthrough.js +7 -41
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes.js +2 -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 +164 -96
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/health-format.js +103 -0
- package/dist/output/text/health.js +7 -0
- package/dist/output/text/helpers.js +10 -8
- package/dist/output/text/lint-format.js +43 -0
- package/dist/output/text/{save.js → lint.js} +2 -2
- package/dist/output/text/migrate.js +88 -0
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +44 -72
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +15 -7
- package/dist/output/text/status-list.js +32 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +24 -203
- package/dist/output/text/workflow.js +1 -7
- package/dist/output/text.js +16 -17
- 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 +13 -23
- package/dist/registry/resolve.js +42 -7
- package/dist/registry/semver.js +34 -84
- package/dist/runtime.js +2 -23
- package/dist/scripts/akm-migrate-node.js +60290 -0
- package/dist/scripts/akm-migrate.js +59628 -0
- package/dist/setup/detect.js +42 -15
- package/dist/setup/registry-stash-loader.js +2 -2
- package/dist/setup/setup.js +236 -136
- package/dist/setup/steps/connection.js +7 -9
- package/dist/setup/steps/platforms.js +9 -9
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +12 -13
- package/dist/setup/steps/stashdir.js +2 -3
- package/dist/setup/steps/tasks.js +237 -120
- package/dist/sources/freshness.js +1 -1
- 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 +25 -23
- package/dist/sources/providers/git-stash.js +395 -106
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +7 -4
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +6 -1
- package/dist/sources/resolve.js +6 -5
- package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
- package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
- package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
- package/dist/sources/snapshot-fetchers/github.js +100 -0
- package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
- package/dist/sources/snapshot-fetchers/registry.js +17 -1
- package/dist/sources/snapshot-fetchers/robots.js +348 -0
- package/dist/sources/snapshot-fetchers/rss.js +282 -0
- package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
- package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
- package/dist/sources/snapshot-fetchers/x.js +910 -0
- package/dist/storage/database.js +7 -0
- package/dist/storage/engines/sqlite-migrations.js +23 -111
- package/dist/storage/managed-db.js +2 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +27 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -12
- package/dist/storage/repositories/index-connection.js +17 -6
- package/dist/storage/repositories/index-entries-repository.js +151 -240
- package/dist/storage/repositories/index-entry-mapper.js +15 -11
- package/dist/storage/repositories/index-fts-repository.js +5 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
- package/dist/storage/repositories/index-meta-repository.js +2 -3
- package/dist/storage/repositories/index-schema.js +10 -25
- package/dist/storage/repositories/index-utility-repository.js +15 -28
- package/dist/storage/repositories/index-vec-repository.js +6 -1
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +296 -59
- package/dist/storage/repositories/registry-cache.js +19 -0
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +15 -13
- package/dist/storage/repositories/workflow-runs-repository.js +52 -40
- package/dist/tasks/backends/cron.js +105 -15
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +85 -38
- package/dist/tasks/backends/schtasks.js +135 -15
- package/dist/tasks/embedded.js +56 -40
- package/dist/tasks/parser.js +7 -157
- package/dist/tasks/resolve-akm-bin.js +137 -59
- package/dist/tasks/runner.js +79 -42
- package/dist/tasks/scheduler-invocation.js +220 -10
- package/dist/tasks/schema.js +24 -1
- package/dist/tasks/task-id.js +1 -3
- package/dist/tasks/validator.js +20 -6
- package/dist/workflows/authoring/authoring.js +94 -143
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/exec/frozen-judge.js +28 -2
- package/dist/workflows/exec/native-executor.js +77 -57
- package/dist/workflows/exec/param-secrets.js +9 -9
- package/dist/workflows/exec/run-workflow.js +133 -79
- package/dist/workflows/exec/step-work.js +219 -346
- package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
- package/dist/workflows/ir/compile.js +141 -270
- package/dist/workflows/ir/freeze.js +40 -30
- package/dist/workflows/ir/params.js +135 -11
- package/dist/workflows/ir/plan-hash.js +1 -1
- package/dist/workflows/ir/schema.js +25 -26
- package/dist/workflows/parser.js +872 -307
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +95 -68
- package/dist/workflows/resource-limits.js +2 -0
- package/dist/workflows/runtime/checkin.js +3 -3
- package/dist/workflows/runtime/plan-classifier.js +16 -75
- package/dist/workflows/runtime/runs.js +186 -127
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +2 -2
- package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +30 -36
- package/dist/workflows/validator.js +21 -62
- package/docs/README.md +68 -0
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.7.0.md +11 -11
- package/docs/migration/release-notes/0.9.0.md +208 -27
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +564 -208
- package/docs/migration/v0.9.0-troubleshooting.md +561 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/cli.md +2253 -0
- package/docs/reference/configuration.md +358 -0
- package/docs/reference/data-and-telemetry.md +105 -42
- package/docs/reference/workflows.md +647 -0
- package/package.json +22 -11
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +81 -128
- package/schemas/akm-workflow.json +74 -73
- package/dist/assets/tasks/core/backup.yml +0 -5
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/cli/config-migrate.js +0 -1806
- package/dist/cli/config-validate.js +0 -41
- package/dist/commands/backup-cli.js +0 -56
- package/dist/commands/bundle/bundle-cli.js +0 -68
- package/dist/commands/bundle/bundle.js +0 -219
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -489
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/mv-cli.js +0 -1221
- package/dist/commands/sources/history.js +0 -201
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/core/migration-backup.js +0 -1234
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/migrate/legacy/config-source-migration.js +0 -223
- package/dist/migrate/legacy/content-migration.js +0 -305
- package/dist/migrate/legacy/legacy-layout.js +0 -779
- package/dist/migrate/legacy/legacy-paths.js +0 -25
- package/dist/migrate/legacy/legacy-stash-json.js +0 -72
- package/dist/migrate/legacy/proposal-fs-import.js +0 -168
- package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
- package/dist/migrate/legacy/three-db-cutover.js +0 -841
- package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
- package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
- package/dist/migrate/legacy-ref-grammar.js +0 -214
- 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/registry/build-index.js +0 -382
- package/dist/schemas/akm-config.json +0 -4704
- package/dist/schemas/akm-task.json +0 -87
- package/dist/schemas/akm-workflow.json +0 -372
- package/dist/scripts/migrate-storage.js +0 -3816
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/cli.js +0 -53
- package/dist/workflows/exec/brief.js +0 -481
- package/dist/workflows/exec/report.js +0 -1460
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -813
- package/dist/workflows/program/project.js +0 -104
|
@@ -4,27 +4,20 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* The `akm-workflow` adapter — akm 0.9.0 format-family work item (#46).
|
|
6
6
|
*
|
|
7
|
-
* A native akm workflow bundle (spec §6/§7).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* detected by `looksLikeWorkflowProgram`.
|
|
15
|
-
* conceptId strips the recognized workflow extension (`.md`/`.yaml`/`.yml`). A
|
|
16
|
-
* plain `.md` that is NOT workflow-shaped (a README, an OKF reserved listing/log
|
|
17
|
-
* file) is abstained on — the content probe subsumes the D-R6 reserved-file
|
|
18
|
-
* exclusion, so no reserved-basename literal is needed here.
|
|
7
|
+
* A native akm workflow bundle (spec §6/§7). One format now (workflow-format-
|
|
8
|
+
* unification): `.md` files, orchestration graph in frontmatter, per-step
|
|
9
|
+
* prose in the body. Recognition is frontmatter `type: workflow`, or — since
|
|
10
|
+
* this adapter's whole domain IS workflows — simply residing under this
|
|
11
|
+
* bundle's root; no content sniffing. conceptId strips the `.md` extension. A
|
|
12
|
+
* plain `.md` that opts out via an explicit non-workflow `type:` frontmatter
|
|
13
|
+
* key is abstained on.
|
|
19
14
|
*
|
|
20
15
|
* ── validate (spec §6 workflow row) ──
|
|
21
16
|
*
|
|
22
17
|
* Reuses the akm adapter's per-type workflow checks (shared base checks +
|
|
23
|
-
* `placeholder-stub` + `invalid-workflow-structure
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `runBaseValidateChecks` the `akm` adapter uses, so workflow validation has
|
|
27
|
-
* one home.
|
|
18
|
+
* `placeholder-stub` + `invalid-workflow-structure`). Delegates to the SAME
|
|
19
|
+
* `perTypeValidateChecks` / `runBaseValidateChecks` the `akm` adapter uses, so
|
|
20
|
+
* workflow validation has one home.
|
|
28
21
|
*
|
|
29
22
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
30
23
|
* `tests/fixtures/bundles/akm-workflow/` + goldens
|
|
@@ -32,60 +25,52 @@
|
|
|
32
25
|
*/
|
|
33
26
|
import fs from "node:fs";
|
|
34
27
|
import path from "node:path";
|
|
35
|
-
import { parse as parseYaml } from "yaml";
|
|
36
|
-
import { looksLikeWorkflow } from "../../../workflows/parser.js";
|
|
37
|
-
import { looksLikeWorkflowProgram } from "../../../workflows/program/parser.js";
|
|
38
28
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
39
29
|
import { perTypeValidateChecks } from "./akm-lint.js";
|
|
40
30
|
import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
|
|
41
31
|
/** A native workflow bundle is single-component; its one component is `main`. */
|
|
42
32
|
const COMPONENT_ID = "main";
|
|
43
|
-
/**
|
|
44
|
-
const WORKFLOW_EXTS = new Set([".md"
|
|
33
|
+
/** One recognized workflow extension now (workflow-format-unification): `.md`. */
|
|
34
|
+
const WORKFLOW_EXTS = new Set([".md"]);
|
|
45
35
|
/** Upper bound on the bounded `content` FTS field (mirrors okf-adapter). */
|
|
46
36
|
const MAX_CONTENT_CHARS = 100_000;
|
|
47
37
|
function toPosix(p) {
|
|
48
38
|
return p.replace(/\\/g, "/");
|
|
49
39
|
}
|
|
50
|
-
/** Strip
|
|
40
|
+
/** Strip the recognized workflow extension from a component-root-relative path → conceptId. */
|
|
51
41
|
function conceptIdOf(relPath) {
|
|
52
|
-
return toPosix(relPath).replace(/\.
|
|
42
|
+
return toPosix(relPath).replace(/\.md$/i, "");
|
|
53
43
|
}
|
|
54
|
-
/**
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
return looksLikeWorkflow(parseFrontmatter(raw).content) ? "markdown" : null;
|
|
58
|
-
if (ext === ".yaml" || ext === ".yml")
|
|
59
|
-
return looksLikeWorkflowProgram(raw) ? "yaml-program" : null;
|
|
60
|
-
return null;
|
|
44
|
+
/** `README.md` (case-insensitive) is documentation, never the typed asset — mirrors the akm matcher stack's D-R6 reserved-file exclusion (`TYPED_DIR_DOC_FILES`). */
|
|
45
|
+
function isReservedDocFile(fileName) {
|
|
46
|
+
return fileName.toLowerCase() === "readme.md";
|
|
61
47
|
}
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// malformed YAML — no description
|
|
74
|
-
}
|
|
75
|
-
return undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Recognition gate: any `.md` file in this bundle IS a workflow (this
|
|
50
|
+
* adapter's entire domain is workflows — spec §2.5, "residence under
|
|
51
|
+
* workflows/"), UNLESS its frontmatter declares a DIFFERENT non-empty
|
|
52
|
+
* `type:` (an explicit opt-out, e.g. a README-shaped doc that wants to be
|
|
53
|
+
* something else). No content sniffing.
|
|
54
|
+
*/
|
|
55
|
+
function isWorkflowFile(raw) {
|
|
56
|
+
const data = parseFrontmatter(raw).data;
|
|
57
|
+
const type = data.type;
|
|
58
|
+
return type === undefined || type === "workflow";
|
|
76
59
|
}
|
|
77
60
|
function recognize(c, file) {
|
|
78
61
|
if (!WORKFLOW_EXTS.has(file.ext))
|
|
79
62
|
return null;
|
|
63
|
+
if (isReservedDocFile(file.fileName))
|
|
64
|
+
return null;
|
|
80
65
|
const raw = file.content();
|
|
81
|
-
|
|
82
|
-
if (form === null)
|
|
66
|
+
if (!isWorkflowFile(raw))
|
|
83
67
|
return null;
|
|
84
68
|
const conceptId = conceptIdOf(file.relPath);
|
|
85
69
|
const name = conceptId.split("/").pop() ?? conceptId;
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
70
|
+
const parsed = parseFrontmatter(raw);
|
|
71
|
+
const description = nonEmptyString(parsed.data.description);
|
|
72
|
+
const body = parsed.content;
|
|
73
|
+
const tags = readTags(parsed.data.tags);
|
|
89
74
|
const doc = {
|
|
90
75
|
ref: `${c.id}//${conceptId}`,
|
|
91
76
|
bundle: c.id,
|
|
@@ -113,18 +98,11 @@ async function validate(c, changes, ctx) {
|
|
|
113
98
|
if (typeof raw !== "string")
|
|
114
99
|
continue;
|
|
115
100
|
const ext = path.extname(change.path).toLowerCase();
|
|
116
|
-
if (!WORKFLOW_EXTS.has(ext) ||
|
|
101
|
+
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path.basename(change.path)) || !isWorkflowFile(raw))
|
|
117
102
|
continue;
|
|
118
103
|
const relPath = toPosix(change.path);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (ext === ".md") {
|
|
122
|
-
const p = parseFrontmatter(raw);
|
|
123
|
-
parsed = { data: p.data, content: p.content, frontmatter: p.frontmatter };
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
parsed = { data: {}, content: raw, frontmatter: null };
|
|
127
|
-
}
|
|
104
|
+
const p = parseFrontmatter(raw);
|
|
105
|
+
const parsed = { data: p.data, content: p.content, frontmatter: p.frontmatter };
|
|
128
106
|
diagnostics.push(...(await runBaseValidateChecks(relPath, parsed, c.root, ctx)));
|
|
129
107
|
diagnostics.push(...(await perTypeValidateChecks({
|
|
130
108
|
type: "workflow",
|
|
@@ -139,13 +117,22 @@ async function validate(c, changes, ctx) {
|
|
|
139
117
|
}
|
|
140
118
|
return diagnostics;
|
|
141
119
|
}
|
|
142
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* True when a top-level file in `root` is workflow-shaped (used by
|
|
122
|
+
* looksLikeRoot). Unlike `isWorkflowFile` (which admits an absent `type:` —
|
|
123
|
+
* the lenient default ONCE a source is already known to be this bundle),
|
|
124
|
+
* this requires an EXPLICIT `type: workflow` — the install-time probe is
|
|
125
|
+
* choosing WHICH adapter owns an unconfigured root among several candidates
|
|
126
|
+
* (spec §1.2), and an incidental `.md` with no frontmatter type at all
|
|
127
|
+
* (common in an OKF or llm-wiki bundle) must not misclassify that root as
|
|
128
|
+
* akm-workflow's.
|
|
129
|
+
*/
|
|
143
130
|
function hasTopLevelWorkflowFile(root, entries) {
|
|
144
131
|
for (const entry of entries) {
|
|
145
132
|
if (!entry.isFile())
|
|
146
133
|
continue;
|
|
147
134
|
const ext = path.extname(entry.name).toLowerCase();
|
|
148
|
-
if (!WORKFLOW_EXTS.has(ext))
|
|
135
|
+
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(entry.name))
|
|
149
136
|
continue;
|
|
150
137
|
let raw;
|
|
151
138
|
try {
|
|
@@ -154,7 +141,7 @@ function hasTopLevelWorkflowFile(root, entries) {
|
|
|
154
141
|
catch {
|
|
155
142
|
continue;
|
|
156
143
|
}
|
|
157
|
-
if (
|
|
144
|
+
if (parseFrontmatter(raw).data.type === "workflow")
|
|
158
145
|
return true;
|
|
159
146
|
}
|
|
160
147
|
return false;
|
|
@@ -162,13 +149,13 @@ function hasTopLevelWorkflowFile(root, entries) {
|
|
|
162
149
|
export const akmWorkflowAdapter = {
|
|
163
150
|
id: "akm-workflow",
|
|
164
151
|
version: "0.9.0",
|
|
165
|
-
extensions: [".md"
|
|
152
|
+
extensions: [".md"],
|
|
166
153
|
recognize,
|
|
167
154
|
validate,
|
|
168
|
-
/**
|
|
155
|
+
/** Markdown placement; an explicit `.md` conceptId short-circuits to that extension. */
|
|
169
156
|
placeNew(c, conceptId) {
|
|
170
157
|
const posix = toPosix(conceptId);
|
|
171
|
-
if (/\.
|
|
158
|
+
if (/\.md$/i.test(posix))
|
|
172
159
|
return path.join(c.root, posix);
|
|
173
160
|
return path.join(c.root, `${posix}.md`);
|
|
174
161
|
},
|
|
@@ -177,11 +164,8 @@ export const akmWorkflowAdapter = {
|
|
|
177
164
|
return ["."];
|
|
178
165
|
},
|
|
179
166
|
/**
|
|
180
|
-
* Install-time probe (§1.2): a root holding a workflow file at
|
|
181
|
-
*
|
|
182
|
-
* content probe means an okf reserved listing, a wiki `schema.md`, or a README
|
|
183
|
-
* never trips it, so the probe stays disjoint from the other adapters' roots
|
|
184
|
-
* without any structural exclusion.
|
|
167
|
+
* Install-time probe (§1.2): a root holding a workflow-shaped `.md` file at
|
|
168
|
+
* top level (frontmatter `type: workflow` or no `type:` at all).
|
|
185
169
|
*/
|
|
186
170
|
looksLikeRoot(root) {
|
|
187
171
|
let entries;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ── validate (spec §6 env/secret validation column) ──
|
|
20
20
|
*
|
|
21
|
-
* The dangerous-key scan (`dangerous-
|
|
21
|
+
* The dangerous-key scan (`dangerous-env-key`), reusing the akm adapter's
|
|
22
22
|
* `dangerousEnvKeyDiagnostics` — which preserves the code-grounded narrowness:
|
|
23
23
|
* it runs ONLY on `*.env`-suffixed files, so `secrets/<bare-name>` is never
|
|
24
24
|
* scanned (its whole content is an opaque secret value). Reads KEY NAMES only.
|
|
@@ -71,6 +71,8 @@ function recognize(c, file) {
|
|
|
71
71
|
name,
|
|
72
72
|
content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
|
|
73
73
|
};
|
|
74
|
+
if (type !== "script")
|
|
75
|
+
doc.ownsPresentation = true;
|
|
74
76
|
const description = nonEmptyString(parsed.data.description);
|
|
75
77
|
if (description !== undefined)
|
|
76
78
|
doc.description = description;
|
|
@@ -33,10 +33,10 @@ export { websiteSnapshotAdapter } from "./website-snapshot-adapter.js";
|
|
|
33
33
|
*
|
|
34
34
|
* Probe-precedence rationale (grounds "cannot shadow the existing three"):
|
|
35
35
|
*
|
|
36
|
-
* - The three loosest probes — `llm-wiki`
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
36
|
+
* - The three loosest probes — `llm-wiki`, `akm`, and `okf` — stay LAST.
|
|
37
|
+
* Native AKM evidence wins before OKF because AKM Markdown is an OKF
|
|
38
|
+
* superset; the AKM probe is correspondingly strict enough not to claim an
|
|
39
|
+
* OKF bundle merely because it contains one familiar directory name.
|
|
40
40
|
* - `akm.looksLikeRoot` fires on ANY root carrying a stash-subdir-named
|
|
41
41
|
* directory — which includes a `.claude`/`.opencode` tool dir (`commands/`,
|
|
42
42
|
* `agents/`, `skills/`) and a dotenv bundle (`env/`, `secrets/`). So
|
|
@@ -62,10 +62,10 @@ export const BUILTIN_ADAPTERS = Object.freeze([
|
|
|
62
62
|
// Native akm sub-formats (disjoint content-shape probes).
|
|
63
63
|
akmWorkflowAdapter,
|
|
64
64
|
akmTaskAdapter,
|
|
65
|
-
//
|
|
65
|
+
// Loose probes: specific native layouts before the portable OKF baseline.
|
|
66
66
|
llmWikiAdapter,
|
|
67
|
-
okfAdapter,
|
|
68
67
|
akmAdapter,
|
|
68
|
+
okfAdapter,
|
|
69
69
|
// Explicit-config fallback (never auto-selected) — last.
|
|
70
70
|
genericFilesAdapter,
|
|
71
71
|
]);
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* The first-class `llm-wiki` adapter — akm 0.9.0 chunk-4 (DEV-7 restore).
|
|
6
6
|
*
|
|
7
7
|
* The `wiki` ASSET-TYPE dies in chunk 4 (plan §11 Chunk 4 / §7.4), but the LLM
|
|
8
|
-
* Wiki structure stays first-class as its OWN adapter. This relocates the
|
|
9
|
-
* wiki semantics from
|
|
8
|
+
* Wiki structure stays first-class as its OWN adapter. This relocates the
|
|
9
|
+
* native wiki semantics from the retired `src/wiki/` module into a
|
|
10
10
|
* `BundleAdapter` implementing `docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md` §7
|
|
11
11
|
* (llm-wiki row), §6 (wiki-page row), §0.2 (the `wiki` asset-type is retired;
|
|
12
12
|
* the adapter is first-class), §1.2 (probe = schema.md + pages/), §9 (links).
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
*
|
|
43
43
|
* ── validate (spec §6/§7, §9) — native wiki checks ONLY ──
|
|
44
44
|
*
|
|
45
|
-
* The native structural checks ported from `wiki
|
|
45
|
+
* The native structural checks ported from the retired `src/wiki/` module's
|
|
46
|
+
* `lintWiki`: `broken-xref`
|
|
46
47
|
* (an xref target that does not resolve to an existing page), `uncited-raw`
|
|
47
48
|
* (a `raw/` source not cited by any page's `sources:`), `missing-description`
|
|
48
49
|
* (a page with no description), and `broken-source` (a page `sources:` entry
|
|
@@ -58,11 +59,15 @@
|
|
|
58
59
|
*
|
|
59
60
|
* ── Cycle-safety ──
|
|
60
61
|
*
|
|
61
|
-
* Imported
|
|
62
|
-
* imports
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
62
|
+
* Imported by the `adapters/index.ts` barrel, which is NOT test-only: `core/
|
|
63
|
+
* adapter/registry.ts:33` imports it in production for the frozen
|
|
64
|
+
* `BUILTIN_ADAPTERS` list (`installations.ts#detectAdapterId`,
|
|
65
|
+
* `provider-utils.ts#detectStashRoot`). This still can never gain an inbound
|
|
66
|
+
* edge from a cycle participant, since neither the barrel nor the registry
|
|
67
|
+
* import anything that imports back into this file. It value-imports only
|
|
68
|
+
* pure leaves (`frontmatter`, `shared`) plus Node builtins + `yaml` (already a
|
|
69
|
+
* runtime dep). Verified: `bun scripts/lint-import-cycles.ts` reports 0 cycle
|
|
70
|
+
* participants with this file present.
|
|
66
71
|
*/
|
|
67
72
|
import fs from "node:fs";
|
|
68
73
|
import path from "node:path";
|
|
@@ -272,6 +277,7 @@ function recognize(c, file) {
|
|
|
272
277
|
path: file.absPath,
|
|
273
278
|
hash: hashContent(raw),
|
|
274
279
|
adapterId: "llm-wiki",
|
|
280
|
+
ownsPresentation: true,
|
|
275
281
|
type: isRaw ? WIKI_SOURCE_TYPE : (fm.pageKind ?? DEFAULT_PAGE_KIND),
|
|
276
282
|
name: lastSegment,
|
|
277
283
|
content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
|
|
@@ -25,12 +25,106 @@
|
|
|
25
25
|
* WARNING (consumers tolerate broken links). Reads go through
|
|
26
26
|
* `ctx.readFile`; ref existence via `ctx.resolveRef`. Never touches the live
|
|
27
27
|
* filesystem.
|
|
28
|
-
* -
|
|
28
|
+
* - directoryList / looksLikeRoot per §5 / §1.2. Authoring is deliberately
|
|
29
|
+
* absent; AKM-native writers fail before mutating an OKF bundle.
|
|
29
30
|
*/
|
|
30
31
|
import fs from "node:fs";
|
|
31
32
|
import path from "node:path";
|
|
32
33
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
33
34
|
import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
|
|
35
|
+
/** v0.2 frontmatter keys consumed into first-class fields below (§0.1) — excluded from the generic `documentJson` extras fold alongside the v0.1 five, so nothing is duplicated between a first-class field and the opaque extras bag. */
|
|
36
|
+
const CONSUMED_FRONTMATTER_KEYS = [
|
|
37
|
+
"type",
|
|
38
|
+
"title",
|
|
39
|
+
"description",
|
|
40
|
+
"tags",
|
|
41
|
+
"timestamp",
|
|
42
|
+
"generated",
|
|
43
|
+
"verified",
|
|
44
|
+
"sources",
|
|
45
|
+
"status",
|
|
46
|
+
"stale_after",
|
|
47
|
+
"okf_version",
|
|
48
|
+
];
|
|
49
|
+
/** True for a plain (non-null, non-array) object — the shape every v0.2 mapping (`generated`, one `verified`/`sources` entry) must have. */
|
|
50
|
+
function isPlainObject(value) {
|
|
51
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse one `verified:` actor mapping (`{by, at?}`). Tolerant: a missing/blank
|
|
55
|
+
* `by` yields `undefined` (the entry is dropped, never rejecting the document
|
|
56
|
+
* — OKF conformance leniency); `at` is independently optional.
|
|
57
|
+
*/
|
|
58
|
+
function parseActorMapping(value) {
|
|
59
|
+
if (!isPlainObject(value))
|
|
60
|
+
return undefined;
|
|
61
|
+
const by = nonEmptyString(value.by);
|
|
62
|
+
if (by === undefined)
|
|
63
|
+
return undefined;
|
|
64
|
+
const at = nonEmptyString(value.at);
|
|
65
|
+
return at !== undefined ? { by, at } : { by };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse the `verified:` family. v0.2 permits EITHER a list of `{by, at?}`
|
|
69
|
+
* mappings OR a single mapping written without the list dash (the shorthand
|
|
70
|
+
* form) — both normalize to a non-empty array here. Malformed entries are
|
|
71
|
+
* dropped individually; an entirely-empty/malformed result is `undefined`
|
|
72
|
+
* rather than `[]` (mirrors every other optional-field convention on this
|
|
73
|
+
* adapter: absent, not empty).
|
|
74
|
+
*/
|
|
75
|
+
function parseVerified(value) {
|
|
76
|
+
if (value === undefined || value === null)
|
|
77
|
+
return undefined;
|
|
78
|
+
const candidates = Array.isArray(value) ? value : [value];
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const candidate of candidates) {
|
|
81
|
+
const parsed = parseActorMapping(candidate);
|
|
82
|
+
if (parsed)
|
|
83
|
+
out.push(parsed);
|
|
84
|
+
}
|
|
85
|
+
return out.length > 0 ? out : undefined;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parse the `sources:` object-list family. Each entry needs at minimum a
|
|
89
|
+
* non-empty `resource`; entries failing that are dropped individually (never
|
|
90
|
+
* rejects the document). This is a DIFFERENT shape from the AKM-native
|
|
91
|
+
* `IndexDocument.sources: string[]` (wiki citations) — the two are never
|
|
92
|
+
* mixed, hence the caller lands this under `provenance.sources` instead.
|
|
93
|
+
*/
|
|
94
|
+
function parseOkfSources(value) {
|
|
95
|
+
if (!Array.isArray(value))
|
|
96
|
+
return undefined;
|
|
97
|
+
const out = [];
|
|
98
|
+
for (const item of value) {
|
|
99
|
+
if (!isPlainObject(item))
|
|
100
|
+
continue;
|
|
101
|
+
const resource = nonEmptyString(item.resource);
|
|
102
|
+
if (resource === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
const entry = { resource };
|
|
105
|
+
const id = nonEmptyString(item.id);
|
|
106
|
+
if (id !== undefined)
|
|
107
|
+
entry.id = id;
|
|
108
|
+
const title = nonEmptyString(item.title);
|
|
109
|
+
if (title !== undefined)
|
|
110
|
+
entry.title = title;
|
|
111
|
+
const author = nonEmptyString(item.author);
|
|
112
|
+
if (author !== undefined)
|
|
113
|
+
entry.author = author;
|
|
114
|
+
if (typeof item.usage_count === "number" && Number.isFinite(item.usage_count)) {
|
|
115
|
+
entry.usage_count = item.usage_count;
|
|
116
|
+
}
|
|
117
|
+
const lastModified = nonEmptyString(item.last_modified);
|
|
118
|
+
if (lastModified !== undefined)
|
|
119
|
+
entry.last_modified = lastModified;
|
|
120
|
+
out.push(entry);
|
|
121
|
+
}
|
|
122
|
+
return out.length > 0 ? out : undefined;
|
|
123
|
+
}
|
|
124
|
+
/** Parse the `status:` lifecycle field — a strict whitelist; any other value (including a foreign/future status) is left unset rather than guessed at. */
|
|
125
|
+
function parseLifecycleStatus(value) {
|
|
126
|
+
return value === "draft" || value === "stable" || value === "deprecated" ? value : undefined;
|
|
127
|
+
}
|
|
34
128
|
/** Reserved OKF files (case-insensitive) — recognized, never indexed as concepts (§5, OKF §1.4). */
|
|
35
129
|
const RESERVED_FILES = new Set(["index.md", "log.md"]);
|
|
36
130
|
/** Upper bound on the bounded `content` FTS field (§3: "content: FTS 1 (bounded)"). Small fixtures are never truncated. */
|
|
@@ -59,13 +153,24 @@ function isReservedFileName(name) {
|
|
|
59
153
|
*/
|
|
60
154
|
export function resolveOkfLinks(body, fileRelPath) {
|
|
61
155
|
const dir = path.posix.dirname(toPosix(fileRelPath));
|
|
62
|
-
const
|
|
156
|
+
const definitions = new Map();
|
|
157
|
+
for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
|
|
158
|
+
definitions.set(match[1].trim().toLowerCase(), match[2]);
|
|
159
|
+
}
|
|
160
|
+
const candidates = [];
|
|
161
|
+
for (const match of body.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
|
|
162
|
+
candidates.push({ index: match.index, target: match[1] });
|
|
163
|
+
}
|
|
164
|
+
for (const match of body.matchAll(/(?<!!)\[[^\]]*\]\[([^\]]+)\]/g)) {
|
|
165
|
+
const target = definitions.get(match[1].trim().toLowerCase());
|
|
166
|
+
if (target)
|
|
167
|
+
candidates.push({ index: match.index, target });
|
|
168
|
+
}
|
|
169
|
+
candidates.sort((a, b) => a.index - b.index);
|
|
63
170
|
const out = [];
|
|
64
171
|
const seen = new Set();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
while ((match = linkRe.exec(body)) !== null) {
|
|
68
|
-
let target = match[1].trim();
|
|
172
|
+
for (const candidate of candidates) {
|
|
173
|
+
let target = candidate.target.trim();
|
|
69
174
|
// Drop an optional markdown link title: `[x](/a.md "Title")`.
|
|
70
175
|
const wsIdx = target.search(/\s/);
|
|
71
176
|
if (wsIdx >= 0)
|
|
@@ -127,8 +232,33 @@ function recognize(c, file) {
|
|
|
127
232
|
const name = nonEmptyString(data.title) ?? lastSegment;
|
|
128
233
|
const description = nonEmptyString(data.description);
|
|
129
234
|
const tags = readTags(data.tags);
|
|
130
|
-
const updated = nonEmptyString(data.timestamp);
|
|
131
235
|
const links = resolveOkfLinks(body, file.relPath);
|
|
236
|
+
// v0.2 trust/provenance/lifecycle families (§0.1, okf-support.md v0.2 note).
|
|
237
|
+
// `generated.at` — v0.2's replacement for `timestamp` — takes precedence;
|
|
238
|
+
// `timestamp` remains a fully valid fallback (the v0.2-permitted legacy
|
|
239
|
+
// reading, not merely tolerated). Both stay fully optional (never rejects).
|
|
240
|
+
const generatedMapping = isPlainObject(data.generated) ? data.generated : undefined;
|
|
241
|
+
const generatedAt = generatedMapping ? nonEmptyString(generatedMapping.at) : undefined;
|
|
242
|
+
const generatedBy = generatedMapping ? nonEmptyString(generatedMapping.by) : undefined;
|
|
243
|
+
const legacyTimestamp = nonEmptyString(data.timestamp);
|
|
244
|
+
const updated = generatedAt ?? legacyTimestamp;
|
|
245
|
+
const verified = parseVerified(data.verified);
|
|
246
|
+
const okfSources = parseOkfSources(data.sources);
|
|
247
|
+
const provenance = generatedBy !== undefined || generatedAt !== undefined || verified !== undefined || okfSources !== undefined
|
|
248
|
+
? {
|
|
249
|
+
...(generatedBy !== undefined ? { generatedBy } : {}),
|
|
250
|
+
...(generatedAt !== undefined ? { generatedAt } : {}),
|
|
251
|
+
...(verified !== undefined ? { verified } : {}),
|
|
252
|
+
...(okfSources !== undefined ? { sources: okfSources } : {}),
|
|
253
|
+
}
|
|
254
|
+
: undefined;
|
|
255
|
+
const lifecycleStatus = parseLifecycleStatus(data.status);
|
|
256
|
+
const staleAfter = nonEmptyString(data.stale_after);
|
|
257
|
+
// `okf_version` is upstream-declared only on a bundle-root `index.md` (never
|
|
258
|
+
// indexed as a concept, §5) — read defensively from any concept anyway
|
|
259
|
+
// (best-effort, conformance Rule 9); a producer that also tags ordinary
|
|
260
|
+
// concepts with it is neither rejected nor silently ignored.
|
|
261
|
+
const okfVersion = nonEmptyString(data.okf_version);
|
|
132
262
|
const doc = {
|
|
133
263
|
ref: `${c.id}//${conceptId}`,
|
|
134
264
|
bundle: c.id,
|
|
@@ -139,6 +269,7 @@ function recognize(c, file) {
|
|
|
139
269
|
// incrementality/fingerprints (`types.ts` hash doc comment).
|
|
140
270
|
hash: hashContent(raw),
|
|
141
271
|
adapterId: "okf",
|
|
272
|
+
ownsPresentation: true,
|
|
142
273
|
type,
|
|
143
274
|
name,
|
|
144
275
|
content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
|
|
@@ -151,6 +282,17 @@ function recognize(c, file) {
|
|
|
151
282
|
doc.updated = updated;
|
|
152
283
|
if (links.length > 0)
|
|
153
284
|
doc.links = links;
|
|
285
|
+
if (provenance !== undefined)
|
|
286
|
+
doc.provenance = provenance;
|
|
287
|
+
if (lifecycleStatus !== undefined)
|
|
288
|
+
doc.lifecycleStatus = lifecycleStatus;
|
|
289
|
+
if (staleAfter !== undefined)
|
|
290
|
+
doc.staleAfter = staleAfter;
|
|
291
|
+
if (okfVersion !== undefined)
|
|
292
|
+
doc.okfVersion = okfVersion;
|
|
293
|
+
const extras = Object.fromEntries(Object.entries(data).filter(([key]) => !CONSUMED_FRONTMATTER_KEYS.includes(key)));
|
|
294
|
+
if (Object.keys(extras).length > 0)
|
|
295
|
+
doc.documentJson = extras;
|
|
154
296
|
return doc;
|
|
155
297
|
}
|
|
156
298
|
async function validate(c, changes, ctx) {
|
|
@@ -165,14 +307,11 @@ async function validate(c, changes, ctx) {
|
|
|
165
307
|
const fileName = relPath.split("/").pop() ?? relPath;
|
|
166
308
|
const reserved = isReservedFileName(fileName);
|
|
167
309
|
const parsed = parseFrontmatter(raw);
|
|
168
|
-
// Base checks
|
|
310
|
+
// Base checks shared with native AKM formats. OKF's timestamp is optional,
|
|
311
|
+
// so the AKM-specific freshness diagnostic is removed unconditionally.
|
|
169
312
|
const base = await runBaseValidateChecks(relPath, parsed, c.root, ctx);
|
|
170
|
-
// §0.1: for OKF content a `timestamp` satisfies the freshness requirement
|
|
171
|
-
// (the base-linter's `missing-updated` maps to `timestamp`). Suppress the
|
|
172
|
-
// `missing-updated` diagnostic when a non-empty `timestamp` is present.
|
|
173
|
-
const hasTimestamp = nonEmptyString(parsed.data.timestamp) !== undefined;
|
|
174
313
|
for (const diag of base) {
|
|
175
|
-
if (
|
|
314
|
+
if (diag.issue === "missing-updated")
|
|
176
315
|
continue;
|
|
177
316
|
diagnostics.push(diag);
|
|
178
317
|
}
|
|
@@ -208,16 +347,45 @@ export const okfAdapter = {
|
|
|
208
347
|
extensions: [".md"],
|
|
209
348
|
recognize,
|
|
210
349
|
validate,
|
|
211
|
-
/** `<c.root>/<conceptId>.md` (§5). */
|
|
212
|
-
placeNew(c, conceptId) {
|
|
213
|
-
return path.join(c.root, `${conceptId}.md`);
|
|
214
|
-
},
|
|
215
350
|
/** OKF concepts live anywhere under the component root (§5). */
|
|
216
351
|
directoryList(_c) {
|
|
217
352
|
return ["."];
|
|
218
353
|
},
|
|
219
|
-
/**
|
|
354
|
+
/**
|
|
355
|
+
* Install-time probe. A root index is sufficient; an index-less root is also
|
|
356
|
+
* OKF when it contains at least one conformant concept with a non-empty open
|
|
357
|
+
* `type`. More-specific native adapters run before this portable baseline.
|
|
358
|
+
*/
|
|
220
359
|
looksLikeRoot(root) {
|
|
221
|
-
|
|
360
|
+
if (fs.existsSync(path.join(root, "index.md")))
|
|
361
|
+
return true;
|
|
362
|
+
const stack = [root];
|
|
363
|
+
while (stack.length > 0) {
|
|
364
|
+
const current = stack.pop();
|
|
365
|
+
if (!current)
|
|
366
|
+
continue;
|
|
367
|
+
let entries;
|
|
368
|
+
try {
|
|
369
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
for (const entry of entries) {
|
|
375
|
+
if (entry.isSymbolicLink() || entry.name === ".git")
|
|
376
|
+
continue;
|
|
377
|
+
const absolute = path.join(current, entry.name);
|
|
378
|
+
if (entry.isDirectory()) {
|
|
379
|
+
stack.push(absolute);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md") || isReservedFileName(entry.name))
|
|
383
|
+
continue;
|
|
384
|
+
const type = nonEmptyString(parseFrontmatter(fs.readFileSync(absolute, "utf8")).data.type);
|
|
385
|
+
if (type)
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return false;
|
|
222
390
|
},
|
|
223
391
|
};
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
*/
|
|
50
50
|
import { createHash } from "node:crypto";
|
|
51
51
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
52
|
+
import { checkUnquotedDescriptionColon } from "../../asset/frontmatter-lint.js";
|
|
52
53
|
// ── Small pure helpers, reused across the concrete adapters ──────────────────
|
|
53
54
|
/** Content hash feeding `IndexDocument.hash` (incrementality/fingerprints, `types.ts` doc comment). */
|
|
54
55
|
export function hashContent(content) {
|
|
@@ -69,23 +70,6 @@ export function readTags(value) {
|
|
|
69
70
|
return tags.length > 0 ? tags : undefined;
|
|
70
71
|
}
|
|
71
72
|
// ── Base validate checks (port of `BaseLinter.runBaseChecks`) ────────────────
|
|
72
|
-
function checkUnquotedColon(frontmatterText) {
|
|
73
|
-
if (!frontmatterText)
|
|
74
|
-
return null;
|
|
75
|
-
for (const line of frontmatterText.split(/\r?\n/)) {
|
|
76
|
-
const match = line.match(/^description:\s*(.*)/);
|
|
77
|
-
if (!match)
|
|
78
|
-
continue;
|
|
79
|
-
const value = match[1].trim();
|
|
80
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
if (value.includes(":")) {
|
|
84
|
-
return `description value contains unquoted colon: ${value}`;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
73
|
function checkMissingUpdated(data, frontmatterText) {
|
|
90
74
|
return frontmatterText !== null && !("updated" in data);
|
|
91
75
|
}
|
|
@@ -207,7 +191,7 @@ function readRefStringOrArray(value) {
|
|
|
207
191
|
export async function runBaseValidateChecks(relPath, parsed, componentRoot, ctx) {
|
|
208
192
|
const diagnostics = [];
|
|
209
193
|
const { data, content: body, frontmatter } = parsed;
|
|
210
|
-
const unquotedColonDetail =
|
|
194
|
+
const unquotedColonDetail = checkUnquotedDescriptionColon(frontmatter);
|
|
211
195
|
if (unquotedColonDetail) {
|
|
212
196
|
diagnostics.push({ file: relPath, issue: "unquoted-colon", detail: unquotedColonDetail, fixed: false });
|
|
213
197
|
}
|
|
@@ -228,7 +212,7 @@ export async function runBaseValidateChecks(relPath, parsed, componentRoot, ctx)
|
|
|
228
212
|
if (found !== null)
|
|
229
213
|
continue;
|
|
230
214
|
const portableHint = candidate.startsWith(componentRoot)
|
|
231
|
-
? ` (portable form: $
|
|
215
|
+
? ` (portable form: $AKM_BUNDLE_DIR${candidate.slice(componentRoot.length)})`
|
|
232
216
|
: "";
|
|
233
217
|
diagnostics.push({
|
|
234
218
|
file: relPath,
|
|
@@ -41,9 +41,12 @@
|
|
|
41
41
|
* ── Cycle-safety ──
|
|
42
42
|
*
|
|
43
43
|
* Imported only by `claude-adapter.ts` / `opencode-adapter.ts` (themselves
|
|
44
|
-
* imported
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* imported by the `adapters/index.ts` barrel — NOT test-only: `core/adapter/
|
|
45
|
+
* registry.ts:33` imports it in production for the frozen `BUILTIN_ADAPTERS`
|
|
46
|
+
* list). This leaf still can never gain an inbound edge from a cycle
|
|
47
|
+
* participant, since nothing on that import chain imports back into it. It
|
|
48
|
+
* value-imports only pure leaves (`shared`, `akm-lint`, `frontmatter`) plus
|
|
49
|
+
* Node builtins.
|
|
47
50
|
*/
|
|
48
51
|
import path from "node:path";
|
|
49
52
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
@@ -121,6 +124,8 @@ export function recognizeToolDir(layout, c, file) {
|
|
|
121
124
|
name,
|
|
122
125
|
content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
|
|
123
126
|
};
|
|
127
|
+
if (cls.type === "instruction")
|
|
128
|
+
doc.ownsPresentation = true;
|
|
124
129
|
if (description !== undefined)
|
|
125
130
|
doc.description = description;
|
|
126
131
|
if (tags !== undefined)
|