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
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* `akm workflow` command family. `run` is the canonical start/resume/execute
|
|
6
6
|
* surface; the former public `start`, `next`, and `complete` lifecycle is gone.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* `create --print` emits Markdown; execution accepts peer `.md` and
|
|
8
|
+
* GitHub-shaped `.yml` workflow sources. Validate with `akm lint --type workflows`.
|
|
9
9
|
*/
|
|
10
10
|
import { getStringArg } from "../cli/parse-args.js";
|
|
11
11
|
import { defineGroupCommand, defineJsonCommand, EXIT_CODES, output } from "../cli/shared.js";
|
|
@@ -232,6 +232,9 @@ export const agentSkillsAdapter = {
|
|
|
232
232
|
extensions: [".md"],
|
|
233
233
|
recognize,
|
|
234
234
|
validate,
|
|
235
|
+
readCandidates(c, conceptId) {
|
|
236
|
+
return [{ path: path.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
|
|
237
|
+
},
|
|
235
238
|
/** A skill places to `<name>/SKILL.md`; the conceptId IS the package directory (spec §4.5). */
|
|
236
239
|
placeNew(c, conceptId) {
|
|
237
240
|
return path.join(c.root, conceptId, SKILL_MANIFEST);
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
* conceptId = `<stash-subdir>/<canonical-name>` — the placement stash-subdir
|
|
40
40
|
* (`stashDirFor(type)`) followed by the winning type's canonical name
|
|
41
41
|
* (`deriveCanonicalAssetNameFromStashRoot`: skill = its dir, script keeps its
|
|
42
|
-
* extension,
|
|
43
|
-
*
|
|
44
|
-
* (path − `.md`); it is
|
|
42
|
+
* extension, Markdown strips `.md`, workflow strips its peer `.md`/`.yml`
|
|
43
|
+
* extension, env/task strip their ext, and secret/session keep the natural
|
|
44
|
+
* path). For Markdown types this IS the OKF concept ID (path − `.md`); it is
|
|
45
|
+
* the same spelling {@link placeNew} consumes, so
|
|
45
46
|
* recognize/place share one identity (D-R2 resolved the earlier split). The
|
|
46
47
|
* `type` is carried separately on `IndexDocument.type`, per §0.2 (type ≠
|
|
47
48
|
* identity), and `entry.name` keeps the BARE canonical name for FTS parity.
|
|
@@ -81,11 +82,11 @@
|
|
|
81
82
|
import fs from "node:fs";
|
|
82
83
|
import path from "node:path";
|
|
83
84
|
import { applyPostContributorFields, applyPreContributorFields, extractPackageMetadata, } from "../../../indexer/passes/metadata.js";
|
|
84
|
-
import { parseTaskYaml, taskYamlParseDetail } from "../../../tasks/schema.js";
|
|
85
85
|
import { assetPathForName, deriveCanonicalAssetNameFromStashRoot, placementTypes, stashDirFor, stashDirNames, } from "../../asset/asset-placement.js";
|
|
86
86
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
87
|
-
import {
|
|
88
|
-
import {
|
|
87
|
+
import { executionDefaultsFromFrontmatter, renderMarkdownExecutionSource } from "../execution-source.js";
|
|
88
|
+
import { recognizeMatch, recognizePathCandidateMatches } from "../recognize-match.js";
|
|
89
|
+
import { perTypeValidateChecks, skillDirectoryDiagnostics, workflowYamlSourceDiagnostics } from "./akm-lint.js";
|
|
89
90
|
import { applyFoldedMetadata, foldRecognizedMetadata } from "./akm-metadata.js";
|
|
90
91
|
import { hashContent, runBaseValidateChecks } from "./shared.js";
|
|
91
92
|
// `recognizeMatch` + the builtin matcher list moved to the cycle-free leaf
|
|
@@ -178,7 +179,6 @@ const DOCUMENT_JSON_CARRIED_FIELDS = [
|
|
|
178
179
|
"whenToUse",
|
|
179
180
|
"toc",
|
|
180
181
|
"parameters",
|
|
181
|
-
"bodyOpening",
|
|
182
182
|
"source",
|
|
183
183
|
"category",
|
|
184
184
|
"supersededBy",
|
|
@@ -221,6 +221,8 @@ function indexDocumentFromEntry(entry, base, rendererName) {
|
|
|
221
221
|
doc.description = entry.description;
|
|
222
222
|
if (entry.tags !== undefined)
|
|
223
223
|
doc.tags = entry.tags;
|
|
224
|
+
if (entry.content !== undefined)
|
|
225
|
+
doc.content = entry.content;
|
|
224
226
|
if (entry.aliases !== undefined)
|
|
225
227
|
doc.aliases = entry.aliases;
|
|
226
228
|
if (entry.searchHints !== undefined)
|
|
@@ -243,6 +245,21 @@ function indexDocumentFromEntry(entry, base, rendererName) {
|
|
|
243
245
|
doc.derivedFrom = entry.derivedFrom;
|
|
244
246
|
return doc;
|
|
245
247
|
}
|
|
248
|
+
function conceptIdForRecognizedType(root, filePath, type) {
|
|
249
|
+
const canonicalName = deriveCanonicalAssetNameFromStashRoot(type, root, filePath);
|
|
250
|
+
if (canonicalName === undefined)
|
|
251
|
+
return undefined;
|
|
252
|
+
const stashDir = stashDirFor(type);
|
|
253
|
+
return stashDir !== undefined ? `${stashDir}/${canonicalName}` : canonicalName;
|
|
254
|
+
}
|
|
255
|
+
function recognizePathCandidates(c, file) {
|
|
256
|
+
if (isReservedFileName(file.fileName) || akmStashAbstains(c.root, file.absPath))
|
|
257
|
+
return [];
|
|
258
|
+
return recognizePathCandidateMatches(file).flatMap((match) => {
|
|
259
|
+
const conceptId = conceptIdForRecognizedType(c.root, file.absPath, match.type);
|
|
260
|
+
return conceptId === undefined ? [] : [conceptId];
|
|
261
|
+
});
|
|
262
|
+
}
|
|
246
263
|
function recognize(c, file) {
|
|
247
264
|
// D-R6 (spec §5.1): `index.md` / `log.md` are OKF reserved structural files at
|
|
248
265
|
// every depth — never items. Excluded BEFORE classification so a directory
|
|
@@ -259,20 +276,20 @@ function recognize(c, file) {
|
|
|
259
276
|
return null;
|
|
260
277
|
// Canonical name = the winning type's per-type canonical name (§5.1).
|
|
261
278
|
// Invalid placements are not projected onto a different identity.
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
279
|
+
const conceptId = conceptIdForRecognizedType(c.root, file.absPath, match.type);
|
|
280
|
+
if (conceptId === undefined)
|
|
264
281
|
return null;
|
|
265
|
-
const
|
|
282
|
+
const stashDir = stashDirFor(match.type);
|
|
283
|
+
const canonicalName = stashDir !== undefined ? conceptId.slice(stashDir.length + 1) : conceptId;
|
|
266
284
|
// conceptId = the QUALIFIED `<stash-subdir>/<canonical-name>` spelling
|
|
267
|
-
// (ref-grammar decision D-R2): the same form `placeNew` consumes
|
|
268
|
-
//
|
|
285
|
+
// (ref-grammar decision D-R2): the same form `placeNew` consumes; Markdown
|
|
286
|
+
// types use the OKF concept ID (path − .md), while workflows strip either
|
|
287
|
+
// peer source extension. Both branches feed a
|
|
269
288
|
// BARE canonicalName (the abstain fallback is the basename, above), so the
|
|
270
289
|
// stash-subdir is prefixed uniformly — a flat `skills/x.md` yields
|
|
271
290
|
// `skills/x`, never the un-prefixed `x` or the double-prefixed
|
|
272
291
|
// `skills/skills/x`. `entry.name` below keeps the BARE canonical name —
|
|
273
292
|
// identity ≠ search text.
|
|
274
|
-
const stashDir = stashDirFor(match.type);
|
|
275
|
-
const conceptId = stashDir !== undefined ? `${stashDir}/${canonicalName}` : canonicalName;
|
|
276
293
|
const dirPath = path.dirname(file.absPath);
|
|
277
294
|
// Chunk 5 M-b: recognize now carries the FULL index-time metadata surface
|
|
278
295
|
// (spec §2/§3), reproducing `buildEntryFromFile`'s flat-walk metadata
|
|
@@ -307,6 +324,30 @@ function recognize(c, file) {
|
|
|
307
324
|
type: match.type,
|
|
308
325
|
}, match.renderer);
|
|
309
326
|
}
|
|
327
|
+
/** Render AKM-native command/agent Markdown into the shared execution source. */
|
|
328
|
+
function renderExecutionSource(c, file) {
|
|
329
|
+
const document = recognize(c, file);
|
|
330
|
+
if (document?.type !== "command" && document?.type !== "agent")
|
|
331
|
+
return null;
|
|
332
|
+
if (!document.ref)
|
|
333
|
+
return null;
|
|
334
|
+
const raw = file.content();
|
|
335
|
+
return renderMarkdownExecutionSource({
|
|
336
|
+
kind: document.type === "command" ? "command" : "persona",
|
|
337
|
+
raw,
|
|
338
|
+
identity: {
|
|
339
|
+
ref: document.ref,
|
|
340
|
+
bundle: c.id,
|
|
341
|
+
adapter: "akm",
|
|
342
|
+
file: file.relPath,
|
|
343
|
+
},
|
|
344
|
+
defaults: (data) => executionDefaultsFromFrontmatter(data, {
|
|
345
|
+
kind: document.type === "command" ? "command" : "persona",
|
|
346
|
+
allowTopLevelEngine: true,
|
|
347
|
+
toolsKeys: ["tools"],
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
350
|
+
}
|
|
310
351
|
/**
|
|
311
352
|
* A read-only {@link FileContext} backed by an OVERLAY string (a pending
|
|
312
353
|
* change's content) instead of the live filesystem — the `validate` contract
|
|
@@ -357,10 +398,9 @@ function buildOverlayContext(root, relPathInput, raw) {
|
|
|
357
398
|
*
|
|
358
399
|
* Per change (non-delete, readable): the `type` is recovered by running the
|
|
359
400
|
* SAME sync matcher arbitration ({@link recognizeMatch}) over an OVERLAY
|
|
360
|
-
* FileContext ({@link buildOverlayContext}) — no live-FS read. `task` files
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* fires (frontmatter is `null`); everything else parses via `parseFrontmatter`.
|
|
401
|
+
* FileContext ({@link buildOverlayContext}) — no live-FS read. `task` files
|
|
402
|
+
* keep raw YAML for the canonical task-v3 parser and use no frontmatter;
|
|
403
|
+
* everything else parses via `parseFrontmatter`.
|
|
364
404
|
* Base checks (shared) then the per-type extra checks run; a `skills/` directory
|
|
365
405
|
* pass reproduces `SkillLinter.lintDirectory` across the change set.
|
|
366
406
|
*/
|
|
@@ -376,23 +416,17 @@ async function validate(c, changes, ctx) {
|
|
|
376
416
|
const overlay = buildOverlayContext(c.root, change.path, raw);
|
|
377
417
|
const match = recognizeMatch(overlay);
|
|
378
418
|
const type = match?.type;
|
|
379
|
-
//
|
|
380
|
-
//
|
|
419
|
+
// A complete GitHub-shaped `on` + `jobs` document is workflow-owned. It
|
|
420
|
+
// never flows through task-v3 parsing or Markdown base/frontmatter checks.
|
|
421
|
+
if (type === "workflow" && overlay.ext === ".yml") {
|
|
422
|
+
diagnostics.push(...workflowYamlSourceDiagnostics(change.path, raw, change.path, c.root).errors);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
// Task parsing belongs to perTypeValidateChecks' canonical v3 parser. Base
|
|
426
|
+
// checks need only a frontmatter-free placeholder here.
|
|
381
427
|
let parsed;
|
|
382
428
|
if (type === "task") {
|
|
383
|
-
|
|
384
|
-
// A parse failure is its OWN finding: every task rule short-circuits on
|
|
385
|
-
// an empty mapping, so collapsing "unparseable" onto `{}` made a broken
|
|
386
|
-
// task file validate clean (issue #760). Mirrors the CLI sweep.
|
|
387
|
-
if (!task.ok) {
|
|
388
|
-
diagnostics.push({
|
|
389
|
-
file: change.path,
|
|
390
|
-
issue: "invalid-task-yaml",
|
|
391
|
-
detail: taskYamlParseDetail(task.error),
|
|
392
|
-
fixed: false,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
parsed = { data: task.data, content: raw, frontmatter: null };
|
|
429
|
+
parsed = { data: {}, content: raw, frontmatter: null };
|
|
396
430
|
}
|
|
397
431
|
else {
|
|
398
432
|
const p = parseFrontmatter(raw);
|
|
@@ -408,6 +442,7 @@ async function validate(c, changes, ctx) {
|
|
|
408
442
|
body: parsed.content,
|
|
409
443
|
ext: overlay.ext,
|
|
410
444
|
ctx,
|
|
445
|
+
workspaceRoot: c.root,
|
|
411
446
|
})));
|
|
412
447
|
diagnostics.push(...(await skillDirectoryDiagnostics(change.path, seenSkillDirs, ctx)));
|
|
413
448
|
}
|
|
@@ -417,8 +452,9 @@ export const akmAdapter = {
|
|
|
417
452
|
id: "akm",
|
|
418
453
|
version: "0.9.0",
|
|
419
454
|
// Recognized-extension HINT, derived from what the matchers accept (§6):
|
|
420
|
-
// `.md` (
|
|
421
|
-
// files), and the 16
|
|
455
|
+
// `.md` (Markdown types + workflow peer), `.yml` (task and workflow YAML),
|
|
456
|
+
// `.yaml` (task near-miss diagnostics), `.env` (env files), and the 16
|
|
457
|
+
// SCRIPT_EXTENSIONS. This is a
|
|
422
458
|
// NON-EXHAUSTIVE hint for the akm adapter: recognition is directory-driven
|
|
423
459
|
// via `recognize()` (e.g. a bare `secrets/<anything>` file with no extension
|
|
424
460
|
// is a `secret`), so `recognize()` — not this list — is the source of truth.
|
|
@@ -445,7 +481,21 @@ export const akmAdapter = {
|
|
|
445
481
|
".kts",
|
|
446
482
|
],
|
|
447
483
|
recognize,
|
|
484
|
+
recognizePathCandidates,
|
|
485
|
+
renderExecutionSource,
|
|
448
486
|
validate,
|
|
487
|
+
readCandidates(c, conceptId) {
|
|
488
|
+
const posix = conceptId.replace(/\\/g, "/");
|
|
489
|
+
const slash = posix.indexOf("/");
|
|
490
|
+
if (slash <= 0)
|
|
491
|
+
return [{ path: path.join(c.root, `${posix}.md`), conceptId: posix }];
|
|
492
|
+
const head = posix.slice(0, slash);
|
|
493
|
+
const rest = posix.slice(slash + 1);
|
|
494
|
+
const type = stashDirToType(head);
|
|
495
|
+
return type === undefined || rest.length === 0
|
|
496
|
+
? []
|
|
497
|
+
: [{ path: assetPathForName(type, path.join(c.root, head), rest), conceptId: posix }];
|
|
498
|
+
},
|
|
449
499
|
/**
|
|
450
500
|
* Type-driven placement (§5.1), reproducing `path-resolver.ts#buildDiskCandidates`:
|
|
451
501
|
* the primary candidate is
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
* ── Cycle-safety (chunk-2 ratchet, baseline 18) ──
|
|
41
41
|
*
|
|
42
42
|
* Imported ONLY by `akm-adapter.ts` (no inbound `src/` edge) → can never join a
|
|
43
|
-
* cycle. It VALUE-imports `
|
|
44
|
-
*
|
|
43
|
+
* cycle. It VALUE-imports the one `compileWorkflowSource` frontend and the pure
|
|
44
|
+
* predicate `isDangerousEnvKey`
|
|
45
45
|
* from `commands/lint/env-key-rules` — the predicate is imported, not copied,
|
|
46
46
|
* precisely so the 40+ security-sensitive dangerous-key names cannot drift from
|
|
47
47
|
* the canonical set; importing it is ratchet-neutral (verified: 18). The small
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
*/
|
|
53
53
|
import path from "node:path";
|
|
54
54
|
import { isDangerousEnvKey } from "../../../commands/lint/env-key-rules.js";
|
|
55
|
-
import {
|
|
55
|
+
import { parseTaskV3Yaml, taskV3SourceErrorDetail } from "../../../tasks/source-v3.js";
|
|
56
56
|
import { compileWorkflowPlan } from "../../../workflows/ir/compile.js";
|
|
57
|
-
import {
|
|
57
|
+
import { compileWorkflowSource } from "../../../workflows/source-ir/compile.js";
|
|
58
58
|
import { conceptIdForStashFile } from "../../asset/resolve-ref.js";
|
|
59
59
|
/** Recommended `category` values for facts — `commands/lint/fact-linter.ts:9`. */
|
|
60
60
|
const KNOWN_CATEGORIES = new Set(["personal", "team", "project", "convention", "meta"]);
|
|
@@ -197,11 +197,8 @@ const AKM_SKILL_DIRS = new Set(["skills"]);
|
|
|
197
197
|
* (matching the per-subdir call). `file`/`detail` mirror the live check exactly
|
|
198
198
|
* (relDir + `no SKILL.md in <relDir>/`).
|
|
199
199
|
*
|
|
200
|
-
* `skillDirs` defaults to the akm-native `skills/` placement dir.
|
|
201
|
-
* adapters pass their
|
|
202
|
-
* singular `skill/` alias on read (`opencode-adapter.ts` LAYOUT) — with the
|
|
203
|
-
* gate hardcoded to `"skills"`, an identical manifest-less package went flagged
|
|
204
|
-
* under `skills/` and unflagged under `skill/` (issue #774).
|
|
200
|
+
* `skillDirs` defaults to the akm-native `skills/` placement dir. Tool-dir
|
|
201
|
+
* adapters pass their own canonical placement directory.
|
|
205
202
|
*/
|
|
206
203
|
export async function skillDirectoryDiagnostics(relPath, seen, ctx, skillDirs = AKM_SKILL_DIRS) {
|
|
207
204
|
const segments = relPath
|
|
@@ -225,7 +222,7 @@ export async function skillDirectoryDiagnostics(relPath, seen, ctx, skillDirs =
|
|
|
225
222
|
* routes through `ctx`.
|
|
226
223
|
*/
|
|
227
224
|
export async function perTypeValidateChecks(args) {
|
|
228
|
-
const { type, relPath, raw, data, frontmatter, body, ext, ctx } = args;
|
|
225
|
+
const { type, relPath, raw, data, frontmatter, body, ext, ctx, workspaceRoot } = args;
|
|
229
226
|
switch (type) {
|
|
230
227
|
case "command":
|
|
231
228
|
return nameOrTypeDiagnostics(relPath, data, frontmatter, ["command"]);
|
|
@@ -234,9 +231,9 @@ export async function perTypeValidateChecks(args) {
|
|
|
234
231
|
case "fact":
|
|
235
232
|
return factDiagnostics(relPath, data);
|
|
236
233
|
case "task":
|
|
237
|
-
return taskDiagnostics(relPath,
|
|
234
|
+
return taskDiagnostics(relPath, raw, workspaceRoot);
|
|
238
235
|
case "workflow":
|
|
239
|
-
//
|
|
236
|
+
// Markdown lint handles `.md`; peer GitHub-shaped `.yml` sources enter through the workflow source adapter.
|
|
240
237
|
return ext === ".md" ? workflowDiagnostics(relPath, raw, body) : [];
|
|
241
238
|
case "memory":
|
|
242
239
|
return memoryDiagnostics(relPath, data, body, ctx);
|
|
@@ -274,33 +271,29 @@ export function factDiagnostics(relPath, data) {
|
|
|
274
271
|
return [];
|
|
275
272
|
}
|
|
276
273
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* at least one target.
|
|
274
|
+
* Task validation has one semantic owner: the strict task-v3 source parser.
|
|
275
|
+
* Keeping raw YAML at this boundary preserves duplicate-key, alias/tag,
|
|
276
|
+
* source-location, descriptor, resource-bound, and migration-hint behavior.
|
|
281
277
|
*/
|
|
282
|
-
export function taskDiagnostics(relPath,
|
|
283
|
-
|
|
278
|
+
export function taskDiagnostics(relPath, raw, workspaceRoot) {
|
|
279
|
+
try {
|
|
280
|
+
parseTaskV3Yaml({
|
|
281
|
+
filePath: relPath,
|
|
282
|
+
yaml: raw,
|
|
283
|
+
...(workspaceRoot ? { workspaceRoot } : {}),
|
|
284
|
+
});
|
|
284
285
|
return [];
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// empty string is NOT a target there, so a `workflow: ""` that linted clean
|
|
288
|
-
// here failed at run time with MISSING_REQUIRED_ARGUMENT — a file the linter
|
|
289
|
-
// called valid but that could never run.
|
|
290
|
-
const hasTarget = ["prompt", "workflow", "command"].some((key) => isPresentTarget(data[key]));
|
|
291
|
-
if (!hasTarget)
|
|
292
|
-
missing.push("prompt, workflow, or command");
|
|
293
|
-
if (missing.length > 0) {
|
|
286
|
+
}
|
|
287
|
+
catch (cause) {
|
|
294
288
|
return [
|
|
295
289
|
{
|
|
296
290
|
file: relPath,
|
|
297
291
|
issue: "invalid-task-yaml",
|
|
298
|
-
detail:
|
|
292
|
+
detail: taskV3SourceErrorDetail(cause),
|
|
299
293
|
fixed: false,
|
|
300
294
|
},
|
|
301
295
|
];
|
|
302
296
|
}
|
|
303
|
-
return [];
|
|
304
297
|
}
|
|
305
298
|
/**
|
|
306
299
|
* The first placeholder marker present in a workflow body, or `null`
|
|
@@ -313,11 +306,10 @@ export function matchWorkflowPlaceholder(body) {
|
|
|
313
306
|
}
|
|
314
307
|
/**
|
|
315
308
|
* WorkflowLinter's `invalid-workflow-structure` check (`workflow-linter.ts:48-77`):
|
|
316
|
-
* the ERROR half of {@link workflowFrontendDiagnostics}, for
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* pairing this with a second view. NEVER writes.
|
|
309
|
+
* the ERROR half of {@link workflowFrontendDiagnostics}, for the read-only
|
|
310
|
+
* adapter `validate` path. A caller that ALSO surfaces advisories must call
|
|
311
|
+
* {@link workflowFrontendDiagnostics} once instead of pairing this with a
|
|
312
|
+
* second view. NEVER writes.
|
|
321
313
|
*/
|
|
322
314
|
export function workflowStructureDiagnostics(relPath, raw, parsePath) {
|
|
323
315
|
return workflowFrontendDiagnostics(relPath, raw, parsePath).errors;
|
|
@@ -333,6 +325,30 @@ export function workflowStructureDiagnostics(relPath, raw, parsePath) {
|
|
|
333
325
|
function lineOf(err) {
|
|
334
326
|
return typeof err.line === "number" && Number.isFinite(err.line) && err.line > 0 ? { line: err.line } : {};
|
|
335
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Compile one peer GitHub-shaped `.yml` source through the shared source-IR
|
|
330
|
+
* frontend. YAML has no Markdown frontmatter/base/stub pass and currently
|
|
331
|
+
* emits fatal source diagnostics only; keeping the same two-channel result
|
|
332
|
+
* shape lets the ordinary sweep and both workflow adapters route it exactly
|
|
333
|
+
* like the established Markdown frontend without inventing another parser.
|
|
334
|
+
*/
|
|
335
|
+
export function workflowYamlSourceDiagnostics(relPath, raw, parsePath, workspaceRoot) {
|
|
336
|
+
if (parsePath.includes("/.cache/") || parsePath.includes("/registry/"))
|
|
337
|
+
return { errors: [], warnings: [] };
|
|
338
|
+
const compiled = compileWorkflowSource(raw, { path: parsePath, workspaceRoot });
|
|
339
|
+
if (compiled.ok)
|
|
340
|
+
return { errors: [], warnings: [] };
|
|
341
|
+
return {
|
|
342
|
+
errors: compiled.errors.map((error) => ({
|
|
343
|
+
file: relPath,
|
|
344
|
+
issue: "invalid-workflow-structure",
|
|
345
|
+
detail: error.message,
|
|
346
|
+
fixed: false,
|
|
347
|
+
...lineOf(error),
|
|
348
|
+
})),
|
|
349
|
+
warnings: [],
|
|
350
|
+
};
|
|
351
|
+
}
|
|
336
352
|
/**
|
|
337
353
|
* ONE parse+compile of a workflow through the unified frontend, returning both
|
|
338
354
|
* halves of what it produces: fatal `invalid-workflow-structure` findings, and
|
|
@@ -340,9 +356,8 @@ function lineOf(err) {
|
|
|
340
356
|
* no `output:` schema, a reference to an undeclared param). The read-only
|
|
341
357
|
* `/.cache/` + `/registry/` cached copies are skipped, and nothing is written.
|
|
342
358
|
*
|
|
343
|
-
* `parsePath` is the
|
|
344
|
-
* change relPath
|
|
345
|
-
* caller's legacy behavior).
|
|
359
|
+
* `parsePath` is the source identity handed to `compileWorkflowSource` (the
|
|
360
|
+
* adapter passes the change relPath; the CLI passes the absolute filePath).
|
|
346
361
|
*
|
|
347
362
|
* A caller that surfaces BOTH halves must call this once and route the result
|
|
348
363
|
* itself. The frontend is expensive — instruction bodies reach
|
|
@@ -356,7 +371,7 @@ export function workflowFrontendDiagnostics(relPath, raw, parsePath) {
|
|
|
356
371
|
const errors = [];
|
|
357
372
|
const warnings = [];
|
|
358
373
|
try {
|
|
359
|
-
const result =
|
|
374
|
+
const result = compileWorkflowSource(raw, { path: parsePath });
|
|
360
375
|
if (!result.ok) {
|
|
361
376
|
for (const err of result.errors ?? []) {
|
|
362
377
|
errors.push({
|
|
@@ -369,7 +384,7 @@ export function workflowFrontendDiagnostics(relPath, raw, parsePath) {
|
|
|
369
384
|
}
|
|
370
385
|
return { errors, warnings };
|
|
371
386
|
}
|
|
372
|
-
const compiled = compileWorkflowPlan(result.
|
|
387
|
+
const compiled = compileWorkflowPlan(result.ir, path.basename(parsePath, path.extname(parsePath)));
|
|
373
388
|
if (!compiled.ok) {
|
|
374
389
|
for (const err of compiled.errors) {
|
|
375
390
|
errors.push({
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* lesson-frontmatter-metadata, memory-frontmatter-metadata,
|
|
15
15
|
* script-comment-metadata, env-file-metadata, secret-file-metadata,
|
|
16
16
|
* task-yaml-metadata, session-md-metadata, fact-md-metadata;
|
|
17
|
-
* - `workflows/renderer.ts` (1): workflow-document-metadata (
|
|
17
|
+
* - `workflows/renderer.ts` (1): workflow-document-metadata (the historical
|
|
18
|
+
* `workflow-md` renderer id now presents both peer workflow sources).
|
|
18
19
|
*
|
|
19
20
|
* ── Cycle-safety (chunk-2 ratchet, baseline 18) ──
|
|
20
21
|
*
|
|
@@ -22,9 +23,9 @@
|
|
|
22
23
|
* that file's header), so this leaf can never gain an inbound edge from a cycle
|
|
23
24
|
* participant and therefore can never JOIN a cycle. It VALUE-imports the pure
|
|
24
25
|
* parsers each contributor already uses so the fold cannot drift from them:
|
|
25
|
-
* `parseFrontmatter`, `parseMarkdownToc`,
|
|
26
|
-
* `
|
|
27
|
-
*
|
|
26
|
+
* `parseFrontmatter`, `parseMarkdownToc`, the peer-source
|
|
27
|
+
* `compileWorkflowSource` frontend/projection, and env key-name scanning.
|
|
28
|
+
* `output/renderers.ts` / `workflows/renderer.ts` are the
|
|
28
29
|
* cycle-sensitive modules whose contributor bodies live in this port — their
|
|
29
30
|
* ONE non-importable helper (`metadata.ts#extractDescriptionFromComments`, a
|
|
30
31
|
* heavy cycle-participant module) is copied verbatim below as
|
|
@@ -46,17 +47,17 @@
|
|
|
46
47
|
*
|
|
47
48
|
* Every contributor that reads/parses content is reproduced with the SAME
|
|
48
49
|
* try/catch tolerance it has today (toc/memory/session/fact/task swallow parse
|
|
49
|
-
* errors).
|
|
50
|
-
*
|
|
50
|
+
* errors). Workflow source compilation fails closed in the drain (a broken
|
|
51
|
+
* workflow is dropped); here the compile/projection is wrapped
|
|
51
52
|
* so a broken workflow yields no folded metadata instead of throwing out of the
|
|
52
53
|
* synchronous `recognize` — the drop-the-entry behavior is an index-drain
|
|
53
54
|
* concern (Chunk 4/5), not recognition's. On the valid Chunk-0b fixture this
|
|
54
55
|
* distinction never triggers.
|
|
55
56
|
*/
|
|
56
|
-
import
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
57
|
+
import { scanEnvKeyNames } from "../../../commands/env/env.js";
|
|
58
|
+
import { parseTaskV3Yaml } from "../../../tasks/source-v3.js";
|
|
59
|
+
import { compileWorkflowSource } from "../../../workflows/source-ir/compile.js";
|
|
60
|
+
import { sourceStepInstructions } from "../../../workflows/source-ir/program.js";
|
|
60
61
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
61
62
|
import { parseMarkdownToc } from "../../asset/markdown.js";
|
|
62
63
|
import { nonEmptyString } from "./shared.js";
|
|
@@ -67,14 +68,7 @@ import { nonEmptyString } from "./shared.js";
|
|
|
67
68
|
* others are imported). Reads a leading JSDoc block or hash-comment run from the
|
|
68
69
|
* script file; returns `null` on read/parse miss.
|
|
69
70
|
*/
|
|
70
|
-
function extractDescriptionFromComments(
|
|
71
|
-
let content;
|
|
72
|
-
try {
|
|
73
|
-
content = fs.readFileSync(filePath, "utf8");
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
71
|
+
function extractDescriptionFromComments(content) {
|
|
78
72
|
const lines = content.split(/\r?\n/).slice(0, 50);
|
|
79
73
|
const blockStart = lines.findIndex((l) => /^\s*\/\*\*/.test(l));
|
|
80
74
|
if (blockStart >= 0) {
|
|
@@ -210,7 +204,7 @@ export function foldRecognizedMetadata(rendererName, file) {
|
|
|
210
204
|
case "script-source": {
|
|
211
205
|
if (file.ext === ".md")
|
|
212
206
|
return out;
|
|
213
|
-
const commentDesc = extractDescriptionFromComments(file.
|
|
207
|
+
const commentDesc = extractDescriptionFromComments(file.content());
|
|
214
208
|
if (commentDesc && !out.description) {
|
|
215
209
|
out.description = commentDesc;
|
|
216
210
|
out.source = "comments";
|
|
@@ -220,7 +214,7 @@ export function foldRecognizedMetadata(rendererName, file) {
|
|
|
220
214
|
}
|
|
221
215
|
// ── env-file-metadata (env-file) ──
|
|
222
216
|
case "env-file": {
|
|
223
|
-
const
|
|
217
|
+
const keys = scanEnvKeyNames(file.content());
|
|
224
218
|
if (keys.length > 0)
|
|
225
219
|
out.searchHints = keys;
|
|
226
220
|
out.tags = Array.from(new Set([...(out.tags ?? []), "env", "secrets"]));
|
|
@@ -235,18 +229,25 @@ export function foldRecognizedMetadata(rendererName, file) {
|
|
|
235
229
|
case "task-yaml": {
|
|
236
230
|
out.tags = Array.from(new Set([...(out.tags ?? []), "task", "scheduled"]));
|
|
237
231
|
try {
|
|
238
|
-
const
|
|
239
|
-
const data = doc && typeof doc === "object" && !Array.isArray(doc) ? doc : {};
|
|
232
|
+
const task = parseTaskV3Yaml({ yaml: file.content(), filePath: file.absPath, workspaceRoot: file.stashRoot });
|
|
240
233
|
const hints = new Set();
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
234
|
+
for (const binding of task.triggers.schedules)
|
|
235
|
+
hints.add(`schedule:${binding.cron}`);
|
|
236
|
+
if (task.target.kind === "uses") {
|
|
237
|
+
if (task.target.uses.kind === "workflow")
|
|
238
|
+
hints.add(`workflow:${task.target.uses.ref}`);
|
|
239
|
+
else if (task.target.uses.kind === "command")
|
|
240
|
+
hints.add(`prompt:${task.target.uses.ref}`);
|
|
241
|
+
else if (task.target.command?.kind === "inline")
|
|
242
|
+
hints.add(`prompt:${task.target.command.content}`);
|
|
243
|
+
else if (task.target.command?.kind === "stored")
|
|
244
|
+
hints.add(`prompt:${task.target.command.ref}`);
|
|
245
|
+
else
|
|
246
|
+
hints.add(`uses:${task.target.uses.ref}`);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
hints.add(`run:${task.target.run}`);
|
|
250
|
+
}
|
|
250
251
|
finalizeHints(out, hints);
|
|
251
252
|
}
|
|
252
253
|
catch {
|
|
@@ -301,26 +302,25 @@ export function foldRecognizedMetadata(rendererName, file) {
|
|
|
301
302
|
}
|
|
302
303
|
return out;
|
|
303
304
|
}
|
|
304
|
-
// ── workflow-document-metadata (workflow-md) ──
|
|
305
|
+
// ── workflow-document-metadata (historical renderer id `workflow-md`, peer sources) ──
|
|
305
306
|
case "workflow-md": {
|
|
306
307
|
try {
|
|
307
|
-
const result =
|
|
308
|
+
const result = compileWorkflowSource(file.content(), { path: file.relPath, workspaceRoot: file.stashRoot });
|
|
308
309
|
if (!result.ok)
|
|
309
310
|
return out;
|
|
310
|
-
const
|
|
311
|
+
const sourceIr = result.ir;
|
|
311
312
|
const hints = new Set();
|
|
312
|
-
if (
|
|
313
|
-
hints.add(
|
|
314
|
-
for (const step of
|
|
313
|
+
if (sourceIr.preamble)
|
|
314
|
+
hints.add(sourceIr.preamble);
|
|
315
|
+
for (const step of sourceIr.jobs.flatMap((job) => job.steps)) {
|
|
315
316
|
hints.add(step.id);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
hints.add(step.gateRubric.text);
|
|
317
|
+
hints.add(sourceStepInstructions(step));
|
|
318
|
+
if (step.gate?.rubric)
|
|
319
|
+
hints.add(step.gate.rubric);
|
|
320
320
|
}
|
|
321
321
|
out.searchHints = Array.from(hints).filter(Boolean);
|
|
322
|
-
if (
|
|
323
|
-
const parameters = Object.entries(
|
|
322
|
+
if (sourceIr.params) {
|
|
323
|
+
const parameters = Object.entries(sourceIr.params).map(([name, schema]) => {
|
|
324
324
|
const description = schema.description;
|
|
325
325
|
return { name, ...(typeof description === "string" && description ? { description } : {}) };
|
|
326
326
|
});
|
|
@@ -348,8 +348,8 @@ export function foldRecognizedMetadata(rendererName, file) {
|
|
|
348
348
|
* Precedence, verified against every case in {@link foldRecognizedMetadata}:
|
|
349
349
|
* - description/source/confidence travel together and only when the entry has
|
|
350
350
|
* no description yet (contributors gate on `!entry.description`); a
|
|
351
|
-
* contributor that sets description WITHOUT source/confidence
|
|
352
|
-
*
|
|
351
|
+
* contributor that sets description WITHOUT source/confidence leaves those
|
|
352
|
+
* untouched — mirrored by the
|
|
353
353
|
* `folded.source`/`folded.confidence` guards below;
|
|
354
354
|
* - tags UNION into the existing set (order-preserving Set dedup), matching the
|
|
355
355
|
* contributors' `Array.from(new Set([...entry.tags, ...added]))`;
|