akm-cli 0.10.261012-beta → 0.10.261013-beta
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 +216 -0
- package/SECURITY.md +2 -2
- package/STABILITY.md +2 -2
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/hints/cli-hints-short.md +3 -4
- package/dist/commands/command/execution-source-loader.js +10 -14
- package/dist/commands/env/env-binding.js +47 -58
- package/dist/commands/env/env-cli.js +20 -22
- package/dist/commands/env/env.js +10 -58
- package/dist/commands/env/secret-cli.js +9 -27
- package/dist/commands/env/secret.js +3 -10
- package/dist/commands/health/scheduler-binary.js +1 -1
- package/dist/commands/improve/distill.js +0 -2
- package/dist/commands/improve/eligibility.js +0 -2
- package/dist/commands/lint/env-key-rules.js +7 -6
- package/dist/commands/lint/index.js +1 -1
- package/dist/commands/proposal/validators/proposal-validators.js +1 -4
- package/dist/commands/read/show.js +4 -25
- package/dist/commands/sources/add-cli.js +8 -63
- package/dist/commands/sources/bundle-cli.js +8 -9
- package/dist/commands/sources/installed-stashes.js +117 -61
- package/dist/commands/sources/schema-repair.js +0 -2
- package/dist/commands/sources/source-clone.js +31 -7
- package/dist/commands/tasks/explain.js +1 -1
- package/dist/commands/tasks/tasks.js +38 -56
- package/dist/commands/ui/redact.js +4 -4
- package/dist/commands/ui/workspace-actions.js +1 -1
- package/dist/commands/workflow/plan.js +47 -8
- package/dist/commands/workflow-cli.js +37 -41
- package/dist/core/adapter/adapters/akm-adapter.js +3 -3
- package/dist/core/adapter/adapters/akm-lint.js +3 -4
- package/dist/core/adapter/adapters/akm-metadata.js +2 -2
- package/dist/core/adapter/adapters/akm-task-adapter.js +5 -6
- package/dist/core/adapter/adapters/dotenv-adapter.js +4 -3
- package/dist/core/asset/resolve-ref.js +5 -0
- package/dist/core/bundle-rename.js +12 -4
- package/dist/core/common.js +4 -52
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +55 -18
- package/dist/core/config/schema/primitives.js +12 -6
- package/dist/core/config/schema/sources-bundles.js +2 -2
- package/dist/core/env-secret-ref.js +84 -73
- package/dist/core/errors.js +1 -1
- package/dist/core/paths.js +1 -6
- package/dist/core/redaction.js +16 -3
- package/dist/core/ref-token.js +82 -0
- package/dist/core/secret-value.js +14 -0
- package/dist/core/write-source.js +20 -4
- package/dist/indexer/indexer.js +27 -36
- package/dist/indexer/installations.js +1 -8
- package/dist/indexer/lookup/adapter-concept-owner.js +40 -14
- package/dist/indexer/materialize-embeddings.js +1 -1
- package/dist/indexer/scan/drain-dir.js +3 -3
- package/dist/indexer/search/search-source.js +4 -2
- package/dist/indexer/walk/path-resolver.js +13 -68
- package/dist/indexer/walk/walker.js +18 -22
- package/dist/integrations/agent/engine-resolution.js +9 -7
- package/dist/integrations/agent/runner-dispatch.js +4 -5
- package/dist/integrations/agent/runner.js +2 -0
- package/dist/llm/client.js +1 -1
- package/dist/llm/embedders/remote.js +4 -3
- package/dist/output/renderers.js +3 -4
- package/dist/output/shapes/helpers.js +0 -2
- package/dist/output/text/command-format.js +12 -2
- package/dist/output/text/show-directives.js +16 -28
- package/dist/output/text/workflow-format.js +37 -7
- package/dist/scripts/akm-migrate-node.js +45865 -44692
- package/dist/scripts/akm-migrate.js +45804 -44630
- package/dist/setup/steps/tasks.js +1 -2
- package/dist/sources/providers/provider-utils.js +12 -0
- package/dist/sources/resolve.js +12 -16
- package/dist/sources/snapshot-fetchers/secret-seam.js +2 -4
- package/dist/sources/snapshot-fetchers/x.js +1 -1
- package/dist/storage/repositories/proposals-repository.js +2 -2
- package/dist/storage/repositories/task-history-repository.js +2 -2
- package/dist/storage/repositories/workflow-runs-repository.js +38 -116
- package/dist/tasks/embedded.js +1 -1
- package/dist/tasks/prepare/prepare-support.js +3 -2
- package/dist/tasks/prepare/prepare.js +3 -4
- package/dist/tasks/prepare/script-capture.js +8 -22
- package/dist/tasks/run/load-task.js +46 -14
- package/dist/tasks/run/run-native-task.js +0 -8
- package/dist/tasks/run/run-workflow-task.js +2 -2
- package/dist/tasks/scheduler-sync.js +0 -1
- package/dist/tasks/source/bounded-document.js +0 -41
- package/dist/tasks/source/parse-task-source.js +0 -1
- package/dist/tasks/source/task-source-v4.js +1 -4
- package/dist/workflows/compile.js +1 -15
- package/dist/workflows/exec/child-workflow.js +1 -2
- package/dist/workflows/exec/dispatch-redaction.js +24 -6
- package/dist/workflows/exec/environment.js +11 -74
- package/dist/workflows/exec/exec-unit.js +31 -23
- package/dist/workflows/exec/frozen-judge.js +17 -3
- package/dist/workflows/exec/native-executor.js +70 -26
- package/dist/workflows/exec/run-workflow.js +31 -18
- package/dist/workflows/exec/step-work.js +4 -3
- package/dist/workflows/exec/unit-dispatch.js +1 -8
- package/dist/workflows/freeze/environment.js +14 -119
- package/dist/workflows/freeze/freeze.js +0 -1
- package/dist/workflows/freeze/step-values.js +1 -2
- package/dist/workflows/freeze/targets/child-workflow.js +3 -5
- package/dist/workflows/freeze/targets/command.js +6 -9
- package/dist/workflows/freeze/targets/shell.js +0 -3
- package/dist/workflows/parser.js +6 -25
- package/dist/workflows/plan.js +6 -2
- package/dist/workflows/renderer.js +77 -4
- package/dist/workflows/runtime/run-plan.js +37 -23
- package/dist/workflows/runtime/runs.js +41 -84
- package/dist/workflows/runtime/workflow-asset-loader.js +55 -86
- package/dist/workflows/source-files.js +7 -19
- package/docs/architecture/0.10-process-rules.md +6 -6
- package/docs/architecture/architecture.md +6 -6
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +12 -18
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +6 -8
- package/docs/architecture/internals/storage-locations.md +4 -4
- package/docs/architecture/persisted-data-compat.md +3 -2
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +1 -1
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +3 -3
- package/docs/architecture/testing/manual-testing-checklist.md +46 -78
- package/docs/architecture/testing/task-workflow-manual-tests.md +22 -40
- package/docs/architecture/testing/testing-workflow.md +9 -11
- package/docs/architecture/workflow-engine.md +41 -27
- package/docs/guides/author-bundles.md +14 -17
- package/docs/guides/author-workflows.md +43 -9
- package/docs/guides/bundles.md +16 -11
- package/docs/guides/claude-code-vs-akm-workflows.md +1 -1
- package/docs/guides/run-workflows.md +25 -13
- package/docs/guides/scheduling.md +1 -1
- package/docs/maintainers/README.md +2 -3
- package/docs/maintainers/release-checklist.md +73 -126
- package/docs/migration/v0.9-to-v0.10.md +5 -1
- package/docs/reference/cli.md +124 -112
- package/docs/reference/configuration.md +16 -9
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/env-and-secrets.md +66 -15
- package/docs/reference/registry.md +6 -11
- package/docs/reference/tasks.md +11 -3
- package/docs/reference/ui-api.md +3 -3
- package/docs/reference/workflow-schema.md +109 -36
- package/package.json +1 -1
- package/schemas/akm-task.json +2 -4
- package/dist/commands/sources/dangerous-env-audit.js +0 -134
- package/dist/core/activation-policy.js +0 -67
- package/dist/execution/directory-identity.js +0 -78
- package/dist/workflows/authoring/scope-key.js +0 -79
- package/dist/workflows/source-semantics.js +0 -110
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { isRelevantAssetFile } from "../../core/asset/asset-placement.js";
|
|
14
|
-
import { WORKFLOW_EXTENSIONS } from "../../core/recognition-util.js";
|
|
15
14
|
import { spawnSync } from "../../runtime.js";
|
|
16
15
|
import { buildFileContext } from "./file-context.js";
|
|
17
16
|
const ALWAYS_SKIP_DIRS = new Set([".git"]);
|
|
@@ -124,13 +123,11 @@ function walkStashGit(stashRoot, options) {
|
|
|
124
123
|
for (const relFile of files) {
|
|
125
124
|
const absPath = path.join(stashRoot, relFile);
|
|
126
125
|
try {
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// reason; the two walkers have to agree regardless of whether the stash
|
|
131
|
-
// happens to sit inside a git repo.
|
|
126
|
+
// A file that is a symlink to a file anywhere is indexed like any other
|
|
127
|
+
// file: installing a bundle is the trust decision. git lists a symlinked
|
|
128
|
+
// directory as one entry, so directory symlinks are never descended.
|
|
132
129
|
const stat = fs.lstatSync(absPath);
|
|
133
|
-
if (stat.isFile() || (stat.isSymbolicLink() &&
|
|
130
|
+
if (stat.isFile() || (stat.isSymbolicLink() && isFileOrFileSymlink(absPath))) {
|
|
134
131
|
results.push(buildFileContext(stashRoot, absPath));
|
|
135
132
|
}
|
|
136
133
|
}
|
|
@@ -191,8 +188,11 @@ export function walkMarkdownFiles(root) {
|
|
|
191
188
|
}
|
|
192
189
|
for (const entry of entries) {
|
|
193
190
|
const full = path.join(current, entry.name);
|
|
194
|
-
if (entry.isSymbolicLink())
|
|
191
|
+
if (entry.isSymbolicLink()) {
|
|
192
|
+
if (entry.name.toLowerCase().endsWith(".md") && isFileOrFileSymlink(full))
|
|
193
|
+
files.push(full);
|
|
195
194
|
continue;
|
|
195
|
+
}
|
|
196
196
|
if (entry.isDirectory()) {
|
|
197
197
|
stack.push(full);
|
|
198
198
|
}
|
|
@@ -225,11 +225,10 @@ function walkStashManual(stashRoot, options) {
|
|
|
225
225
|
continue;
|
|
226
226
|
const fullPath = path.join(current, entry.name);
|
|
227
227
|
if (entry.isSymbolicLink()) {
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
if (
|
|
228
|
+
// A file symlink is indexed like any other file; a directory symlink
|
|
229
|
+
// is never descended (no cycles).
|
|
230
|
+
if (isFileOrFileSymlink(fullPath))
|
|
231
231
|
results.push(buildFileContext(stashRoot, fullPath));
|
|
232
|
-
}
|
|
233
232
|
continue;
|
|
234
233
|
}
|
|
235
234
|
if (entry.isDirectory()) {
|
|
@@ -245,15 +244,12 @@ function walkStashManual(stashRoot, options) {
|
|
|
245
244
|
}
|
|
246
245
|
return { files: results, complete };
|
|
247
246
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return false;
|
|
255
|
-
if (adapterId === "akm" && !relativePath.startsWith("workflows/"))
|
|
247
|
+
/** True for a regular file, or a symlink whose target is a regular file. */
|
|
248
|
+
export function isFileOrFileSymlink(filePath) {
|
|
249
|
+
try {
|
|
250
|
+
return fs.statSync(filePath).isFile();
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
256
253
|
return false;
|
|
257
|
-
|
|
258
|
-
return WORKFLOW_EXTENSIONS.includes(extension);
|
|
254
|
+
}
|
|
259
255
|
}
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
import { resolveSecret } from "../../core/config/config.js";
|
|
7
|
+
import { liftRetiredSecretRef, resolveSecret } from "../../core/config/config.js";
|
|
8
8
|
import { deepMergeConfig } from "../../core/config/deep-merge.js";
|
|
9
|
-
import { SECRET_STORE_REFERENCE_PATTERN } from "../../core/config/schema/primitives.js";
|
|
10
9
|
import { ConfigError } from "../../core/errors.js";
|
|
11
10
|
import { formatExtraParamsIssue, validateExtraParams } from "../../core/extra-params.js";
|
|
12
11
|
import { collectSensitiveValues } from "../../core/redaction.js";
|
|
12
|
+
import { isRefToken } from "../../core/ref-token.js";
|
|
13
13
|
import { resolveSecretFromStore } from "../../sources/snapshot-fetchers/secret-seam.js";
|
|
14
14
|
import { getHarness } from "../harnesses/index.js";
|
|
15
15
|
import { resolveOpencodeBin } from "../harnesses/opencode/version.js";
|
|
@@ -68,7 +68,7 @@ export function lookupApiKeyFileValue(filePath) {
|
|
|
68
68
|
/** Best-effort, non-throwing read of a secret-store credential for redaction and health. */
|
|
69
69
|
export function lookupApiKeySecretRefValue(ref) {
|
|
70
70
|
try {
|
|
71
|
-
return resolveSecret(ref, resolveSecretFromStore);
|
|
71
|
+
return resolveSecret(liftRetiredSecretRef(ref) ?? ref, resolveSecretFromStore);
|
|
72
72
|
}
|
|
73
73
|
catch {
|
|
74
74
|
return undefined;
|
|
@@ -95,7 +95,7 @@ function resolveCredential(name, engine, config) {
|
|
|
95
95
|
if (explicit)
|
|
96
96
|
return { names: [explicit], required: true };
|
|
97
97
|
// A secret-store reference is carried as `apiKeySecretRef` instead.
|
|
98
|
-
if (
|
|
98
|
+
if (isRefToken(engine.apiKey))
|
|
99
99
|
return undefined;
|
|
100
100
|
throw new ConfigError(`Engine "${name}" has an invalid symbolic apiKey reference.`, "INVALID_CONFIG_FILE");
|
|
101
101
|
}
|
|
@@ -138,7 +138,9 @@ export function resolveLlmCredentialValue(engine, credential, apiKeyFile, apiKey
|
|
|
138
138
|
return envValue;
|
|
139
139
|
if (apiKeyFile !== undefined)
|
|
140
140
|
return readApiKeyFile(engine, apiKeyFile);
|
|
141
|
-
return apiKeySecretRef !== undefined
|
|
141
|
+
return apiKeySecretRef !== undefined
|
|
142
|
+
? resolveSecret(liftRetiredSecretRef(apiKeySecretRef) ?? apiKeySecretRef, resolveSecretFromStore)
|
|
143
|
+
: undefined;
|
|
142
144
|
}
|
|
143
145
|
/**
|
|
144
146
|
* Non-throwing credential-presence check for `akm health` and improve's
|
|
@@ -193,7 +195,7 @@ export function collectEngineCredentialValues(config, envSource = process.env) {
|
|
|
193
195
|
if (value)
|
|
194
196
|
values.add(value);
|
|
195
197
|
}
|
|
196
|
-
if (engine.apiKey !== undefined &&
|
|
198
|
+
if (engine.apiKey !== undefined && isRefToken(engine.apiKey)) {
|
|
197
199
|
const value = lookupApiKeySecretRefValue(engine.apiKey);
|
|
198
200
|
if (value)
|
|
199
201
|
values.add(value);
|
|
@@ -237,7 +239,7 @@ export function resolveLlmEngineUse(config, layers) {
|
|
|
237
239
|
if (connection[key] === undefined)
|
|
238
240
|
delete connection[key];
|
|
239
241
|
}
|
|
240
|
-
const apiKeySecretRef = engine.apiKey !== undefined &&
|
|
242
|
+
const apiKeySecretRef = engine.apiKey !== undefined && isRefToken(engine.apiKey) ? engine.apiKey : undefined;
|
|
241
243
|
return {
|
|
242
244
|
engine: name,
|
|
243
245
|
connection: connection,
|
|
@@ -33,7 +33,10 @@ const OPERATIONAL_OPTIONS = [
|
|
|
33
33
|
"clearTimeoutFn",
|
|
34
34
|
"onEvent",
|
|
35
35
|
];
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Every value that can reach one dispatch and must never be echoed back: credentials and unsafe passthrough env.
|
|
38
|
+
* `opts.env` is configuration; a caller's secret values are redacted through its own sensitive set.
|
|
39
|
+
*/
|
|
37
40
|
export function collectDispatchSensitiveValues(runner, opts, envSource = opts.envSource ?? process.env) {
|
|
38
41
|
const values = [];
|
|
39
42
|
if (runner.kind === "llm") {
|
|
@@ -49,10 +52,6 @@ export function collectDispatchSensitiveValues(runner, opts, envSource = opts.en
|
|
|
49
52
|
values.push(envSource[name]);
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
|
-
for (const [name, value] of Object.entries(opts.env ?? {})) {
|
|
53
|
-
if (!isEnvPassthroughValueSafeToExpose(name, value))
|
|
54
|
-
values.push(value);
|
|
55
|
-
}
|
|
56
55
|
return collectSensitiveValues(values);
|
|
57
56
|
}
|
|
58
57
|
function redactResult(result, sensitiveValues) {
|
|
@@ -41,6 +41,8 @@ function isRecord(value) {
|
|
|
41
41
|
/**
|
|
42
42
|
* Read a journaled runner back. Tolerant: unknown keys are kept and missing
|
|
43
43
|
* profile defaults are filled in; only a shape nothing could dispatch is refused.
|
|
44
|
+
* Credentials stay as stored (a 0.9.x plan's `secret://<name>` included) because the
|
|
45
|
+
* unit input hash covers them; they are read as `${ref}` where they are resolved.
|
|
44
46
|
*/
|
|
45
47
|
export function decodeFrozenRunnerSpec(value) {
|
|
46
48
|
if (!isRecord(value) || typeof value.engine !== "string") {
|
package/dist/llm/client.js
CHANGED
|
@@ -359,7 +359,7 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
|
|
|
359
359
|
throw new Error(formatExtraParamsIssue("LLM extraParams", issue));
|
|
360
360
|
}
|
|
361
361
|
const headers = { "Content-Type": "application/json" };
|
|
362
|
-
// Resolve ONLY a whole-string reference ($VAR/${VAR} or
|
|
362
|
+
// Resolve ONLY a whole-string reference ($VAR/${VAR} or ${ref}).
|
|
363
363
|
// The execution boundary normally hands us a materialized credential after
|
|
364
364
|
// resolving the reference upstream, so re-running the substitution over a
|
|
365
365
|
// literal key mangled any credential containing `$` — `sk-live$ecret` lost
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
import { abortableDelay, backoffDelay, fetchWithTimeout, isHttpUrl, readBodyWithByteCap } from "../../core/common.js";
|
|
11
11
|
import { concurrentMap } from "../../core/concurrent.js";
|
|
12
12
|
import { resolveSecret } from "../../core/config/config.js";
|
|
13
|
-
import { ENV_REFERENCE_PATTERN
|
|
13
|
+
import { ENV_REFERENCE_PATTERN } from "../../core/config/schema/primitives.js";
|
|
14
14
|
import { defaultConcurrencyForEndpoint } from "../../core/loopback.js";
|
|
15
15
|
import { redactErrorBody, redactSensitiveText } from "../../core/redaction.js";
|
|
16
|
+
import { isRefToken } from "../../core/ref-token.js";
|
|
16
17
|
import { warnVerbose } from "../../core/warn.js";
|
|
17
18
|
import { resolveSecretFromStore } from "../../sources/snapshot-fetchers/secret-seam.js";
|
|
18
19
|
/**
|
|
@@ -845,7 +846,7 @@ export function hasRemoteEndpoint(config) {
|
|
|
845
846
|
/**
|
|
846
847
|
* Describe WHERE an `embedding.apiKey` came from, never its value — the
|
|
847
848
|
* actionable outcome of the #953 field gap: `resolveSecret` throws on an
|
|
848
|
-
* unresolvable `
|
|
849
|
+
* unresolvable `${ref}` reference, so a keyless request can only mean
|
|
849
850
|
* `embedding.apiKey` was absent from the config the run actually loaded (a
|
|
850
851
|
* different config root, scope, or a config edited after the run started).
|
|
851
852
|
* A default-level progress line naming the credential's SOURCE (this
|
|
@@ -855,7 +856,7 @@ export function hasRemoteEndpoint(config) {
|
|
|
855
856
|
export function describeEmbeddingCredential(apiKey) {
|
|
856
857
|
if (!apiKey)
|
|
857
858
|
return "none configured";
|
|
858
|
-
if (
|
|
859
|
+
if (isRefToken(apiKey))
|
|
859
860
|
return `${apiKey} (store)`;
|
|
860
861
|
if (ENV_REFERENCE_PATTERN.test(apiKey))
|
|
861
862
|
return `${apiKey} (env)`;
|
package/dist/output/renderers.js
CHANGED
|
@@ -213,10 +213,9 @@ const agentMdRenderer = {
|
|
|
213
213
|
action: "Dispatch using the prompt below verbatim. Use modelHint and toolPolicy if present.",
|
|
214
214
|
description: asNonEmptyString(parsedMd.data.description),
|
|
215
215
|
prompt: parsedMd.content,
|
|
216
|
-
// `tools` is self-declared frontmatter
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
// own writable stash vs a read-only third-party source (07 P1-D).
|
|
216
|
+
// `tools` is self-declared frontmatter and is passed through as-is. The
|
|
217
|
+
// host's `execution.allowedTools` caps it at dispatch (agent execution),
|
|
218
|
+
// so `show` does not filter it by source.
|
|
220
219
|
...(toolPolicy !== undefined ? { toolPolicy } : {}),
|
|
221
220
|
...(modelHint !== undefined ? { modelHint } : {}),
|
|
222
221
|
};
|
|
@@ -376,7 +376,6 @@ export function shapeShowOutput(result, detail, shape = "human") {
|
|
|
376
376
|
"run",
|
|
377
377
|
"setup",
|
|
378
378
|
"cwd",
|
|
379
|
-
"activeRun",
|
|
380
379
|
"toolPolicy",
|
|
381
380
|
"modelHint",
|
|
382
381
|
"agent",
|
|
@@ -418,7 +417,6 @@ export function shapeShowOutput(result, detail, shape = "human") {
|
|
|
418
417
|
"run",
|
|
419
418
|
"setup",
|
|
420
419
|
"cwd",
|
|
421
|
-
"activeRun",
|
|
422
420
|
"keys",
|
|
423
421
|
"links",
|
|
424
422
|
"evidence",
|
|
@@ -177,7 +177,7 @@ export function formatEnvListPlain(r) {
|
|
|
177
177
|
// Multi-env listing: { envs: [{ ref, path, keys }, ...] }
|
|
178
178
|
const envs = Array.isArray(r.envs) ? r.envs : [];
|
|
179
179
|
if (envs.length === 0) {
|
|
180
|
-
return "No env files. Create one with `akm env create
|
|
180
|
+
return "No env files. Create one with `akm env create env/<name>`, then edit the .env file directly.";
|
|
181
181
|
}
|
|
182
182
|
const lines = [];
|
|
183
183
|
for (const v of envs) {
|
|
@@ -580,14 +580,24 @@ export function formatBundleRenamePlain(r) {
|
|
|
580
580
|
const proposalRefs = Number(state.proposalRefs ?? 0);
|
|
581
581
|
const proposalTargets = Number(state.proposalTargets ?? 0);
|
|
582
582
|
const taskHistoryRefs = Number(state.taskHistoryRefs ?? 0);
|
|
583
|
+
const workflowRunRefs = Number(state.workflowRunRefs ?? 0);
|
|
584
|
+
const activeWorkflowRuns = Array.isArray(r.activeWorkflowRuns)
|
|
585
|
+
? r.activeWorkflowRuns
|
|
586
|
+
: [];
|
|
583
587
|
const entries = Number(index.entries ?? 0);
|
|
584
588
|
const contentRefs = Array.isArray(r.contentRefs) ? r.contentRefs : [];
|
|
585
589
|
const nativeSchedulerRows = Array.isArray(r.nativeSchedulerRows) ? r.nativeSchedulerRows : [];
|
|
586
590
|
const verb = applied ? "Renamed" : "Would rename";
|
|
587
591
|
const lines = [
|
|
588
592
|
`${verb} bundle "${oldId}" to "${newId}" (${entries} index entries, ${schedulerRefs} scheduler ref(s), ` +
|
|
589
|
-
`${proposalRefs + proposalTargets} proposal reference(s), ${taskHistoryRefs} task-history row(s)
|
|
593
|
+
`${proposalRefs + proposalTargets} proposal reference(s), ${taskHistoryRefs} task-history row(s), ` +
|
|
594
|
+
`${workflowRunRefs} workflow run(s)).`,
|
|
590
595
|
];
|
|
596
|
+
if (activeWorkflowRuns.length > 0) {
|
|
597
|
+
lines.push("Active and blocked workflow runs keep the old bundle name in their frozen plan; continue them (`akm workflow run <id>`, after `akm workflow resume <id>` for a blocked one) or abandon them (`akm workflow abandon <id>`):");
|
|
598
|
+
for (const run of activeWorkflowRuns)
|
|
599
|
+
lines.push(` - ${run.id} (${run.workflowRef}, ${run.status})`);
|
|
600
|
+
}
|
|
591
601
|
if (!applied) {
|
|
592
602
|
lines.push("Re-run without --dry-run to apply. It also re-syncs native scheduler bindings under the new name.");
|
|
593
603
|
if (nativeSchedulerRows.length > 0) {
|
|
@@ -43,36 +43,24 @@ export function appendShowDirectives(lines, r) {
|
|
|
43
43
|
lines.push(` - If this asset does not contain what you need, run \`akm feedback '${assetRef ?? "<ref>"}' --negative\` and search for a different asset.`);
|
|
44
44
|
}
|
|
45
45
|
if (assetType === "skill" || assetType === "knowledge") {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
lines.push("");
|
|
54
|
-
lines.push(
|
|
46
|
+
// Show the APPLY directive. Branch on whether this
|
|
47
|
+
// skill primarily teaches CLI commands (shell output) vs YAML schema.
|
|
48
|
+
const preApplyLines = [...lines];
|
|
49
|
+
lines.push("");
|
|
50
|
+
lines.push("---");
|
|
51
|
+
if (isCommandOutputSkill(preApplyLines)) {
|
|
52
|
+
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
53
|
+
lines.push(" 1. Identify the output file from README.md (typically commands.txt).");
|
|
54
|
+
lines.push(" 2. Write the exact command syntax from the code blocks above — replace every placeholder (`<name>`, `<value>`) with a real, concrete value from your task context. Do not write placeholder text.");
|
|
55
|
+
lines.push(" 3. Each command should be on a single line (no backslash line continuation unless the verifier expects it).");
|
|
56
|
+
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if this reference did not contain the needed command syntax.`);
|
|
55
57
|
}
|
|
56
58
|
else {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
lines.push("");
|
|
61
|
-
lines.push("
|
|
62
|
-
if (isCommandOutputSkill(preApplyLines)) {
|
|
63
|
-
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
64
|
-
lines.push(" 1. Identify the output file from README.md (typically commands.txt).");
|
|
65
|
-
lines.push(" 2. Write the exact command syntax from the code blocks above — replace every placeholder (`<name>`, `<value>`) with a real, concrete value from your task context. Do not write placeholder text.");
|
|
66
|
-
lines.push(" 3. Each command should be on a single line (no backslash line continuation unless the verifier expects it).");
|
|
67
|
-
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if this reference did not contain the needed command syntax.`);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
71
|
-
lines.push(" 1. Identify the target file from README.md — write or edit it. If the file does not yet exist, CREATE it with the full structure from this schema.");
|
|
72
|
-
lines.push(" 2. Add/edit the fields shown above using the exact field names from this schema.");
|
|
73
|
-
lines.push(" 3. COPY the exact YAML structure and field names from the code blocks above — do not substitute synonyms or invent nesting. Replace every placeholder value with a real, concrete value from your task context. Do not leave any field as null, empty, or a placeholder.");
|
|
74
|
-
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if the task fails after following this guidance.`);
|
|
75
|
-
}
|
|
59
|
+
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
60
|
+
lines.push(" 1. Identify the target file from README.md — write or edit it. If the file does not yet exist, CREATE it with the full structure from this schema.");
|
|
61
|
+
lines.push(" 2. Add/edit the fields shown above using the exact field names from this schema.");
|
|
62
|
+
lines.push(" 3. COPY the exact YAML structure and field names from the code blocks above — do not substitute synonyms or invent nesting. Replace every placeholder value with a real, concrete value from your task context. Do not leave any field as null, empty, or a placeholder.");
|
|
63
|
+
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if the task fails after following this guidance.`);
|
|
76
64
|
}
|
|
77
65
|
}
|
|
78
66
|
else if (assetType === "workflow") {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
export function formatWorkflowListPlain(result) {
|
|
13
13
|
const runs = Array.isArray(result.runs) ? result.runs : [];
|
|
14
14
|
if (runs.length === 0) {
|
|
15
|
-
return "No workflow runs
|
|
15
|
+
return "No workflow runs. Start one with `akm workflow run workflows/<name>` or author one with `akm workflow create <name>`.";
|
|
16
16
|
}
|
|
17
17
|
return runs
|
|
18
18
|
.map((run) => {
|
|
@@ -56,6 +56,40 @@ function renderChildNode(child, depth, lines) {
|
|
|
56
56
|
for (const grandchild of nested)
|
|
57
57
|
renderChildNode(grandchild, depth + 1, lines);
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* The `show` orchestration projection as text lines: the exec argv (JSON, so
|
|
61
|
+
* word boundaries survive), cwd, env refs and the bundle-qualified ref each
|
|
62
|
+
* token resolved to. Shared by `workflow plan` steps and `status --units`.
|
|
63
|
+
*/
|
|
64
|
+
function renderOrchestrationLines(value, prefix) {
|
|
65
|
+
if (typeof value !== "object" || value === null)
|
|
66
|
+
return [];
|
|
67
|
+
const orchestration = value;
|
|
68
|
+
const lines = [];
|
|
69
|
+
const exec = typeof orchestration.exec === "object" && orchestration.exec !== null
|
|
70
|
+
? orchestration.exec
|
|
71
|
+
: undefined;
|
|
72
|
+
if (exec) {
|
|
73
|
+
if (Array.isArray(exec.command))
|
|
74
|
+
lines.push(`${prefix}argv: ${JSON.stringify(exec.command)}`);
|
|
75
|
+
if (typeof exec.cwd === "string")
|
|
76
|
+
lines.push(`${prefix}cwd: ${exec.cwd}`);
|
|
77
|
+
}
|
|
78
|
+
if (Array.isArray(orchestration.env) && orchestration.env.length > 0) {
|
|
79
|
+
lines.push(`${prefix}env: ${orchestration.env.join(", ")}`);
|
|
80
|
+
}
|
|
81
|
+
const refs = Array.isArray(orchestration.refs) ? orchestration.refs : [];
|
|
82
|
+
for (const ref of refs) {
|
|
83
|
+
const written = ref.in === "argv" || ref.in === "cwd" ? `\${${String(ref.ref)}}` : String(ref.ref);
|
|
84
|
+
lines.push(`${prefix}ref: ${written} -> ${String(ref.resolved)} (${String(ref.in)})`);
|
|
85
|
+
}
|
|
86
|
+
const unresolved = Array.isArray(orchestration.unresolved)
|
|
87
|
+
? orchestration.unresolved
|
|
88
|
+
: [];
|
|
89
|
+
for (const ref of unresolved)
|
|
90
|
+
lines.push(`${prefix}ref: ${String(ref.ref)} -> not found (${String(ref.in)})`);
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
59
93
|
export function formatWorkflowStatusPlain(result) {
|
|
60
94
|
const run = typeof result.run === "object" && result.run !== null ? result.run : undefined;
|
|
61
95
|
const workflow = typeof result.workflow === "object" && result.workflow !== null
|
|
@@ -111,6 +145,7 @@ export function formatWorkflowStatusPlain(result) {
|
|
|
111
145
|
if (typeof unit.failureReason === "string" && unit.failureReason.trim()) {
|
|
112
146
|
lines.push(` failure_reason: ${unit.failureReason}`);
|
|
113
147
|
}
|
|
148
|
+
lines.push(...renderOrchestrationLines(unit.orchestration, " "));
|
|
114
149
|
if (typeof unit.diagnostic === "string" && unit.diagnostic.trim()) {
|
|
115
150
|
const diagLines = unit.diagnostic.split("\n");
|
|
116
151
|
lines.push(` diagnostic: ${diagLines[0]}`);
|
|
@@ -147,12 +182,6 @@ export function formatWorkflowRunPlain(result) {
|
|
|
147
182
|
if (!run)
|
|
148
183
|
return null;
|
|
149
184
|
const lines = [];
|
|
150
|
-
// #919: `workflow run <ref>` silently resuming an existing active run (the
|
|
151
|
-
// #485 concurrency guard) is now announced up front, with the escape hatch.
|
|
152
|
-
if (result.resumed === true) {
|
|
153
|
-
lines.push(`resuming existing run ${String(run.id ?? "unknown")} for ${String(run.workflowRef ?? "this ref")}; ` +
|
|
154
|
-
`pass --new to start a fresh run`);
|
|
155
|
-
}
|
|
156
185
|
lines.push(`run: ${String(run.id ?? "unknown")}`, `status: ${String(run.status ?? "unknown")}`);
|
|
157
186
|
// Creation-time notices (e.g. the implicit engine fallback) must survive the
|
|
158
187
|
// text renderer: JSON/YAML pass them through, and dropping them here would
|
|
@@ -252,6 +281,7 @@ function renderPlanStepLines(step, ordinal, lines, prefix = " ") {
|
|
|
252
281
|
if (inputBindings.length > 0) {
|
|
253
282
|
lines.push(`${detailPrefix}with: ${formatInputBindingsList(inputBindings)}`);
|
|
254
283
|
}
|
|
284
|
+
lines.push(...renderOrchestrationLines(step.orchestration, detailPrefix));
|
|
255
285
|
if (via === "child") {
|
|
256
286
|
const childSteps = Array.isArray(expansion.steps) ? expansion.steps : [];
|
|
257
287
|
for (const [index, childStep] of childSteps.entries()) {
|