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
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { prepareCommandInvocation } from "../../commands/command/command-execution.js";
|
|
9
|
+
import { loadAdapterExecutionSource } from "../../commands/command/execution-source-loader.js";
|
|
10
|
+
import { makeBundleRef, parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
11
|
+
import { parseEnvRef } from "../../core/env-secret-ref.js";
|
|
12
|
+
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
13
|
+
import { captureFrozenDirectoryIdentity } from "../../execution/directory-identity.js";
|
|
14
|
+
import { freezeExecutableIdentity } from "../../execution/executable-identity.js";
|
|
15
|
+
import { canonicalResolvedExecutionRequest, decodeResolvedExecutionRequest, } from "../../execution/resolved-request.js";
|
|
16
|
+
import { deriveInstallations } from "../../indexer/installations.js";
|
|
17
|
+
import { resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
18
|
+
import { fallbackAnnouncement } from "../../integrations/agent/engine-fallback.js";
|
|
19
|
+
import { requireAuthorizedExecutionPlan } from "../../integrations/agent/execution-cascade.js";
|
|
20
|
+
import { lowerResolvedExecutionRequest } from "../../integrations/agent/execution-lowering.js";
|
|
21
|
+
import { prepareInlineExecution } from "../../integrations/agent/inline-execution.js";
|
|
22
|
+
import { resolveAssetPath } from "../../sources/resolve.js";
|
|
23
|
+
import { prepareTaskV3Execution, } from "../../tasks/runtime-v3.js";
|
|
24
|
+
import { parseTaskV3Yaml } from "../../tasks/source-v3.js";
|
|
25
|
+
import { defaultLlmEngineConcurrency } from "../concurrency-policy.js";
|
|
26
|
+
import { DEFAULT_EXEC_TIMEOUT_MS } from "../resource-limits.js";
|
|
27
|
+
import { compileWorkflowSource } from "../source-ir/compile.js";
|
|
28
|
+
import { sourceStepProgramUnit, sourceStepRef, workflowShellCommand } from "../source-ir/program.js";
|
|
29
|
+
import { classifyWorkflowStepUses } from "../source-ir/semantics.js";
|
|
30
|
+
import { freezeWorkflowEnvironment } from "./environment-v4.js";
|
|
31
|
+
/** Resolve every authored target through the shared command/task authorities before v4 publication. */
|
|
32
|
+
export async function resolveWorkflowSourceV4(asset, workflowSource, config, collector) {
|
|
33
|
+
const compiled = compileWorkflowSource(workflowSource.content, { path: asset.path, workspaceRoot: asset.sourcePath });
|
|
34
|
+
if (!compiled.ok) {
|
|
35
|
+
throw new UsageError(`Workflow source cannot be frozen: ${compiled.errors.map((error) => error.message).join("; ")}`, "INVALID_FLAG_VALUE");
|
|
36
|
+
}
|
|
37
|
+
if (compiled.ir.jobs.length !== 1) {
|
|
38
|
+
throw new UsageError("Multi-job workflow cannot execute until job boundaries and needs have a durable runtime representation.", "INVALID_FLAG_VALUE");
|
|
39
|
+
}
|
|
40
|
+
const context = { asset, config, collector, sourceIr: compiled.ir };
|
|
41
|
+
const units = new Map();
|
|
42
|
+
const judges = new Map();
|
|
43
|
+
let engineAnnouncement;
|
|
44
|
+
const sourceSteps = compiled.ir.jobs[0]?.steps ?? [];
|
|
45
|
+
for (const sourceStep of sourceSteps) {
|
|
46
|
+
if (!sourceStep.route) {
|
|
47
|
+
const resolved = await resolveStep(sourceStep, context);
|
|
48
|
+
units.set(sourceStep.id, Object.freeze(resolved));
|
|
49
|
+
engineAnnouncement ??= resolved.engineAnnouncement;
|
|
50
|
+
}
|
|
51
|
+
if (sourceStep.gate?.rubric?.trim()) {
|
|
52
|
+
const judge = resolveJudge(sourceStep, context);
|
|
53
|
+
if (judge.target.kind !== "command")
|
|
54
|
+
throw new Error(`workflow judge ${sourceStep.id} did not resolve to a command target`);
|
|
55
|
+
judges.set(sourceStep.id, judge.target);
|
|
56
|
+
engineAnnouncement ??= judge.engineAnnouncement;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return Object.freeze({
|
|
60
|
+
sourceIr: compiled.ir,
|
|
61
|
+
units,
|
|
62
|
+
judges,
|
|
63
|
+
...(engineAnnouncement ? { engineAnnouncement } : {}),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function resolveStep(source, context) {
|
|
67
|
+
const baseUnit = sourceStepProgramUnit(source);
|
|
68
|
+
if (source.exec || source.run !== undefined)
|
|
69
|
+
return directShell(source, baseUnit, context);
|
|
70
|
+
if (!source.uses)
|
|
71
|
+
return inlineDispatch(source, baseUnit, context);
|
|
72
|
+
const target = classifyWorkflowStepUses(source.uses);
|
|
73
|
+
if (target.kind === "task")
|
|
74
|
+
return taskDispatch(source, baseUnit, target.ref, context);
|
|
75
|
+
if (target.kind === "script")
|
|
76
|
+
return directScript(source, baseUnit, target.ref, context);
|
|
77
|
+
if (target.kind === "command" || target.kind === "builtin-command") {
|
|
78
|
+
const action = target.kind === "builtin-command"
|
|
79
|
+
? source.with
|
|
80
|
+
: { ref: qualifyRef(target.ref, "commands", context.asset, context.config) };
|
|
81
|
+
return commandDispatch(source, baseUnit, action, context);
|
|
82
|
+
}
|
|
83
|
+
throw new UsageError(`Workflow target ${source.uses} is not executable in 0.9.2.`, "INVALID_FLAG_VALUE");
|
|
84
|
+
}
|
|
85
|
+
async function commandDispatch(source, baseUnit, action, context) {
|
|
86
|
+
const prepared = await prepareCommandInvocation({
|
|
87
|
+
action,
|
|
88
|
+
config: context.config,
|
|
89
|
+
invocationKind: "workflow",
|
|
90
|
+
...(context.sourceIr.defaults
|
|
91
|
+
? { invocationDefaults: executionUnitValues(context.sourceIr.defaults, context.asset.sourcePath) }
|
|
92
|
+
: {}),
|
|
93
|
+
...(source.commandMode === "literal" ? { inlineContentMode: "literal" } : {}),
|
|
94
|
+
current: executionValues(source, context.asset.sourcePath),
|
|
95
|
+
sourceLoader: (ref, kind) => guardedExecutionSource(ref, kind, context),
|
|
96
|
+
});
|
|
97
|
+
return commandResult(source, baseUnit, prepared, context);
|
|
98
|
+
}
|
|
99
|
+
function inlineDispatch(source, baseUnit, context) {
|
|
100
|
+
const content = source.instructions ?? `Execute workflow step ${source.id}.`;
|
|
101
|
+
const prepared = prepareInlineExecution({
|
|
102
|
+
content,
|
|
103
|
+
config: context.config,
|
|
104
|
+
invocationKind: "workflow",
|
|
105
|
+
...(context.sourceIr.defaults
|
|
106
|
+
? { invocationDefaults: executionUnitValues(context.sourceIr.defaults, context.asset.sourcePath) }
|
|
107
|
+
: {}),
|
|
108
|
+
current: executionValues(source, context.asset.sourcePath),
|
|
109
|
+
});
|
|
110
|
+
return commandResult(source, baseUnit, prepared, context);
|
|
111
|
+
}
|
|
112
|
+
function resolveJudge(source, context) {
|
|
113
|
+
const engine = context.config.workflow?.judgeEngine;
|
|
114
|
+
if (!engine) {
|
|
115
|
+
throw new ConfigError("This workflow declares completion criteria but no verification engine is configured. Set workflow.judgeEngine to a named LLM or agent engine.", "INVALID_CONFIG_FILE");
|
|
116
|
+
}
|
|
117
|
+
const content = source.gate?.rubric?.trim() ?? "Judge workflow completion.";
|
|
118
|
+
const prepared = prepareInlineExecution({
|
|
119
|
+
content,
|
|
120
|
+
config: context.config,
|
|
121
|
+
invocationKind: "workflow",
|
|
122
|
+
current: { engine },
|
|
123
|
+
});
|
|
124
|
+
return commandResult(source, { onError: "fail", source: sourceStepRef(source) }, prepared, context);
|
|
125
|
+
}
|
|
126
|
+
async function taskDispatch(source, baseUnit, refInput, context) {
|
|
127
|
+
const owned = await resolveOwnedAsset(refInput, "task", context);
|
|
128
|
+
const retained = captureOwned(owned, context.collector);
|
|
129
|
+
const task = parseTaskV3Yaml({ yaml: retained.content, filePath: owned.file, workspaceRoot: owned.root });
|
|
130
|
+
if (task.target.kind === "uses" && task.target.uses.kind === "workflow") {
|
|
131
|
+
throw new UsageError("A workflow task step cannot compose a nested workflow target.", "INVALID_FLAG_VALUE");
|
|
132
|
+
}
|
|
133
|
+
const prepared = await prepareTaskV3Execution(task, {
|
|
134
|
+
taskId: parseBundleRef(owned.ref).conceptId.slice("tasks/".length),
|
|
135
|
+
taskRef: owned.ref,
|
|
136
|
+
bundleName: owned.bundle,
|
|
137
|
+
bundleRoot: owned.root,
|
|
138
|
+
config: context.config,
|
|
139
|
+
commandSourceLoader: (ref, kind) => guardedExecutionSource(ref, kind, context),
|
|
140
|
+
resolveAsset: async ({ ref, type }) => {
|
|
141
|
+
const target = await resolveOwnedAsset(ref, type, context);
|
|
142
|
+
captureOwned(target, context.collector);
|
|
143
|
+
return { file: target.file, bundleRoot: target.root };
|
|
144
|
+
},
|
|
145
|
+
readFile: (file, root = owned.root) => context.collector.readBytes(file, root),
|
|
146
|
+
});
|
|
147
|
+
if (prepared.kind === "workflow") {
|
|
148
|
+
throw new UsageError("A workflow task step cannot compose a nested workflow target.", "INVALID_FLAG_VALUE");
|
|
149
|
+
}
|
|
150
|
+
const taskLiterals = Object.entries(prepared.environment).map(([name, value]) => Object.freeze({ kind: "literal", name, value }));
|
|
151
|
+
if (prepared.kind === "command") {
|
|
152
|
+
return commandResult(source, baseUnit, prepared.invocation, context, taskLiterals);
|
|
153
|
+
}
|
|
154
|
+
if (prepared.kind === "shell") {
|
|
155
|
+
const authoredExec = {
|
|
156
|
+
command: workflowShellCommand(prepared.shell, prepared.command),
|
|
157
|
+
...(prepared.cwdIdentity.realCwd !== prepared.cwdIdentity.realRoot
|
|
158
|
+
? { cwd: path.relative(prepared.cwdIdentity.realRoot, prepared.cwdIdentity.realCwd) }
|
|
159
|
+
: {}),
|
|
160
|
+
};
|
|
161
|
+
const exec = freezeExecSpec(source, authoredExec, context);
|
|
162
|
+
const environment = Object.freeze([...taskLiterals, ...freezeEnvironment(source, authoredExec, context)]);
|
|
163
|
+
const executable = freezeExecutableIdentity(exec.command[0], { cwd: prepared.cwdIdentity.realCwd });
|
|
164
|
+
const target = Object.freeze({
|
|
165
|
+
kind: "shell",
|
|
166
|
+
contentHash: "",
|
|
167
|
+
exec,
|
|
168
|
+
cwdIdentity: prepared.cwdIdentity,
|
|
169
|
+
executable,
|
|
170
|
+
...gitIdentity(baseUnit, prepared.cwdIdentity.realRoot),
|
|
171
|
+
});
|
|
172
|
+
return {
|
|
173
|
+
target,
|
|
174
|
+
environment,
|
|
175
|
+
unit: { ...baseUnit, exec: authoredExec },
|
|
176
|
+
instructions: source.instructions ?? `Run task ${owned.ref}.`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return scriptResult(source, baseUnit, prepared, context, taskLiterals);
|
|
180
|
+
}
|
|
181
|
+
async function directScript(source, baseUnit, refInput, context) {
|
|
182
|
+
const owned = await resolveOwnedAsset(refInput, "script", context);
|
|
183
|
+
captureOwned(owned, context.collector);
|
|
184
|
+
const synthetic = parseTaskV3Yaml({
|
|
185
|
+
yaml: `version: 3\nuses: ${owned.ref}\nakm:\n schedule: "@daily"\n`,
|
|
186
|
+
filePath: `${context.asset.path}#${source.id}`,
|
|
187
|
+
workspaceRoot: context.asset.sourcePath,
|
|
188
|
+
});
|
|
189
|
+
const prepared = await prepareTaskV3Execution(synthetic, {
|
|
190
|
+
taskId: source.id,
|
|
191
|
+
taskRef: `${context.asset.ref}#${source.id}`,
|
|
192
|
+
bundleName: parseBundleRef(context.asset.ref).bundle ?? owned.bundle,
|
|
193
|
+
bundleRoot: context.asset.sourcePath,
|
|
194
|
+
config: context.config,
|
|
195
|
+
resolveAsset: async () => ({ file: owned.file, bundleRoot: owned.root }),
|
|
196
|
+
readFile: () => context.collector.readBytes(owned.file, owned.root),
|
|
197
|
+
});
|
|
198
|
+
if (prepared.kind !== "script")
|
|
199
|
+
throw new Error("direct script did not project as a script");
|
|
200
|
+
return scriptResult(source, baseUnit, prepared, context, []);
|
|
201
|
+
}
|
|
202
|
+
function scriptResult(source, baseUnit, prepared, context, literals) {
|
|
203
|
+
const requestedExecutable = scriptExecutable(prepared.interpreter);
|
|
204
|
+
const executable = freezeExecutableIdentity(requestedExecutable, { cwd: prepared.cwdIdentity.realCwd });
|
|
205
|
+
const authoredExec = { command: [executable.absolutePath, "<frozen-script>"] };
|
|
206
|
+
const exec = freezeExecSpec(source, authoredExec, context);
|
|
207
|
+
const environment = Object.freeze([...literals, ...freezeEnvironment(source, authoredExec, context)]);
|
|
208
|
+
const target = Object.freeze({
|
|
209
|
+
kind: "script",
|
|
210
|
+
ref: prepared.sourceRef,
|
|
211
|
+
contentHash: prepared.sha256,
|
|
212
|
+
exec,
|
|
213
|
+
interpreter: prepared.interpreter,
|
|
214
|
+
extension: prepared.extension,
|
|
215
|
+
bytesBase64: prepared.bytesBase64,
|
|
216
|
+
byteLength: prepared.byteLength,
|
|
217
|
+
cwdIdentity: prepared.cwdIdentity,
|
|
218
|
+
materialization: "ephemeral-0700-delete",
|
|
219
|
+
executable,
|
|
220
|
+
...gitIdentity(baseUnit, prepared.cwdIdentity.realRoot),
|
|
221
|
+
});
|
|
222
|
+
return {
|
|
223
|
+
target,
|
|
224
|
+
environment,
|
|
225
|
+
unit: { ...baseUnit, exec: authoredExec },
|
|
226
|
+
instructions: source.instructions ?? `Run script ${prepared.sourceRef}.`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function directShell(source, baseUnit, context) {
|
|
230
|
+
const authoredExec = baseUnit.exec;
|
|
231
|
+
if (!authoredExec)
|
|
232
|
+
throw new Error(`workflow shell step ${source.id} lost its source-IR execution spec`);
|
|
233
|
+
const exec = freezeExecSpec(source, authoredExec, context);
|
|
234
|
+
const cwdIdentity = captureFrozenDirectoryIdentity(context.asset.sourcePath, authoredExec.cwd);
|
|
235
|
+
const executable = freezeExecutableIdentity(authoredExec.command[0], { cwd: cwdIdentity.realCwd });
|
|
236
|
+
const environment = Object.freeze(freezeEnvironment(source, authoredExec, context));
|
|
237
|
+
const target = Object.freeze({
|
|
238
|
+
kind: "shell",
|
|
239
|
+
contentHash: "",
|
|
240
|
+
exec,
|
|
241
|
+
cwdIdentity,
|
|
242
|
+
executable,
|
|
243
|
+
...gitIdentity(baseUnit, cwdIdentity.realRoot),
|
|
244
|
+
});
|
|
245
|
+
return {
|
|
246
|
+
target,
|
|
247
|
+
environment,
|
|
248
|
+
unit: { ...baseUnit, exec },
|
|
249
|
+
instructions: source.instructions ?? `Run ${source.run ?? authoredExec.command.join(" ")}.`,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function commandResult(source, baseUnit, prepared, context, literals = []) {
|
|
253
|
+
const request = durableRequest(requireAuthorizedExecutionPlan(prepared.plan));
|
|
254
|
+
const lowered = lowerResolvedExecutionRequest(request, prepared.config);
|
|
255
|
+
const cwdIdentity = captureFrozenDirectoryIdentity(context.asset.sourcePath);
|
|
256
|
+
let runner = lowered.runner;
|
|
257
|
+
let executable;
|
|
258
|
+
if (runner.kind === "agent") {
|
|
259
|
+
executable = freezeExecutableIdentity(runner.profile.bin, { cwd: cwdIdentity.realCwd });
|
|
260
|
+
runner = Object.freeze({ ...runner, profile: Object.freeze({ ...runner.profile, bin: executable.absolutePath }) });
|
|
261
|
+
}
|
|
262
|
+
const unit = {
|
|
263
|
+
...baseUnit,
|
|
264
|
+
engine: request.engine.name,
|
|
265
|
+
...(request.model ? { model: request.model.resolved } : {}),
|
|
266
|
+
...(Object.hasOwn(request.runtime, "timeoutMs") ? { timeoutMs: request.runtime.timeoutMs } : {}),
|
|
267
|
+
...(request.inference ? { llm: request.inference } : {}),
|
|
268
|
+
...(request.outputSchema ? { output: request.outputSchema } : {}),
|
|
269
|
+
};
|
|
270
|
+
const environment = Object.freeze([...literals, ...freezeEnvironment(source, undefined, context)]);
|
|
271
|
+
const target = Object.freeze({
|
|
272
|
+
kind: "command",
|
|
273
|
+
ref: request.command.source?.ref ?? null,
|
|
274
|
+
contentHash: createHash("sha256").update(request.command.content).digest("hex"),
|
|
275
|
+
request: JSON.parse(canonicalResolvedExecutionRequest(request)),
|
|
276
|
+
runner,
|
|
277
|
+
...(targetConcurrency(runner, context.config) ? { concurrency: targetConcurrency(runner, context.config) } : {}),
|
|
278
|
+
cwdIdentity,
|
|
279
|
+
...(executable ? { executable } : {}),
|
|
280
|
+
...gitIdentity(baseUnit, cwdIdentity.realRoot),
|
|
281
|
+
});
|
|
282
|
+
const engineAnnouncement = fallbackAnnouncement(prepared.fallbackEngineName, request.engine.name);
|
|
283
|
+
return {
|
|
284
|
+
target,
|
|
285
|
+
environment,
|
|
286
|
+
unit,
|
|
287
|
+
instructions: request.command.content,
|
|
288
|
+
...(engineAnnouncement ? { engineAnnouncement } : {}),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function freezeExecSpec(source, exec, context) {
|
|
292
|
+
const declared = Object.hasOwn(source.unit ?? {}, "timeoutMs")
|
|
293
|
+
? source.unit?.timeoutMs
|
|
294
|
+
: context.sourceIr.defaults && Object.hasOwn(context.sourceIr.defaults, "timeoutMs")
|
|
295
|
+
? context.sourceIr.defaults.timeoutMs
|
|
296
|
+
: undefined;
|
|
297
|
+
return {
|
|
298
|
+
...exec,
|
|
299
|
+
command: exec.command,
|
|
300
|
+
timeoutMs: declared === undefined ? DEFAULT_EXEC_TIMEOUT_MS : declared,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function targetConcurrency(runner, config) {
|
|
304
|
+
if (runner.kind === "llm") {
|
|
305
|
+
const configured = typeof runner.engine === "string" ? config.engines?.[runner.engine] : undefined;
|
|
306
|
+
return defaultLlmEngineConcurrency(runner.connection.endpoint, configured?.kind === "llm" ? configured.concurrency : undefined);
|
|
307
|
+
}
|
|
308
|
+
if (runner.kind !== "sdk" || !runner.fallbackConnection)
|
|
309
|
+
return undefined;
|
|
310
|
+
const selected = typeof runner.engine === "string" ? config.engines?.[runner.engine] : undefined;
|
|
311
|
+
const fallbackName = selected?.kind === "agent" ? (selected.llmEngine ?? config.defaults?.llmEngine) : undefined;
|
|
312
|
+
const fallback = fallbackName ? config.engines?.[fallbackName] : undefined;
|
|
313
|
+
return defaultLlmEngineConcurrency(runner.fallbackConnection.endpoint, fallback?.kind === "llm" ? fallback.concurrency : undefined);
|
|
314
|
+
}
|
|
315
|
+
function durableRequest(request) {
|
|
316
|
+
const wire = JSON.parse(canonicalResolvedExecutionRequest(request));
|
|
317
|
+
const runtime = { ...wire.runtime };
|
|
318
|
+
delete runtime.environment;
|
|
319
|
+
wire.runtime = runtime;
|
|
320
|
+
return decodeResolvedExecutionRequest(wire);
|
|
321
|
+
}
|
|
322
|
+
function executionValues(source, workspace) {
|
|
323
|
+
return executionUnitValues(source.unit, workspace);
|
|
324
|
+
}
|
|
325
|
+
function executionUnitValues(unit, workspace) {
|
|
326
|
+
return Object.freeze({
|
|
327
|
+
...(unit && Object.hasOwn(unit, "engine") ? { engine: unit.engine } : {}),
|
|
328
|
+
...(unit && Object.hasOwn(unit, "model") ? { model: unit.model } : {}),
|
|
329
|
+
...(unit && Object.hasOwn(unit, "llm") ? { inference: unit.llm } : {}),
|
|
330
|
+
...(unit && Object.hasOwn(unit, "timeoutMs") ? { timeout: unit.timeoutMs } : {}),
|
|
331
|
+
...(unit && "output" in unit && Object.hasOwn(unit, "output") ? { outputSchema: unit.output } : {}),
|
|
332
|
+
workspace,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function freezeEnvironment(source, exec, context) {
|
|
336
|
+
const literals = Object.entries(source.env ?? {}).map(([name, value]) => Object.freeze({ kind: "literal", name, value: String(value) }));
|
|
337
|
+
const passThrough = (exec?.passEnv ?? []).map((name) => Object.freeze({ kind: "pass-through", name }));
|
|
338
|
+
const refs = source.unit?.env ?? [];
|
|
339
|
+
const envRefs = freezeWorkflowEnvironment(refs, {
|
|
340
|
+
collector: context.collector,
|
|
341
|
+
resolveRef: (ref) => {
|
|
342
|
+
const parsedEnv = parseEnvRef(ref);
|
|
343
|
+
if (parsedEnv.type !== "env")
|
|
344
|
+
throw new UsageError(`Expected an env ref; got ${ref}.`, "INVALID_FLAG_VALUE");
|
|
345
|
+
const owned = resolveOwnedAssetSync(ref, "env", context);
|
|
346
|
+
return { ref: owned.ref, bundle: owned.bundle, adapter: owned.adapter, root: owned.root, path: owned.file };
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
return [...literals, ...passThrough, ...envRefs];
|
|
350
|
+
}
|
|
351
|
+
async function guardedExecutionSource(ref, kind, context) {
|
|
352
|
+
const owned = await resolveOwnedAsset(ref, kind === "command" ? "command" : "agent", context);
|
|
353
|
+
captureOwned(owned, context.collector);
|
|
354
|
+
const options = {
|
|
355
|
+
config: context.config,
|
|
356
|
+
fileContext: () => context.collector.fileContext(owned.root, owned.file),
|
|
357
|
+
};
|
|
358
|
+
const rendered = kind === "command"
|
|
359
|
+
? await loadAdapterExecutionSource(owned.ref, "command", options)
|
|
360
|
+
: await loadAdapterExecutionSource(owned.ref, "persona", options);
|
|
361
|
+
context.collector.bindIdentity(owned.file, owned.root, rendered.identity);
|
|
362
|
+
return rendered;
|
|
363
|
+
}
|
|
364
|
+
async function resolveOwnedAsset(ref, type, context) {
|
|
365
|
+
return resolveOwnedAssetCore(ref, type, context, false);
|
|
366
|
+
}
|
|
367
|
+
function resolveOwnedAssetSync(ref, type, context) {
|
|
368
|
+
return resolveOwnedAssetCore(ref, type, context, true);
|
|
369
|
+
}
|
|
370
|
+
function resolveOwnedAssetCore(refInput, type, context, sync) {
|
|
371
|
+
const parsed = parseBundleRef(refInput);
|
|
372
|
+
const plural = type === "env" ? "env" : `${type}s`;
|
|
373
|
+
const conceptId = parsed.conceptId.startsWith(`${plural}/`) ? parsed.conceptId : `${plural}/${parsed.conceptId}`;
|
|
374
|
+
const name = conceptId.slice(plural.length + 1);
|
|
375
|
+
const direct = parsed.bundle ? configuredOwner(parsed.bundle, context.config) : undefined;
|
|
376
|
+
const sources = resolveSourceEntries(undefined, context.config);
|
|
377
|
+
const installations = deriveInstallations(sources);
|
|
378
|
+
const candidates = direct
|
|
379
|
+
? [direct]
|
|
380
|
+
: sources.flatMap((source, index) => {
|
|
381
|
+
const installation = installations[index];
|
|
382
|
+
if (!installation || (parsed.bundle && installation.id !== parsed.bundle))
|
|
383
|
+
return [];
|
|
384
|
+
return [
|
|
385
|
+
{
|
|
386
|
+
bundle: installation.id,
|
|
387
|
+
root: source.path,
|
|
388
|
+
adapter: source.adapterId ?? installation.components[0]?.adapter ?? "akm",
|
|
389
|
+
},
|
|
390
|
+
];
|
|
391
|
+
});
|
|
392
|
+
const findSync = () => {
|
|
393
|
+
for (const candidate of candidates) {
|
|
394
|
+
const directory = path.join(candidate.root, plural);
|
|
395
|
+
for (const extension of assetExtensions(type)) {
|
|
396
|
+
const file = path.resolve(directory, `${name}${extension}`);
|
|
397
|
+
if (fs.existsSync(file) && fs.statSync(file).isFile()) {
|
|
398
|
+
return { ...candidate, ref: makeBundleRef(candidate.bundle, conceptId), file };
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
throw new UsageError(`Workflow source target ${refInput} was not found.`, "INVALID_FLAG_VALUE");
|
|
403
|
+
};
|
|
404
|
+
if (sync)
|
|
405
|
+
return findSync();
|
|
406
|
+
return (async () => {
|
|
407
|
+
for (const candidate of candidates) {
|
|
408
|
+
try {
|
|
409
|
+
const file = await resolveAssetPath(candidate.root, type, name);
|
|
410
|
+
return { ...candidate, ref: makeBundleRef(candidate.bundle, conceptId), file };
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
// Continue in installation priority order.
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return findSync();
|
|
417
|
+
})();
|
|
418
|
+
}
|
|
419
|
+
function configuredOwner(bundle, config) {
|
|
420
|
+
const entry = config.bundles?.[bundle];
|
|
421
|
+
if (!entry || typeof entry.path !== "string")
|
|
422
|
+
return undefined;
|
|
423
|
+
const components = entry.components ? Object.values(entry.components) : [];
|
|
424
|
+
const component = components[0];
|
|
425
|
+
return {
|
|
426
|
+
bundle,
|
|
427
|
+
root: path.resolve(entry.path, component?.root ?? "."),
|
|
428
|
+
adapter: component?.adapter ?? "akm",
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function assetExtensions(type) {
|
|
432
|
+
if (type === "script")
|
|
433
|
+
return [
|
|
434
|
+
"",
|
|
435
|
+
".sh",
|
|
436
|
+
".ts",
|
|
437
|
+
".js",
|
|
438
|
+
".py",
|
|
439
|
+
".rb",
|
|
440
|
+
".go",
|
|
441
|
+
".pl",
|
|
442
|
+
".php",
|
|
443
|
+
".lua",
|
|
444
|
+
".r",
|
|
445
|
+
".swift",
|
|
446
|
+
".kt",
|
|
447
|
+
".kts",
|
|
448
|
+
".ps1",
|
|
449
|
+
".cmd",
|
|
450
|
+
".bat",
|
|
451
|
+
];
|
|
452
|
+
if (type === "env")
|
|
453
|
+
return ["", ".env"];
|
|
454
|
+
return ["", ".md", ".yml"];
|
|
455
|
+
}
|
|
456
|
+
function captureOwned(owned, collector) {
|
|
457
|
+
trackAncestry(collector, owned.root, owned.file);
|
|
458
|
+
const retained = collector.capture(owned.file, owned.root, { authored: true });
|
|
459
|
+
return collector.bindIdentity(owned.file, owned.root, {
|
|
460
|
+
ref: owned.ref,
|
|
461
|
+
bundle: owned.bundle,
|
|
462
|
+
adapter: owned.adapter,
|
|
463
|
+
file: retained.relativePath,
|
|
464
|
+
hash: retained.sha256,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
function trackAncestry(collector, rootInput, file) {
|
|
468
|
+
const root = path.resolve(rootInput);
|
|
469
|
+
collector.trackDirectory(root, root);
|
|
470
|
+
const relative = path.relative(root, path.dirname(file));
|
|
471
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
472
|
+
throw new UsageError(`${file} resolves outside its owning root.`, "PATH_ESCAPE_VIOLATION");
|
|
473
|
+
}
|
|
474
|
+
let current = root;
|
|
475
|
+
for (const segment of relative === "" ? [] : relative.split(path.sep)) {
|
|
476
|
+
current = path.join(current, segment);
|
|
477
|
+
collector.trackDirectory(current, root);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function qualifyRef(ref, plural, asset, config) {
|
|
481
|
+
const parsed = parseBundleRef(ref);
|
|
482
|
+
if (parsed.bundle)
|
|
483
|
+
return ref;
|
|
484
|
+
const bundle = parseBundleRef(asset.ref).bundle ?? config.defaultBundle;
|
|
485
|
+
if (!bundle)
|
|
486
|
+
throw new UsageError(`Workflow ref ${ref} has no owning bundle.`, "INVALID_FLAG_VALUE");
|
|
487
|
+
const concept = parsed.conceptId.startsWith(`${plural}/`) ? parsed.conceptId : `${plural}/${parsed.conceptId}`;
|
|
488
|
+
return makeBundleRef(bundle, concept);
|
|
489
|
+
}
|
|
490
|
+
function scriptExecutable(interpreter) {
|
|
491
|
+
if (interpreter === "bun" || interpreter === "bun-standalone")
|
|
492
|
+
return process.execPath;
|
|
493
|
+
if (interpreter === "kotlin")
|
|
494
|
+
return "kotlin";
|
|
495
|
+
return interpreter;
|
|
496
|
+
}
|
|
497
|
+
function gitIdentity(unit, root) {
|
|
498
|
+
if (unit.isolation !== "worktree")
|
|
499
|
+
return {};
|
|
500
|
+
const result = spawnSync("git", ["-C", root, "rev-parse", "HEAD"], { encoding: "utf8" });
|
|
501
|
+
const oid = result.status === 0 ? result.stdout.trim() : "";
|
|
502
|
+
if (!/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(oid)) {
|
|
503
|
+
throw new UsageError(`Worktree-isolated workflow root ${root} has no immutable Git HEAD OID.`, "INVALID_FLAG_VALUE");
|
|
504
|
+
}
|
|
505
|
+
return { gitCommitOid: oid };
|
|
506
|
+
}
|
package/dist/workflows/parser.js
CHANGED
|
@@ -62,7 +62,7 @@ const DEFAULTS_KEYS = ["engine", "model", "timeout", "on_error", "llm"];
|
|
|
62
62
|
const BUDGET_KEYS = ["max_tokens", "max_units"];
|
|
63
63
|
const STEP_KEYS = ["id", "unit", "map", "route", "inputs", "output", "gate"];
|
|
64
64
|
const UNIT_KEYS = ["exec", "engine", "model", "llm", "timeout", "retry", "on_error", "output", "env", "isolation"];
|
|
65
|
-
const EXEC_KEYS = ["command", "cwd", "pass_env"
|
|
65
|
+
const EXEC_KEYS = ["command", "cwd", "pass_env"];
|
|
66
66
|
/** Unit keys that name an ENGINE dispatch and therefore cannot appear beside `exec:`. */
|
|
67
67
|
const UNIT_ENGINE_KEYS = ["engine", "model", "llm"];
|
|
68
68
|
const MAP_KEYS = ["over", "concurrency", "reducer", "unit"];
|
|
@@ -74,19 +74,6 @@ const ACTOR_STAMP_KEYS = ["by", "at"];
|
|
|
74
74
|
const TIMEOUT_VALUE = /^(\d+)(ms|s|m)?$/;
|
|
75
75
|
const TIMEOUT_HINT = `Use "<n>ms", "<n>s", "<n>m" (e.g. "10m"), or "none"`;
|
|
76
76
|
const LIFECYCLE_STATUSES = new Set(["draft", "stable", "deprecated"]);
|
|
77
|
-
/**
|
|
78
|
-
* Cheap structural probe retained ONLY for callers that still need a fast
|
|
79
|
-
* "is this workflow-shaped" content check without touching the filesystem's
|
|
80
|
-
* directory. Recognition itself no longer sniffs content (spec §2.5) — this
|
|
81
|
-
* is a best-effort convenience for content-only contexts (e.g. a proposal
|
|
82
|
-
* whose ref carries no path). It looks for `type: workflow` in frontmatter.
|
|
83
|
-
*/
|
|
84
|
-
export function looksLikeWorkflow(raw) {
|
|
85
|
-
const fmBlock = parseFrontmatterBlock(raw);
|
|
86
|
-
if (!fmBlock)
|
|
87
|
-
return false;
|
|
88
|
-
return /^type:\s*['"]?workflow['"]?\s*(#.*)?$/m.test(fmBlock.frontmatter);
|
|
89
|
-
}
|
|
90
77
|
export function parseWorkflow(markdown, source) {
|
|
91
78
|
if (utf8Bytes(markdown) > WORKFLOW_MAX_SOURCE_BYTES) {
|
|
92
79
|
return {
|
|
@@ -155,6 +142,7 @@ export function parseWorkflow(markdown, source) {
|
|
|
155
142
|
const ctx = {
|
|
156
143
|
filePath: path,
|
|
157
144
|
errors,
|
|
145
|
+
...(source.validateExecCwd ? { validateExecCwd: source.validateExecCwd } : {}),
|
|
158
146
|
lineAt,
|
|
159
147
|
lineAtOffset: (offset) => Math.max(1, lineCounter.linePos(offset).line + lineOffset),
|
|
160
148
|
nodeAt: (p) => (p.length === 0 ? doc.contents : doc.getIn(p, true)),
|
|
@@ -700,15 +688,6 @@ function parseExec(ctx, raw, path, stepLabel) {
|
|
|
700
688
|
const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path, "pass_env"], stepLabel);
|
|
701
689
|
if (passEnv !== undefined)
|
|
702
690
|
exec.passEnv = passEnv;
|
|
703
|
-
if (raw.inherit_env !== undefined) {
|
|
704
|
-
if (typeof raw.inherit_env !== "boolean") {
|
|
705
|
-
ctx.err([...path, "inherit_env"], `${stepLabel} "exec.inherit_env" must be true or false. true gives the command akm's whole environment ` +
|
|
706
|
-
`instead of the default allowlist; omit it (or write false) to keep the allowlist.`);
|
|
707
|
-
}
|
|
708
|
-
else if (raw.inherit_env) {
|
|
709
|
-
exec.inheritEnv = true;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
691
|
return exec;
|
|
713
692
|
}
|
|
714
693
|
/**
|
|
@@ -726,7 +705,7 @@ function parseExecPassEnv(ctx, raw, path, stepLabel) {
|
|
|
726
705
|
}
|
|
727
706
|
if (raw.length > WORKFLOW_MAX_EXEC_PASS_ENV) {
|
|
728
707
|
ctx.err(path, `${stepLabel} "exec.pass_env" must have at most ${WORKFLOW_MAX_EXEC_PASS_ENV} entries. A command needing ` +
|
|
729
|
-
`more than that
|
|
708
|
+
`more than that should use explicit named "env:" bindings instead.`);
|
|
730
709
|
return undefined;
|
|
731
710
|
}
|
|
732
711
|
const names = [];
|
|
@@ -761,6 +740,10 @@ function parseExecCommand(ctx, raw, path, stepLabel) {
|
|
|
761
740
|
ctx.err(path, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
|
|
762
741
|
return undefined;
|
|
763
742
|
}
|
|
743
|
+
if (entry.includes("\0")) {
|
|
744
|
+
ctx.err([...path, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
|
|
745
|
+
return undefined;
|
|
746
|
+
}
|
|
764
747
|
if (utf8Bytes(entry) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
765
748
|
ctx.err(path, `${stepLabel} "exec.command[${index}]" exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes.`);
|
|
766
749
|
return undefined;
|
|
@@ -791,6 +774,18 @@ function parseExecCwd(ctx, raw, path, stepLabel) {
|
|
|
791
774
|
`directory — absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
|
|
792
775
|
return undefined;
|
|
793
776
|
}
|
|
777
|
+
if (ctx.validateExecCwd) {
|
|
778
|
+
const semantic = ctx.validateExecCwd(value);
|
|
779
|
+
if (!semantic.ok) {
|
|
780
|
+
ctx.errors.push({
|
|
781
|
+
code: semantic.code,
|
|
782
|
+
line: ctx.lineAt(path),
|
|
783
|
+
message: semantic.message,
|
|
784
|
+
});
|
|
785
|
+
return undefined;
|
|
786
|
+
}
|
|
787
|
+
return semantic.value;
|
|
788
|
+
}
|
|
794
789
|
return value;
|
|
795
790
|
}
|
|
796
791
|
function parseMap(ctx, raw, path, stepLabel) {
|
|
@@ -1077,6 +1072,7 @@ function parseLlmOverrides(ctx, raw, path, label) {
|
|
|
1077
1072
|
"extra_params",
|
|
1078
1073
|
"context_length",
|
|
1079
1074
|
"enable_thinking",
|
|
1075
|
+
"reasoning_effort",
|
|
1080
1076
|
];
|
|
1081
1077
|
checkUnknownKeys(ctx, raw, path, keys, label);
|
|
1082
1078
|
const result = {};
|
|
@@ -1129,6 +1125,13 @@ function parseLlmOverrides(ctx, raw, path, label) {
|
|
|
1129
1125
|
else
|
|
1130
1126
|
ctx.err([...path, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
|
|
1131
1127
|
}
|
|
1128
|
+
if (raw.reasoning_effort !== undefined) {
|
|
1129
|
+
if (typeof raw.reasoning_effort === "string" && raw.reasoning_effort.trim().length > 0) {
|
|
1130
|
+
result.reasoningEffort = raw.reasoning_effort;
|
|
1131
|
+
}
|
|
1132
|
+
else
|
|
1133
|
+
ctx.err([...path, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
|
|
1134
|
+
}
|
|
1132
1135
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
1133
1136
|
}
|
|
1134
1137
|
function parseSchemaObject(ctx, raw, path, label) {
|
|
@@ -30,7 +30,7 @@ const RETRY_REASON_SET = {
|
|
|
30
30
|
export const PROGRAM_RETRY_REASONS = Object.keys(RETRY_REASON_SET);
|
|
31
31
|
/**
|
|
32
32
|
* Step ids: `[A-Za-z_][A-Za-z0-9_-]*` (also pinned in the JSON Schema) — the
|
|
33
|
-
* ONE id grammar for the
|
|
33
|
+
* ONE id grammar for the shared source IR (workflow-format-unification, spec
|
|
34
34
|
* §2.2). This is EXACTLY the `<ident>` grammar `readIdent` accepts in
|
|
35
35
|
* `program/expressions.ts` for `steps.<id>.output` references: a
|
|
36
36
|
* letter/underscore first char, then letters/digits/underscores/dashes, and
|
|
@@ -70,6 +70,5 @@ export function projectExecCore(exec) {
|
|
|
70
70
|
command: [...exec.command],
|
|
71
71
|
...(exec.cwd ? { cwd: exec.cwd } : {}),
|
|
72
72
|
...(exec.passEnv && exec.passEnv.length > 0 ? { passEnv: [...exec.passEnv] } : {}),
|
|
73
|
-
...(exec.inheritEnv ? { inheritEnv: true } : {}),
|
|
74
73
|
};
|
|
75
74
|
}
|