akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -2,12 +2,12 @@
|
|
|
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
|
-
* The `akm-task` adapter
|
|
5
|
+
* The `akm-task` adapter for strict task-v3 `.yml` sources.
|
|
6
6
|
*
|
|
7
7
|
* A native akm task-YAML bundle (spec §6/§7). A `.yml` file derives
|
|
8
8
|
* `type: task`; conceptId strips the `.yml` extension. Tasks are AKM-native
|
|
9
9
|
* YAML, NOT OKF markdown concepts. Recognition does NOT gate on validity — an
|
|
10
|
-
* invalid task (e.g.
|
|
10
|
+
* invalid task (e.g. `uses` plus `run`) is still RECOGNIZED; the `invalid-task-yaml`
|
|
11
11
|
* violation surfaces only in `validate`.
|
|
12
12
|
*
|
|
13
13
|
* `.yaml` is the one extension `validate` inspects but `recognize` refuses: it
|
|
@@ -16,13 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* ── validate (spec §6 task validation column) ──
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* two targets is `invalid-task-yaml`. So this adapter owns a purpose-built
|
|
25
|
-
* one-target check rather than reusing that port.
|
|
19
|
+
* Validation enters the canonical task-v3 source parser. That parser owns the
|
|
20
|
+
* closed key sets, executable-selector XOR, scheduling-source XOR, hostile
|
|
21
|
+
* YAML policy, trigger classification, built-in action validation, bounds,
|
|
22
|
+
* and physical `working-directory` containment. The adapter only translates a
|
|
23
|
+
* parser failure into the format-family diagnostic shape.
|
|
26
24
|
*
|
|
27
25
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
28
26
|
* `tests/fixtures/bundles/akm-task/` + goldens
|
|
@@ -30,14 +28,12 @@
|
|
|
30
28
|
*/
|
|
31
29
|
import fs from "node:fs";
|
|
32
30
|
import path from "node:path";
|
|
33
|
-
import {
|
|
31
|
+
import { parseTaskV3Yaml, TASK_EXTENSION, TASK_NEAR_MISS_EXTENSION, taskExtensionDetail, taskV3SourceErrorDetail, } from "../../../tasks/source-v3.js";
|
|
34
32
|
import { hashContent } from "./shared.js";
|
|
35
33
|
/** A native task bundle is single-component; its one component is `main`. */
|
|
36
34
|
const COMPONENT_ID = "main";
|
|
37
35
|
/** The task YAML extension (spec §6 task row). */
|
|
38
36
|
const TASK_EXT = TASK_EXTENSION;
|
|
39
|
-
/** The mutually-exclusive task target keys (exactly one required). */
|
|
40
|
-
const TARGET_KEYS = ["prompt", "workflow", "command"];
|
|
41
37
|
/** Upper bound on the bounded `content` FTS field (mirrors okf-adapter). */
|
|
42
38
|
const MAX_CONTENT_CHARS = 100_000;
|
|
43
39
|
function toPosix(p) {
|
|
@@ -62,29 +58,7 @@ function recognize(c, file) {
|
|
|
62
58
|
content: raw.length > MAX_CONTENT_CHARS ? raw.slice(0, MAX_CONTENT_CHARS) : raw,
|
|
63
59
|
};
|
|
64
60
|
}
|
|
65
|
-
|
|
66
|
-
* The native `invalid-task-yaml` check: the shared field rules
|
|
67
|
-
* ({@link taskFieldProblems} — see its doc for the lint-vs-parser
|
|
68
|
-
* reconciliation story) plus this adapter's stricter EXACTLY-ONE-target rule.
|
|
69
|
-
*/
|
|
70
|
-
function taskDiagnostics(relPath, data) {
|
|
71
|
-
if (Object.keys(data).length === 0)
|
|
72
|
-
return [];
|
|
73
|
-
const problems = taskFieldProblems(data);
|
|
74
|
-
// Shared presence rule (src/tasks/schema.ts): an empty string or empty array
|
|
75
|
-
// is not a target, matching the runtime parser.
|
|
76
|
-
const targets = TARGET_KEYS.filter((k) => isPresentTarget(data[k]));
|
|
77
|
-
if (targets.length === 0)
|
|
78
|
-
problems.push("exactly one target (prompt, workflow, or command)");
|
|
79
|
-
else if (targets.length > 1)
|
|
80
|
-
problems.push(`exactly one target — declares ${targets.length} (${targets.join(", ")})`);
|
|
81
|
-
if (problems.length === 0)
|
|
82
|
-
return [];
|
|
83
|
-
return [
|
|
84
|
-
{ file: relPath, issue: "invalid-task-yaml", detail: `task field errors: ${problems.join("; ")}`, fixed: false },
|
|
85
|
-
];
|
|
86
|
-
}
|
|
87
|
-
async function validate(_c, changes, ctx) {
|
|
61
|
+
async function validate(c, changes, ctx) {
|
|
88
62
|
const diagnostics = [];
|
|
89
63
|
for (const change of changes) {
|
|
90
64
|
if (change.op === "delete")
|
|
@@ -106,27 +80,25 @@ async function validate(_c, changes, ctx) {
|
|
|
106
80
|
detail: taskExtensionDetail(relPath),
|
|
107
81
|
fixed: false,
|
|
108
82
|
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
parseTaskV3Yaml({ yaml: raw, filePath: relPath, workspaceRoot: c.root });
|
|
109
87
|
}
|
|
110
|
-
|
|
111
|
-
if (!parsed.ok) {
|
|
112
|
-
// Distinguish "unparseable" from "empty": `taskDiagnostics` returns []
|
|
113
|
-
// for an empty mapping, so collapsing a parse failure onto `{}` made a
|
|
114
|
-
// broken task file lint clean.
|
|
88
|
+
catch (cause) {
|
|
115
89
|
diagnostics.push({
|
|
116
90
|
file: relPath,
|
|
117
91
|
issue: "invalid-task-yaml",
|
|
118
|
-
detail:
|
|
92
|
+
detail: taskV3SourceErrorDetail(cause),
|
|
119
93
|
fixed: false,
|
|
120
94
|
});
|
|
121
|
-
continue;
|
|
122
95
|
}
|
|
123
|
-
diagnostics.push(...taskDiagnostics(relPath, parsed.data));
|
|
124
96
|
}
|
|
125
97
|
return diagnostics;
|
|
126
98
|
}
|
|
127
99
|
export const akmTaskAdapter = {
|
|
128
100
|
id: "akm-task",
|
|
129
|
-
version: "0.9.
|
|
101
|
+
version: "0.9.2",
|
|
130
102
|
// `.yaml` is listed as a COLLECTION hint only — `recognize` still gates on
|
|
131
103
|
// `.yml`, so a `.yaml` file is never indexed as a task. Listing it is what
|
|
132
104
|
// routes the near-miss file into `validate`, where it is reported instead of
|
|
@@ -134,6 +106,13 @@ export const akmTaskAdapter = {
|
|
|
134
106
|
extensions: [TASK_EXT, TASK_NEAR_MISS_EXTENSION],
|
|
135
107
|
recognize,
|
|
136
108
|
validate,
|
|
109
|
+
readCandidates(c, conceptId) {
|
|
110
|
+
const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
|
|
111
|
+
return [
|
|
112
|
+
{ path: path.join(c.root, `${posix}.yml`), conceptId: posix },
|
|
113
|
+
{ path: path.join(c.root, `${posix}.yaml`), conceptId: posix },
|
|
114
|
+
];
|
|
115
|
+
},
|
|
137
116
|
/** A task places to `<conceptId>.yml`; an already-suffixed conceptId is idempotent. */
|
|
138
117
|
placeNew(c, conceptId) {
|
|
139
118
|
const posix = toPosix(conceptId);
|
|
@@ -144,9 +123,9 @@ export const akmTaskAdapter = {
|
|
|
144
123
|
return ["."];
|
|
145
124
|
},
|
|
146
125
|
/**
|
|
147
|
-
* Install-time probe (§1.2): a root holding a top-level
|
|
148
|
-
*
|
|
149
|
-
* from
|
|
126
|
+
* Install-time probe (§1.2): a root holding a top-level, valid task-v3
|
|
127
|
+
* `.yml` file. The full parser keeps this disjoint from unrelated YAML and
|
|
128
|
+
* prevents probe semantics from drifting from validation semantics.
|
|
150
129
|
*/
|
|
151
130
|
looksLikeRoot(root) {
|
|
152
131
|
let entries;
|
|
@@ -166,9 +145,13 @@ export const akmTaskAdapter = {
|
|
|
166
145
|
catch {
|
|
167
146
|
continue;
|
|
168
147
|
}
|
|
169
|
-
|
|
170
|
-
|
|
148
|
+
try {
|
|
149
|
+
parseTaskV3Yaml({ yaml: raw, filePath: entry.name, workspaceRoot: root });
|
|
171
150
|
return true;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Continue probing the remaining top-level .yml files.
|
|
154
|
+
}
|
|
172
155
|
}
|
|
173
156
|
return false;
|
|
174
157
|
},
|
|
@@ -4,13 +4,9 @@
|
|
|
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
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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.
|
|
7
|
+
* A native akm workflow bundle. AKM Markdown and the strict local GitHub-shaped
|
|
8
|
+
* `.yml` subset are peer source formats. Both compile through the source IR;
|
|
9
|
+
* neither source is rewritten or projected onto the other.
|
|
14
10
|
*
|
|
15
11
|
* ── validate (spec §6 workflow row) ──
|
|
16
12
|
*
|
|
@@ -25,13 +21,14 @@
|
|
|
25
21
|
*/
|
|
26
22
|
import fs from "node:fs";
|
|
27
23
|
import path from "node:path";
|
|
24
|
+
import { looksLikeGithubWorkflowSource } from "../../../workflows/source-ir/compile.js";
|
|
28
25
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
29
|
-
import { perTypeValidateChecks } from "./akm-lint.js";
|
|
26
|
+
import { perTypeValidateChecks, workflowYamlSourceDiagnostics } from "./akm-lint.js";
|
|
30
27
|
import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
|
|
31
28
|
/** A native workflow bundle is single-component; its one component is `main`. */
|
|
32
29
|
const COMPONENT_ID = "main";
|
|
33
|
-
/**
|
|
34
|
-
const WORKFLOW_EXTS = new Set([".md"]);
|
|
30
|
+
/** The two authoritative workflow source formats. `.yaml` is deliberately not accepted. */
|
|
31
|
+
const WORKFLOW_EXTS = new Set([".md", ".yml"]);
|
|
35
32
|
/** Upper bound on the bounded `content` FTS field (mirrors okf-adapter). */
|
|
36
33
|
const MAX_CONTENT_CHARS = 100_000;
|
|
37
34
|
function toPosix(p) {
|
|
@@ -39,7 +36,7 @@ function toPosix(p) {
|
|
|
39
36
|
}
|
|
40
37
|
/** Strip the recognized workflow extension from a component-root-relative path → conceptId. */
|
|
41
38
|
function conceptIdOf(relPath) {
|
|
42
|
-
return toPosix(relPath).replace(/\.md$/i, "");
|
|
39
|
+
return toPosix(relPath).replace(/\.(?:md|yml)$/i, "");
|
|
43
40
|
}
|
|
44
41
|
/** `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
42
|
function isReservedDocFile(fileName) {
|
|
@@ -63,14 +60,14 @@ function recognize(c, file) {
|
|
|
63
60
|
if (isReservedDocFile(file.fileName))
|
|
64
61
|
return null;
|
|
65
62
|
const raw = file.content();
|
|
66
|
-
if (!isWorkflowFile(raw))
|
|
63
|
+
if (file.ext === ".md" && !isWorkflowFile(raw))
|
|
67
64
|
return null;
|
|
68
65
|
const conceptId = conceptIdOf(file.relPath);
|
|
69
66
|
const name = conceptId.split("/").pop() ?? conceptId;
|
|
70
67
|
const parsed = parseFrontmatter(raw);
|
|
71
|
-
const description = nonEmptyString(parsed.data.description);
|
|
72
|
-
const body = parsed.content;
|
|
73
|
-
const tags = readTags(parsed.data.tags);
|
|
68
|
+
const description = file.ext === ".md" ? nonEmptyString(parsed.data.description) : undefined;
|
|
69
|
+
const body = file.ext === ".md" ? parsed.content : raw;
|
|
70
|
+
const tags = file.ext === ".md" ? readTags(parsed.data.tags) : undefined;
|
|
74
71
|
const doc = {
|
|
75
72
|
ref: `${c.id}//${conceptId}`,
|
|
76
73
|
bundle: c.id,
|
|
@@ -98,9 +95,15 @@ async function validate(c, changes, ctx) {
|
|
|
98
95
|
if (typeof raw !== "string")
|
|
99
96
|
continue;
|
|
100
97
|
const ext = path.extname(change.path).toLowerCase();
|
|
101
|
-
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path.basename(change.path))
|
|
98
|
+
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path.basename(change.path)))
|
|
102
99
|
continue;
|
|
103
100
|
const relPath = toPosix(change.path);
|
|
101
|
+
if (ext === ".yml") {
|
|
102
|
+
diagnostics.push(...workflowYamlSourceDiagnostics(relPath, raw, relPath, c.root).errors);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!isWorkflowFile(raw))
|
|
106
|
+
continue;
|
|
104
107
|
const p = parseFrontmatter(raw);
|
|
105
108
|
const parsed = { data: p.data, content: p.content, frontmatter: p.frontmatter };
|
|
106
109
|
diagnostics.push(...(await runBaseValidateChecks(relPath, parsed, c.root, ctx)));
|
|
@@ -141,21 +144,33 @@ function hasTopLevelWorkflowFile(root, entries) {
|
|
|
141
144
|
catch {
|
|
142
145
|
continue;
|
|
143
146
|
}
|
|
144
|
-
if (
|
|
147
|
+
if (ext === ".yml" && looksLikeGithubWorkflowSource(raw))
|
|
148
|
+
return true;
|
|
149
|
+
if (ext === ".md" && parseFrontmatter(raw).data.type === "workflow")
|
|
145
150
|
return true;
|
|
146
151
|
}
|
|
147
152
|
return false;
|
|
148
153
|
}
|
|
149
154
|
export const akmWorkflowAdapter = {
|
|
150
155
|
id: "akm-workflow",
|
|
151
|
-
version: "0.9.
|
|
152
|
-
extensions: [".md"],
|
|
156
|
+
version: "0.9.2",
|
|
157
|
+
extensions: [".md", ".yml"],
|
|
153
158
|
recognize,
|
|
154
159
|
validate,
|
|
155
|
-
|
|
160
|
+
readCandidates(c, conceptId) {
|
|
161
|
+
const posix = toPosix(conceptId);
|
|
162
|
+
const canonical = posix.replace(/\.(?:md|yml)$/i, "");
|
|
163
|
+
return /\.(?:md|yml)$/i.test(posix)
|
|
164
|
+
? [{ path: path.join(c.root, posix), conceptId: canonical }]
|
|
165
|
+
: [
|
|
166
|
+
{ path: path.join(c.root, `${posix}.md`), conceptId: canonical },
|
|
167
|
+
{ path: path.join(c.root, `${posix}.yml`), conceptId: canonical },
|
|
168
|
+
];
|
|
169
|
+
},
|
|
170
|
+
/** Markdown remains the default; an explicit `.md`/`.yml` suffix is preserved. */
|
|
156
171
|
placeNew(c, conceptId) {
|
|
157
172
|
const posix = toPosix(conceptId);
|
|
158
|
-
if (/\.md$/i.test(posix))
|
|
173
|
+
if (/\.(?:md|yml)$/i.test(posix))
|
|
159
174
|
return path.join(c.root, posix);
|
|
160
175
|
return path.join(c.root, `${posix}.md`);
|
|
161
176
|
},
|
|
@@ -164,8 +179,8 @@ export const akmWorkflowAdapter = {
|
|
|
164
179
|
return ["."];
|
|
165
180
|
},
|
|
166
181
|
/**
|
|
167
|
-
* Install-time probe (§1.2): a root holding
|
|
168
|
-
*
|
|
182
|
+
* Install-time probe (§1.2): a root holding an explicitly typed Markdown
|
|
183
|
+
* workflow or a complete GitHub-shaped YAML workflow at top level.
|
|
169
184
|
*/
|
|
170
185
|
looksLikeRoot(root) {
|
|
171
186
|
let entries;
|
|
@@ -96,6 +96,19 @@ function scanKeyNames(raw) {
|
|
|
96
96
|
}
|
|
97
97
|
return keys;
|
|
98
98
|
}
|
|
99
|
+
function conceptIdForPath(type, relativePath) {
|
|
100
|
+
const posix = toPosix(relativePath);
|
|
101
|
+
if (type === "secret")
|
|
102
|
+
return posix;
|
|
103
|
+
const stripped = posix.replace(/\.env$/i, "");
|
|
104
|
+
return stripped.endsWith("/") ? `${stripped}default` : stripped;
|
|
105
|
+
}
|
|
106
|
+
function recognizePathCandidates(_c, file) {
|
|
107
|
+
const type = classify(file.relPath);
|
|
108
|
+
if (type === null || hasSensitiveMarker(file.absPath, type))
|
|
109
|
+
return [];
|
|
110
|
+
return [conceptIdForPath(type, file.relPath)];
|
|
111
|
+
}
|
|
99
112
|
function recognize(c, file) {
|
|
100
113
|
const type = classify(file.relPath);
|
|
101
114
|
if (type === null)
|
|
@@ -106,7 +119,7 @@ function recognize(c, file) {
|
|
|
106
119
|
const raw = file.content();
|
|
107
120
|
if (type === "env") {
|
|
108
121
|
// env: strip `.env`; surface KEY NAMES only (never values/comments/content).
|
|
109
|
-
const conceptId =
|
|
122
|
+
const conceptId = conceptIdForPath(type, posix);
|
|
110
123
|
const name = (conceptId.split("/").pop() ?? conceptId) || "default";
|
|
111
124
|
const keys = scanKeyNames(raw);
|
|
112
125
|
const doc = {
|
|
@@ -159,7 +172,23 @@ export const dotenvAdapter = {
|
|
|
159
172
|
version: "0.9.0",
|
|
160
173
|
extensions: [".env"],
|
|
161
174
|
recognize,
|
|
175
|
+
recognizePathCandidates,
|
|
162
176
|
validate,
|
|
177
|
+
readCandidates(c, conceptId) {
|
|
178
|
+
const posix = toPosix(conceptId);
|
|
179
|
+
const slash = posix.indexOf("/");
|
|
180
|
+
if (slash <= 0)
|
|
181
|
+
return [];
|
|
182
|
+
const head = posix.slice(0, slash);
|
|
183
|
+
const rest = posix.slice(slash + 1);
|
|
184
|
+
const type = typeForStashDir(head);
|
|
185
|
+
if ((type !== "env" && type !== "secret") || rest.length === 0)
|
|
186
|
+
return [];
|
|
187
|
+
const primary = assetPathForName(type, path.join(c.root, head), rest);
|
|
188
|
+
return (type === "env"
|
|
189
|
+
? [primary, primary.replace(/\.env$/i, ".sensitive")]
|
|
190
|
+
: [primary, `${primary}.sensitive`, `${primary}.lock`]).map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
|
|
191
|
+
},
|
|
163
192
|
/**
|
|
164
193
|
* env places to `env/<name>.env`, secret to `secrets/<name>` (identity join,
|
|
165
194
|
* no extension logic) — reusing the shared `assetPathForName` so the env
|
|
@@ -102,6 +102,17 @@ export const genericFilesAdapter = {
|
|
|
102
102
|
extensions: [".md", ".txt"],
|
|
103
103
|
recognize,
|
|
104
104
|
validate,
|
|
105
|
+
readCandidates(c, conceptId) {
|
|
106
|
+
const posix = toPosix(conceptId);
|
|
107
|
+
const extension = path.extname(posix).toLowerCase();
|
|
108
|
+
const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
|
|
109
|
+
path: path.join(c.root, `${posix}${candidateExtension}`),
|
|
110
|
+
conceptId: posix,
|
|
111
|
+
}));
|
|
112
|
+
return DOCUMENT_EXTENSIONS.has(extension)
|
|
113
|
+
? documentCandidates
|
|
114
|
+
: [{ path: path.join(c.root, posix), conceptId: posix }, ...documentCandidates];
|
|
115
|
+
},
|
|
105
116
|
/**
|
|
106
117
|
* IDENTITY placement (open-question-5): a conceptId that carries an extension
|
|
107
118
|
* (`script`/`file`) places to itself; an extension-less conceptId (a
|
|
@@ -69,12 +69,3 @@ export const BUILTIN_ADAPTERS = Object.freeze([
|
|
|
69
69
|
// Explicit-config fallback (never auto-selected) — last.
|
|
70
70
|
genericFilesAdapter,
|
|
71
71
|
]);
|
|
72
|
-
/**
|
|
73
|
-
* DEPRECATED no-op retained for test back-compat only. The built-in set is now
|
|
74
|
-
* the static, frozen {@link BUILTIN_ADAPTERS}, exposed by the registry at
|
|
75
|
-
* module load (normative §12.6), so there is nothing to register. New code MUST
|
|
76
|
-
* NOT call this — `getAdapters()` / `adapterForId()` are always populated.
|
|
77
|
-
*/
|
|
78
|
-
export function registerBuiltinAdapters() {
|
|
79
|
-
// intentionally empty — BUILTIN_ADAPTERS is static; see the doc comment above.
|
|
80
|
-
}
|
|
@@ -395,6 +395,10 @@ export const llmWikiAdapter = {
|
|
|
395
395
|
extensions: [".md"],
|
|
396
396
|
recognize,
|
|
397
397
|
validate,
|
|
398
|
+
readCandidates(c, conceptId) {
|
|
399
|
+
const canonical = toPosix(conceptId).replace(/\.md$/i, "");
|
|
400
|
+
return [{ path: path.join(c.root, `${canonical}.md`), conceptId: canonical }];
|
|
401
|
+
},
|
|
398
402
|
/** `<c.root>/<conceptId>.md` — the conceptId already carries its `pages/`/`raw/` prefix (placement golden). */
|
|
399
403
|
placeNew(c, conceptId) {
|
|
400
404
|
return path.join(c.root, `${conceptId}.md`);
|
|
@@ -347,6 +347,10 @@ export const okfAdapter = {
|
|
|
347
347
|
extensions: [".md"],
|
|
348
348
|
recognize,
|
|
349
349
|
validate,
|
|
350
|
+
readCandidates(c, conceptId) {
|
|
351
|
+
const canonical = conceptId.replace(/\\/g, "/").replace(/\.md$/i, "");
|
|
352
|
+
return [{ path: path.join(c.root, `${canonical}.md`), conceptId: canonical }];
|
|
353
|
+
},
|
|
350
354
|
/** OKF concepts live anywhere under the component root (§5). */
|
|
351
355
|
directoryList(_c) {
|
|
352
356
|
return ["."];
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
* https://opencode.ai/docs/{commands,agents,skills,rules}/): a root `AGENTS.md`
|
|
10
10
|
* → `instruction`, `commands/*.md` → `command`, `agents/*.md` → `agent`,
|
|
11
11
|
* `skills/<name>/SKILL.md` → `skill`, and ABSTAINS on `opencode.json` runtime
|
|
12
|
-
* config.
|
|
13
|
-
* `command/`/`agent/`/`skill/` dirs are accepted as backwards-compat aliases on
|
|
14
|
-
* READ (the conceptId preserves the on-disk spelling, e.g. `command/legacy`);
|
|
15
|
-
* WRITES normalize to the canonical plural (handled in the shared codec).
|
|
12
|
+
* config. Only OpenCode's canonical plural tool directories are accepted.
|
|
16
13
|
*
|
|
17
14
|
* All behavior lives in the shared tool-dir codec ({@link makeToolDirAdapter});
|
|
18
15
|
* this module supplies only the `.opencode` layout + the install-time probe.
|
|
@@ -29,12 +26,12 @@ const LAYOUT = {
|
|
|
29
26
|
componentId: ".opencode",
|
|
30
27
|
instructionFile: "AGENTS.md",
|
|
31
28
|
instructionConceptId: "AGENTS",
|
|
32
|
-
commandDirs: new Set(["commands"
|
|
33
|
-
agentDirs: new Set(["agents"
|
|
34
|
-
skillDirs: new Set(["skills"
|
|
29
|
+
commandDirs: new Set(["commands"]),
|
|
30
|
+
agentDirs: new Set(["agents"]),
|
|
31
|
+
skillDirs: new Set(["skills"]),
|
|
35
32
|
};
|
|
36
33
|
const CONFIG_FILES = ["opencode.json", "opencode.jsonc"];
|
|
37
|
-
const TOOL_DIRS = ["commands", "
|
|
34
|
+
const TOOL_DIRS = ["commands", "agents", "skills"];
|
|
38
35
|
function fileExists(p) {
|
|
39
36
|
try {
|
|
40
37
|
return fs.existsSync(p);
|
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
* open AKM `type` vocabulary (spec §6/§7): a root instruction file
|
|
9
9
|
* (CLAUDE.md / AGENTS.md) → `instruction`, `commands/*.md` → `command`,
|
|
10
10
|
* `agents/*.md` → `agent`, `skills/<name>/SKILL.md` → `skill` (item = the dir).
|
|
11
|
-
* They differ only in
|
|
11
|
+
* They differ only in two parameters carried on {@link ToolDirLayout}:
|
|
12
12
|
* - the instruction basename + its concept id,
|
|
13
|
-
* - the accepted subdir spellings (opencode accepts the SINGULAR
|
|
14
|
-
* `command/`/`agent/`/`skill/` aliases per open-question-6, claude does not),
|
|
15
13
|
* - the adapter id + component id.
|
|
16
14
|
*
|
|
17
15
|
* The SKILL.md codec is shared with the `agent-skills` adapter as functions
|
|
@@ -49,7 +47,9 @@
|
|
|
49
47
|
* Node builtins.
|
|
50
48
|
*/
|
|
51
49
|
import path from "node:path";
|
|
50
|
+
import { createAdapterExtensions, } from "../../../execution/source.js";
|
|
52
51
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
52
|
+
import { executionDefaultsFromFrontmatter, renderMarkdownExecutionSource } from "../execution-source.js";
|
|
53
53
|
import { skillDirectoryDiagnostics } from "./akm-lint.js";
|
|
54
54
|
import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
|
|
55
55
|
/** OKF reserved structural files (D-R6) — excluded at every depth, case-insensitive. */
|
|
@@ -85,7 +85,7 @@ function classify(relPath, layout) {
|
|
|
85
85
|
// skill: <skillDir>/<name>/SKILL.md — the item is the DIRECTORY. Any other
|
|
86
86
|
// file under a skill dir (bundled resources) is part of the item, not a concept.
|
|
87
87
|
if (layout.skillDirs.has(head)) {
|
|
88
|
-
if (segs.length
|
|
88
|
+
if (segs.length === 3 && base === SKILL_MANIFEST) {
|
|
89
89
|
return { type: "skill", conceptId: `${segs[0]}/${segs[1]}`, name: segs[1] };
|
|
90
90
|
}
|
|
91
91
|
return null;
|
|
@@ -155,6 +155,25 @@ export function placeNewToolDir(layout, c, conceptId) {
|
|
|
155
155
|
}
|
|
156
156
|
return path.join(c.root, `${posix}.md`);
|
|
157
157
|
}
|
|
158
|
+
/** List native read spellings. */
|
|
159
|
+
export function readCandidatesToolDir(layout, c, conceptId) {
|
|
160
|
+
const posix = toPosix(conceptId);
|
|
161
|
+
if (posix === layout.instructionConceptId) {
|
|
162
|
+
return [{ path: path.join(c.root, layout.instructionFile), conceptId: posix }];
|
|
163
|
+
}
|
|
164
|
+
const segs = posix.split("/").filter((segment) => segment.length > 0);
|
|
165
|
+
const head = segs[0];
|
|
166
|
+
const rest = segs.slice(1).join("/");
|
|
167
|
+
if (!head || !rest)
|
|
168
|
+
return [];
|
|
169
|
+
if (layout.skillDirs.has(head)) {
|
|
170
|
+
return segs.length === 2 ? [{ path: path.join(c.root, head, rest, SKILL_MANIFEST), conceptId: posix }] : [];
|
|
171
|
+
}
|
|
172
|
+
if (layout.commandDirs.has(head) || layout.agentDirs.has(head)) {
|
|
173
|
+
return [{ path: path.join(c.root, head, `${rest}.md`), conceptId: posix }];
|
|
174
|
+
}
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
158
177
|
/** LENIENT command/agent check: a diagnostic only when NEITHER a name/description NOR a type-shaped signal is present. */
|
|
159
178
|
function nameOrSignalDiagnostics(type, relPath, data, body) {
|
|
160
179
|
if (nonEmptyString(data.name) !== undefined || nonEmptyString(data.description) !== undefined)
|
|
@@ -187,8 +206,7 @@ export async function validateToolDir(layout, c, changes, ctx) {
|
|
|
187
206
|
// The one coded skill check (missing-skill-md) fires on ANY change under a
|
|
188
207
|
// `<skillDir>/<name>/…` package (self-gated + deduped), even a bundled
|
|
189
208
|
// resource — mirrors the akm adapter's per-change SkillLinter.lintDirectory
|
|
190
|
-
// pass.
|
|
191
|
-
// is checked identically to `skills/` (issue #774).
|
|
209
|
+
// pass.
|
|
192
210
|
diagnostics.push(...(await skillDirectoryDiagnostics(relPath, seenSkillDirs, ctx, layout.skillDirs)));
|
|
193
211
|
const cls = classify(change.path, layout);
|
|
194
212
|
if (cls === null)
|
|
@@ -204,6 +222,43 @@ export async function validateToolDir(layout, c, changes, ctx) {
|
|
|
204
222
|
}
|
|
205
223
|
return diagnostics;
|
|
206
224
|
}
|
|
225
|
+
function nativeExecutionExtensions(layout, cls, data) {
|
|
226
|
+
const values = {};
|
|
227
|
+
if (layout.adapterId === "claude" && cls.type === "command" && Object.hasOwn(data, "argument-hint")) {
|
|
228
|
+
if (typeof data["argument-hint"] !== "string") {
|
|
229
|
+
throw new TypeError("frontmatter.argument-hint must be a string");
|
|
230
|
+
}
|
|
231
|
+
values.argumentHint = data["argument-hint"];
|
|
232
|
+
}
|
|
233
|
+
if (layout.adapterId === "opencode" && Object.hasOwn(data, "mode")) {
|
|
234
|
+
if (typeof data.mode !== "string")
|
|
235
|
+
throw new TypeError("frontmatter.mode must be a string");
|
|
236
|
+
values.mode = data.mode;
|
|
237
|
+
}
|
|
238
|
+
return Object.keys(values).length > 0 ? createAdapterExtensions(layout.adapterId, values) : undefined;
|
|
239
|
+
}
|
|
240
|
+
/** Translate a native Claude/OpenCode command or agent without exposing raw frontmatter. */
|
|
241
|
+
export function renderToolDirExecutionSource(layout, c, file) {
|
|
242
|
+
const cls = classify(file.relPath, layout);
|
|
243
|
+
if (cls?.type !== "command" && cls?.type !== "agent")
|
|
244
|
+
return null;
|
|
245
|
+
const raw = file.content();
|
|
246
|
+
return renderMarkdownExecutionSource({
|
|
247
|
+
kind: cls.type === "command" ? "command" : "persona",
|
|
248
|
+
raw,
|
|
249
|
+
identity: {
|
|
250
|
+
ref: `${c.id}//${cls.conceptId}`,
|
|
251
|
+
bundle: c.id,
|
|
252
|
+
adapter: layout.adapterId,
|
|
253
|
+
file: file.relPath,
|
|
254
|
+
},
|
|
255
|
+
defaults: (data) => executionDefaultsFromFrontmatter(data, {
|
|
256
|
+
kind: cls.type === "command" ? "command" : "persona",
|
|
257
|
+
toolsKeys: layout.adapterId === "claude" && cls.type === "command" ? ["allowed-tools", "tools"] : ["tools"],
|
|
258
|
+
}),
|
|
259
|
+
extensions: (data) => nativeExecutionExtensions(layout, cls, data),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
207
262
|
/** Build the concrete `BundleAdapter` from a layout + a `looksLikeRoot` probe (claude/opencode share everything else). */
|
|
208
263
|
export function makeToolDirAdapter(layout, looksLikeRoot) {
|
|
209
264
|
return {
|
|
@@ -211,7 +266,9 @@ export function makeToolDirAdapter(layout, looksLikeRoot) {
|
|
|
211
266
|
version: "0.9.0",
|
|
212
267
|
extensions: [".md"],
|
|
213
268
|
recognize: (c, file) => recognizeToolDir(layout, c, file),
|
|
269
|
+
renderExecutionSource: (c, file) => renderToolDirExecutionSource(layout, c, file),
|
|
214
270
|
validate: (c, changes, ctx) => validateToolDir(layout, c, changes, ctx),
|
|
271
|
+
readCandidates: (c, conceptId) => readCandidatesToolDir(layout, c, conceptId),
|
|
215
272
|
placeNew: (c, conceptId) => placeNewToolDir(layout, c, conceptId),
|
|
216
273
|
directoryList: () => [CANONICAL_COMMAND_DIR, CANONICAL_AGENT_DIR, CANONICAL_SKILL_DIR],
|
|
217
274
|
looksLikeRoot,
|
|
@@ -129,6 +129,10 @@ export const websiteSnapshotAdapter = {
|
|
|
129
129
|
extensions: [".md"],
|
|
130
130
|
recognize,
|
|
131
131
|
validate,
|
|
132
|
+
readCandidates(c, conceptId) {
|
|
133
|
+
const canonical = toPosix(conceptId).replace(/\.md$/i, "");
|
|
134
|
+
return [{ path: path.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
|
|
135
|
+
},
|
|
132
136
|
// No placeNew: the snapshot is READ-ONLY (Mode A). Export (Mode B) routes
|
|
133
137
|
// content through the DESTINATION adapter, which owns placement.
|
|
134
138
|
/**
|