akm-cli 0.9.4 → 0.9.6
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 +265 -0
- package/dist/commands/env/env-cli.js +1 -2
- package/dist/commands/env/secret-cli.js +1 -5
- package/dist/commands/feedback-cli.js +0 -4
- package/dist/commands/health/checks.js +0 -32
- package/dist/commands/health/surfaces.js +2 -2
- package/dist/commands/health.js +6 -15
- package/dist/commands/improve/anti-collapse.js +4 -91
- package/dist/commands/improve/autonomy-gate.js +1 -1
- package/dist/commands/improve/consolidate.js +25 -26
- package/dist/commands/improve/distill.js +2 -2
- package/dist/commands/improve/extract.js +8 -1
- package/dist/commands/improve/improve.js +3 -5
- package/dist/commands/improve/locks.js +13 -5
- package/dist/commands/improve/loop-stages.js +8 -9
- package/dist/commands/improve/memory/memory-contradiction-detect.js +1 -19
- package/dist/commands/improve/outcome-loop.js +0 -6
- package/dist/commands/improve/reflect.js +20 -9
- package/dist/commands/lint/index.js +4 -6
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -7
- package/dist/commands/proposal/validators/proposal-validators.js +12 -0
- package/dist/commands/read/search.js +14 -24
- package/dist/commands/sources/bundle-config-ops.js +9 -4
- package/dist/commands/sources/info.js +14 -10
- package/dist/commands/tasks/tasks-cli.js +56 -3
- package/dist/commands/tasks/tasks.js +101 -18
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/akm-adapter.js +2 -0
- package/dist/core/common.js +61 -24
- package/dist/core/config/config-io.js +2 -2
- package/dist/core/config/config-sources.js +32 -2
- package/dist/core/config/config-version-shim.js +101 -0
- package/dist/core/config/config.js +7 -7
- package/dist/core/config/schema/engines.js +9 -7
- package/dist/core/config/schema/primitives.js +0 -5
- package/dist/core/config/schema/search.js +2 -1
- package/dist/core/file-lock.js +2 -1
- package/dist/core/improve-result.js +35 -14
- package/dist/core/maintenance-barrier.js +2 -14
- package/dist/core/paths.js +0 -3
- package/dist/core/redaction.js +2 -2
- package/dist/core/spawn-env.js +8 -12
- package/dist/core/state/migrations.js +1 -12
- package/dist/core/state-db.js +9 -27
- package/dist/core/write-source.js +12 -19
- package/dist/execution/directory-identity.js +36 -10
- package/dist/execution/guarded-source.js +0 -10
- package/dist/indexer/graph/graph-boost.js +0 -4
- package/dist/indexer/index-writer-lock.js +43 -24
- package/dist/indexer/index-written-assets.js +5 -6
- package/dist/indexer/indexer.js +2 -39
- package/dist/indexer/materialize-embeddings.js +85 -41
- package/dist/indexer/passes/metadata.js +12 -4
- package/dist/indexer/scan/doc-to-entry.js +2 -0
- package/dist/indexer/search/db-search.js +15 -48
- package/dist/indexer/search/ranking-contributors.js +0 -25
- package/dist/indexer/search/ranking.js +3 -13
- package/dist/indexer/search/search-fields.js +16 -1
- package/dist/integrations/agent/builder-shared.js +0 -25
- package/dist/integrations/agent/model-map.js +2 -60
- package/dist/integrations/harnesses/aider/agent-builder.js +1 -3
- package/dist/integrations/harnesses/amazonq/agent-builder.js +2 -7
- package/dist/integrations/harnesses/claude/agent-builder.js +1 -4
- package/dist/integrations/harnesses/codex/agent-builder.js +1 -4
- package/dist/integrations/harnesses/copilot/agent-builder.js +2 -6
- package/dist/integrations/harnesses/gemini/agent-builder.js +2 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -4
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +2 -16
- package/dist/integrations/harnesses/openhands/agent-builder.js +1 -3
- package/dist/integrations/harnesses/pi/agent-builder.js +2 -4
- package/dist/integrations/session-logs/index.js +0 -9
- package/dist/llm/client.js +75 -42
- package/dist/llm/embedder.js +7 -3
- package/dist/llm/embedders/remote.js +141 -42
- package/dist/output/shapes/passthrough.js +17 -5
- package/dist/registry/network.js +5 -37
- package/dist/runtime.js +2 -10
- package/dist/scripts/akm-migrate-node.js +180 -238
- package/dist/scripts/akm-migrate.js +180 -238
- package/dist/setup/engine-config.js +2 -5
- package/dist/setup/registry-stash-loader.js +0 -8
- package/dist/setup/setup.js +9 -46
- package/dist/setup/steps/connection-shared.js +10 -13
- package/dist/sources/providers/git-install.js +1 -1
- package/dist/storage/engines/sqlite-migrations.js +20 -1
- package/dist/storage/repositories/index-entries-repository.js +0 -15
- package/dist/storage/repositories/proposals-repository.js +32 -6
- package/dist/tasks/backends/launchd.js +15 -20
- package/dist/tasks/backends/schtasks.js +18 -8
- package/dist/tasks/run/run-native-task.js +8 -6
- package/dist/tasks/scheduler-binding.js +15 -5
- package/dist/tasks/scheduler-sync-preview.js +4 -2
- package/dist/tasks/scheduler-sync.js +77 -42
- package/dist/tasks/source/bounded-document.js +2 -4
- package/dist/tasks/source/task-source-v3-frozen.js +5 -7
- package/dist/tasks/source/task-source-v4.js +5 -10
- package/dist/tasks/source/task-to-v3.js +29 -22
- package/dist/tasks/source/task-to-v4.js +1 -14
- package/dist/tasks/source-v3.js +6 -6
- package/dist/workflows/exec/native-executor.js +21 -31
- package/dist/workflows/exec/run-workflow.js +5 -6
- package/dist/workflows/exec/scheduler.js +3 -19
- package/dist/workflows/exec/step-work.js +1 -4
- package/dist/workflows/exec/unit-dispatch.js +2 -2
- package/dist/workflows/exec/worktree.js +1 -13
- package/dist/workflows/freeze/targets/child-workflow.js +2 -10
- package/dist/workflows/ir/plan-hash.js +4 -6
- package/dist/workflows/ir/schema-v4.js +0 -12
- package/dist/workflows/ir/schema.js +20 -31
- package/dist/workflows/parser.js +11 -52
- package/dist/workflows/renderer.js +2 -3
- package/dist/workflows/resource-limits.js +11 -41
- package/dist/workflows/runtime/runs.js +3 -4
- package/dist/workflows/source-ir/schema.js +14 -30
- package/dist/workflows/validator.js +1 -7
- package/docs/reference/cli.md +25 -3
- package/docs/reference/configuration.md +28 -7
- package/docs/reference/tasks.md +10 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +4 -23
- package/schemas/akm-task.json +1 -2
- package/schemas/akm-workflow.json +1 -13
- package/dist/indexer/search/semantic-status.js +0 -142
|
@@ -396,10 +396,9 @@ export function isTruncatedEvidence(value) {
|
|
|
396
396
|
* `buildEvidence` (exec/step-work.ts) promotes `evidence.output` UNCLIPPED by
|
|
397
397
|
* design: gates judge the full promoted artifact and the in-memory
|
|
398
398
|
* {@link StepExecutionResult} carries it to the caller intact. Nothing bounded
|
|
399
|
-
* the PERSISTED form, though — a `collect` reducer over
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* the shared step-semantics module.
|
|
399
|
+
* the PERSISTED form, though — a `collect` reducer over an unbounded fan-out
|
|
400
|
+
* can serialize to hundreds of megabytes. This is the write boundary, so the
|
|
401
|
+
* bound lives here rather than in the shared step-semantics module.
|
|
403
402
|
*
|
|
404
403
|
* Over-cap values are REPLACED (largest top-level entry BY UTF-8 BYTES first —
|
|
405
404
|
* the unit the cap is measured in — until the row fits) with a
|
|
@@ -14,7 +14,7 @@ import { validateExtraParams } from "../../core/extra-params.js";
|
|
|
14
14
|
import { checkJsonSchemaDefinition } from "../../core/json-schema.js";
|
|
15
15
|
import { parseReference } from "../program/expressions.js";
|
|
16
16
|
import { PROGRAM_RETRY_REASONS } from "../program/schema.js";
|
|
17
|
-
import { jsonBytes,
|
|
17
|
+
import { jsonBytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "../resource-limits.js";
|
|
18
18
|
import { compareWorkflowSourceCodePoints } from "./compare.js";
|
|
19
19
|
import { canonicalizeWorkflowCron, canonicalizeWorkflowRun, canonicalizeWorkflowWorkingDirectory, classifyWorkflowStepUses, rejectNulInArgv, validateWorkflowBuiltinCommand, WorkflowSourceSemanticError, } from "./semantics.js";
|
|
20
20
|
export const WORKFLOW_SOURCE_IR_VERSION = 1;
|
|
@@ -255,7 +255,7 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
255
255
|
}
|
|
256
256
|
validateMap(step.map, `step ${id} map`);
|
|
257
257
|
validateRoute(step.route, `step ${id} route`);
|
|
258
|
-
optionalStringList(step.inputs, `step ${id} inputs`,
|
|
258
|
+
optionalStringList(step.inputs, `step ${id} inputs`, Infinity);
|
|
259
259
|
if (Array.isArray(step.inputs)) {
|
|
260
260
|
for (const [inputIndex, input] of step.inputs.entries())
|
|
261
261
|
validateReference(input, `step ${id} inputs[${inputIndex}]`);
|
|
@@ -277,12 +277,7 @@ function validateExec(value, location, options) {
|
|
|
277
277
|
return;
|
|
278
278
|
const exec = record(value, location);
|
|
279
279
|
keys(exec, ["command", "cwd", "passEnv"], location);
|
|
280
|
-
stringList(exec.command, `${location}.command`,
|
|
281
|
-
for (const [index, argument] of exec.command.entries()) {
|
|
282
|
-
if (utf8Bytes(argument) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
283
|
-
fail(`${location}.command[${index}] exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
280
|
+
stringList(exec.command, `${location}.command`, Infinity, false);
|
|
286
281
|
try {
|
|
287
282
|
rejectNulInArgv(exec.command);
|
|
288
283
|
}
|
|
@@ -291,9 +286,6 @@ function validateExec(value, location, options) {
|
|
|
291
286
|
}
|
|
292
287
|
optionalString(exec.cwd, `${location}.cwd`);
|
|
293
288
|
if (exec.cwd !== undefined) {
|
|
294
|
-
if (exec.cwd.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
295
|
-
fail(`${location}.cwd exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters`);
|
|
296
|
-
}
|
|
297
289
|
try {
|
|
298
290
|
exec.cwd = canonicalizeWorkflowWorkingDirectory(exec.cwd, options.workspaceRoot);
|
|
299
291
|
}
|
|
@@ -302,7 +294,7 @@ function validateExec(value, location, options) {
|
|
|
302
294
|
}
|
|
303
295
|
}
|
|
304
296
|
if (exec.passEnv !== undefined) {
|
|
305
|
-
stringList(exec.passEnv, `${location}.passEnv`,
|
|
297
|
+
stringList(exec.passEnv, `${location}.passEnv`, Infinity, false);
|
|
306
298
|
}
|
|
307
299
|
if (Array.isArray(exec.passEnv)) {
|
|
308
300
|
for (const name of exec.passEnv) {
|
|
@@ -359,8 +351,8 @@ function validateRetry(value, location) {
|
|
|
359
351
|
return;
|
|
360
352
|
const retry = record(value, location);
|
|
361
353
|
keys(retry, ["max", "on"], location);
|
|
362
|
-
if (!Number.isSafeInteger(retry.max) || retry.max < 0
|
|
363
|
-
fail(`${location}.max must be
|
|
354
|
+
if (!Number.isSafeInteger(retry.max) || retry.max < 0) {
|
|
355
|
+
fail(`${location}.max must be a non-negative integer`);
|
|
364
356
|
}
|
|
365
357
|
stringList(retry.on, `${location}.on`, PROGRAM_RETRY_REASONS.length, false);
|
|
366
358
|
for (const reason of retry.on) {
|
|
@@ -393,10 +385,8 @@ function validateRoute(value, location) {
|
|
|
393
385
|
keys(route, ["input", "branches", "defaultStepId"], location);
|
|
394
386
|
nonEmptyString(route.input, `${location}.input`);
|
|
395
387
|
validateReference(route.input, `${location}.input`);
|
|
396
|
-
if (!Array.isArray(route.branches) ||
|
|
397
|
-
|
|
398
|
-
route.branches.length > WORKFLOW_MAX_ROUTE_BRANCHES) {
|
|
399
|
-
fail(`${location}.branches must contain 1 through ${WORKFLOW_MAX_ROUTE_BRANCHES} entries`);
|
|
388
|
+
if (!Array.isArray(route.branches) || route.branches.length === 0) {
|
|
389
|
+
fail(`${location}.branches must be a non-empty array`);
|
|
400
390
|
}
|
|
401
391
|
const matches = new Set();
|
|
402
392
|
for (const [index, value] of route.branches.entries()) {
|
|
@@ -416,11 +406,8 @@ function validateGate(value, location) {
|
|
|
416
406
|
return;
|
|
417
407
|
const gate = record(value, location);
|
|
418
408
|
keys(gate, ["maxLoops", "rubric"], location);
|
|
419
|
-
if (gate.maxLoops !== undefined &&
|
|
420
|
-
(
|
|
421
|
-
gate.maxLoops < 1 ||
|
|
422
|
-
gate.maxLoops > WORKFLOW_MAX_GATE_LOOPS)) {
|
|
423
|
-
fail(`${location}.maxLoops must be an integer from 1 through ${WORKFLOW_MAX_GATE_LOOPS}`);
|
|
409
|
+
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1)) {
|
|
410
|
+
fail(`${location}.maxLoops must be an integer of at least 1`);
|
|
424
411
|
}
|
|
425
412
|
optionalString(gate.rubric, `${location}.rubric`);
|
|
426
413
|
}
|
|
@@ -453,8 +440,8 @@ function validateParams(value) {
|
|
|
453
440
|
if (value === undefined)
|
|
454
441
|
return;
|
|
455
442
|
const params = record(value, "params");
|
|
456
|
-
if (Object.keys(params).length === 0
|
|
457
|
-
fail(`params must contain
|
|
443
|
+
if (Object.keys(params).length === 0) {
|
|
444
|
+
fail(`params must contain at least one entry`);
|
|
458
445
|
}
|
|
459
446
|
for (const [name, schema] of Object.entries(params)) {
|
|
460
447
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -472,8 +459,8 @@ function validateOutputs(value) {
|
|
|
472
459
|
if (value === undefined)
|
|
473
460
|
return;
|
|
474
461
|
const outputs = record(value, "outputs");
|
|
475
|
-
if (Object.keys(outputs).length === 0
|
|
476
|
-
fail(`outputs must contain
|
|
462
|
+
if (Object.keys(outputs).length === 0) {
|
|
463
|
+
fail(`outputs must contain at least one entry`);
|
|
477
464
|
}
|
|
478
465
|
for (const [name, declaration] of Object.entries(outputs)) {
|
|
479
466
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -496,9 +483,6 @@ function validateBudget(value) {
|
|
|
496
483
|
fail(`budget.${key} must be a positive integer`);
|
|
497
484
|
}
|
|
498
485
|
}
|
|
499
|
-
if (typeof budget.maxUnits === "number" && budget.maxUnits > WORKFLOW_MAX_MAP_EXPANSION) {
|
|
500
|
-
fail(`budget.maxUnits must be at most ${WORKFLOW_MAX_MAP_EXPANSION}`);
|
|
501
|
-
}
|
|
502
486
|
}
|
|
503
487
|
function validateLlm(value, location) {
|
|
504
488
|
if (value === undefined)
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* resource limits).
|
|
17
17
|
*/
|
|
18
18
|
import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
19
|
-
import { utf8Bytes, WORKFLOW_MAX_INSTRUCTION_BYTES
|
|
19
|
+
import { utf8Bytes, WORKFLOW_MAX_INSTRUCTION_BYTES } from "./resource-limits.js";
|
|
20
20
|
export function runSemanticChecks(draft, frontmatterData, frontmatterEndLine, errors) {
|
|
21
21
|
checkXrefs(frontmatterData.xrefs, frontmatterEndLine, errors);
|
|
22
22
|
checkResourceLimits(draft, errors);
|
|
@@ -43,12 +43,6 @@ function checkXrefs(value, line, errors) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function checkResourceLimits(draft, errors) {
|
|
46
|
-
if (draft.steps.length > WORKFLOW_MAX_STEPS) {
|
|
47
|
-
errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_STEPS} steps.` });
|
|
48
|
-
}
|
|
49
|
-
if (Object.keys(draft.params ?? {}).length > WORKFLOW_MAX_PARAMS) {
|
|
50
|
-
errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_PARAMS} parameters.` });
|
|
51
|
-
}
|
|
52
46
|
for (const step of draft.steps) {
|
|
53
47
|
if (step.instructions && utf8Bytes(step.instructions.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
|
|
54
48
|
errors.push({
|
package/docs/reference/cli.md
CHANGED
|
@@ -2423,9 +2423,10 @@ shell commands. It manages on-disk task definitions under
|
|
|
2423
2423
|
(cron / launchd / schtasks). Task source v4 YAML (`version: 4`) is the only
|
|
2424
2424
|
executable source contract this release accepts; `akm task add` writes v4 —
|
|
2425
2425
|
see the canonical [Tasks reference](tasks.md). The
|
|
2426
|
-
group is `add | run | explain | sync | doctor | history` — there is
|
|
2427
|
-
or `remove`; use `akm search --type task` / `akm show tasks/<id>`
|
|
2428
|
-
and edit the file + `akm task sync` to change or remove a
|
|
2426
|
+
group is `add | run | explain | sync | doctor | history | prune` — there is
|
|
2427
|
+
no `list` or `remove`; use `akm search --type task` / `akm show tasks/<id>`
|
|
2428
|
+
to inspect, and edit the file + `akm task sync` to change or remove a
|
|
2429
|
+
schedule.
|
|
2429
2430
|
|
|
2430
2431
|
```sh
|
|
2431
2432
|
akm search --type task # List tasks (cross-bundle)
|
|
@@ -2439,8 +2440,12 @@ akm task run <id> # Execute now (what the scheduler ca
|
|
|
2439
2440
|
akm task explain <ref> # Read-only: declared inputs, target, schedule — spawns nothing
|
|
2440
2441
|
akm task history [--id <id>] [--limit <n>] # Recent runs from state.db
|
|
2441
2442
|
akm task sync # Reconcile on-disk YAML with scheduler
|
|
2443
|
+
akm task sync --dry-run # Preview the reconcile — zero scheduler writes
|
|
2442
2444
|
akm task sync --rebind # Also capture the current installed runtime
|
|
2443
2445
|
akm task doctor # Report scheduler backend + paths
|
|
2446
|
+
akm task prune # Preview orphaned scheduler entries — zero writes
|
|
2447
|
+
akm task prune --yes # Remove every currently-computed orphan
|
|
2448
|
+
akm task prune --id ghost,stale --yes # Remove only the named orphan ids
|
|
2444
2449
|
```
|
|
2445
2450
|
|
|
2446
2451
|
`task add` also accepts `--disabled` (register but leave off in the OS
|
|
@@ -2466,6 +2471,23 @@ schedule-binding) and run `akm task sync`. To remove one, delete its file
|
|
|
2466
2471
|
(`<bundle>/tasks/<id>.yml`) and run `akm task sync` — sync uninstalls the
|
|
2467
2472
|
orphaned scheduler entry.
|
|
2468
2473
|
|
|
2474
|
+
`akm task sync --dry-run` prints the planned adds/updates/removes (removals
|
|
2475
|
+
carry their owning bundle) without touching the scheduler — zero writes.
|
|
2476
|
+
Exits non-zero when removals are pending, so it can gate a CI/health check
|
|
2477
|
+
on "sync would change something."
|
|
2478
|
+
|
|
2479
|
+
`akm task prune` reclaims installed scheduler entries that `sync` can never
|
|
2480
|
+
clean up on its own: entries whose own `--scheduler-context` descriptor no
|
|
2481
|
+
longer resolves to a live bundle (a corrupt/missing descriptor, or the
|
|
2482
|
+
bundle directory it pointed at is gone). It never touches an entry that
|
|
2483
|
+
still resolves to a live bundle — that's `sync`'s job. Like `sync
|
|
2484
|
+
--dry-run`, the default is a dry-run preview (zero scheduler writes) that
|
|
2485
|
+
exits non-zero when there are candidates to remove; `--yes` executes the
|
|
2486
|
+
printed plan, and `--id <id1,id2,...>` narrows a `--yes` run (or a preview)
|
|
2487
|
+
to specific binding ids — naming an id that isn't a current orphan
|
|
2488
|
+
candidate (not installed, or it still resolves to a live bundle) is
|
|
2489
|
+
refused with a usage error and removes nothing.
|
|
2490
|
+
|
|
2469
2491
|
Scheduler activation captures the installed akm runtime. Ordinary `task sync`
|
|
2470
2492
|
reconciles definitions, schedules, and enabled state while preserving that
|
|
2471
2493
|
runtime binding. Use `task sync --rebind` only after intentionally moving or
|
|
@@ -7,12 +7,33 @@ directory. Project `.akm/config.json` files are not merged.
|
|
|
7
7
|
|
|
8
8
|
## Version 0.9
|
|
9
9
|
|
|
10
|
-
A present configuration file must set `configVersion` to
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
A present configuration file must set `configVersion` to a version this
|
|
11
|
+
binary knows: the current `"0.9.0"`, or a known older version it can
|
|
12
|
+
auto-upgrade in memory (see "Version read shim" below). Missing, newer,
|
|
13
|
+
numeric, and any other unrecognized version are rejected by ordinary
|
|
14
|
+
commands without rewriting the file — an older binary never guesses at a
|
|
15
|
+
newer, unknown shape. Pre-0.9 config and database layouts are not runtime
|
|
16
|
+
inputs and are not migrated by `akm upgrade`. Configure the current schema
|
|
17
|
+
directly. The standalone migrator exists only for explicit task migration:
|
|
18
|
+
task v2 to task v3, then task v3 to task source v4, in one pass.
|
|
19
|
+
|
|
20
|
+
### Version read shim
|
|
21
|
+
|
|
22
|
+
Like the task-source v2/v3 auto-shim (`akm migrate apply`'s in-memory
|
|
23
|
+
counterpart, documented under Migration below), a known older `configVersion`
|
|
24
|
+
is converted to the current shape in memory on load — with a one-line stderr
|
|
25
|
+
deprecation warning — rather than hard-failing every command. Nothing is
|
|
26
|
+
written back to disk by the shim itself; the very next config-mutating
|
|
27
|
+
command (`akm config set`, etc.) persists the upgrade for free, since every
|
|
28
|
+
config write already forces `configVersion` to the current value, which
|
|
29
|
+
silences the warning. A `configVersion` this binary does not recognize at
|
|
30
|
+
all — including anything newer than current — still fails closed with
|
|
31
|
+
`UNSUPPORTED_CONFIG_VERSION`.
|
|
32
|
+
|
|
33
|
+
As of this writing `"0.9.0"` is the only `configVersion` akm has ever
|
|
34
|
+
shipped, so there is no real older shape for the shim to convert yet; the
|
|
35
|
+
mechanism (`src/core/config/config-version-shim.ts`) is established ahead of
|
|
36
|
+
the first bump that will need it, per #863.
|
|
16
37
|
|
|
17
38
|
```jsonc
|
|
18
39
|
{
|
|
@@ -345,7 +366,7 @@ reference, same rules as engine `apiKey`), `dimension`, `localModel`,
|
|
|
345
366
|
|
|
346
367
|
| Key | Purpose |
|
|
347
368
|
| --- | --- |
|
|
348
|
-
| `search.graphBoost.*` | Entity-graph relevance boost: `directBoostPerEntity`/`directBoostCap` (directly related entities), `hopBoostPerEntity`/`hopBoostCap` (multi-hop, capped at `maxHops` ≤ 3), `confidenceMode` (`
|
|
369
|
+
| `search.graphBoost.*` | Entity-graph relevance boost: `directBoostPerEntity`/`directBoostCap` (directly related entities), `hopBoostPerEntity`/`hopBoostCap` (multi-hop, capped at `maxHops` ≤ 3), `confidenceMode` (`blend`, the only supported value), `confidenceWeight` (0–1, default `0.2`) |
|
|
349
370
|
|
|
350
371
|
## Feedback
|
|
351
372
|
|
package/docs/reference/tasks.md
CHANGED
|
@@ -389,6 +389,16 @@ for full before/after examples and recovery guidance.
|
|
|
389
389
|
- Disable a binding by editing the source and syncing: set that schedule
|
|
390
390
|
entry's own `enabled: false`.
|
|
391
391
|
- Delete the `.yml` source and sync to remove its derived binding(s).
|
|
392
|
+
- `akm task sync --dry-run` previews the reconcile (adds/updates/removes,
|
|
393
|
+
removals annotated with their owning bundle) without writing to the
|
|
394
|
+
scheduler; exits non-zero when removals are pending.
|
|
395
|
+
- `akm task prune` removes installed scheduler entries `sync` cannot reach
|
|
396
|
+
because their own descriptor no longer resolves to a live bundle
|
|
397
|
+
(corrupt/missing `--scheduler-context`, or the owning bundle directory is
|
|
398
|
+
gone). It never touches an entry that still resolves to a live bundle.
|
|
399
|
+
Defaults to a dry-run preview (zero writes); `--yes` executes it; `--id
|
|
400
|
+
<id1,id2,...>` scopes to specific ids and refuses any id that isn't a
|
|
401
|
+
current orphan candidate.
|
|
392
402
|
- Use `akm task sync --rebind` only when deliberately changing the captured
|
|
393
403
|
AKM runtime, then verify with `akm task doctor`.
|
|
394
404
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
|
|
6
6
|
"keywords": [
|
package/schemas/akm-config.json
CHANGED
|
@@ -57,9 +57,6 @@
|
|
|
57
57
|
"type": "integer",
|
|
58
58
|
"exclusiveMinimum": 0
|
|
59
59
|
},
|
|
60
|
-
"supportsJsonSchema": {
|
|
61
|
-
"type": "boolean"
|
|
62
|
-
},
|
|
63
60
|
"extraParams": {
|
|
64
61
|
"type": "object",
|
|
65
62
|
"additionalProperties": {}
|
|
@@ -572,9 +569,7 @@
|
|
|
572
569
|
"confidenceMode": {
|
|
573
570
|
"type": "string",
|
|
574
571
|
"enum": [
|
|
575
|
-
"
|
|
576
|
-
"blend",
|
|
577
|
-
"multiply"
|
|
572
|
+
"blend"
|
|
578
573
|
],
|
|
579
574
|
"default": "blend"
|
|
580
575
|
},
|
|
@@ -1747,9 +1742,6 @@
|
|
|
1747
1742
|
"type": "integer",
|
|
1748
1743
|
"exclusiveMinimum": 0
|
|
1749
1744
|
},
|
|
1750
|
-
"supportsJsonSchema": {
|
|
1751
|
-
"type": "boolean"
|
|
1752
|
-
},
|
|
1753
1745
|
"extraParams": {
|
|
1754
1746
|
"type": "object",
|
|
1755
1747
|
"additionalProperties": {}
|
|
@@ -2262,9 +2254,7 @@
|
|
|
2262
2254
|
"confidenceMode": {
|
|
2263
2255
|
"type": "string",
|
|
2264
2256
|
"enum": [
|
|
2265
|
-
"
|
|
2266
|
-
"blend",
|
|
2267
|
-
"multiply"
|
|
2257
|
+
"blend"
|
|
2268
2258
|
],
|
|
2269
2259
|
"default": "blend"
|
|
2270
2260
|
},
|
|
@@ -3420,14 +3410,8 @@
|
|
|
3420
3410
|
"type": "integer",
|
|
3421
3411
|
"exclusiveMinimum": 0
|
|
3422
3412
|
},
|
|
3423
|
-
"
|
|
3424
|
-
"type": "
|
|
3425
|
-
"properties": {
|
|
3426
|
-
"structuredOutput": {
|
|
3427
|
-
"type": "boolean"
|
|
3428
|
-
}
|
|
3429
|
-
},
|
|
3430
|
-
"additionalProperties": true
|
|
3413
|
+
"supportsJsonSchema": {
|
|
3414
|
+
"type": "boolean"
|
|
3431
3415
|
},
|
|
3432
3416
|
"extraParams": {
|
|
3433
3417
|
"type": "object",
|
|
@@ -3443,9 +3427,6 @@
|
|
|
3443
3427
|
"reasoningEffort": {
|
|
3444
3428
|
"type": "string",
|
|
3445
3429
|
"minLength": 1
|
|
3446
|
-
},
|
|
3447
|
-
"supportsJsonSchema": {
|
|
3448
|
-
"type": "boolean"
|
|
3449
3430
|
}
|
|
3450
3431
|
},
|
|
3451
3432
|
"required": [
|
package/schemas/akm-task.json
CHANGED
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
},
|
|
28
28
|
"inputs": {
|
|
29
29
|
"type": "object",
|
|
30
|
-
"maxProperties": 128,
|
|
31
30
|
"propertyNames": { "$ref": "#/definitions/taskInputName" },
|
|
32
31
|
"additionalProperties": { "$ref": "#/definitions/inputDeclaration" }
|
|
33
32
|
},
|
|
@@ -105,7 +104,7 @@
|
|
|
105
104
|
"items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }
|
|
106
105
|
},
|
|
107
106
|
"maxSteps": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 },
|
|
108
|
-
"maxRetries": { "type": "integer", "minimum": 0
|
|
107
|
+
"maxRetries": { "type": "integer", "minimum": 0 }
|
|
109
108
|
},
|
|
110
109
|
"oneOf": [
|
|
111
110
|
{
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"params": {
|
|
23
23
|
"type": "object",
|
|
24
24
|
"minProperties": 1,
|
|
25
|
-
"maxProperties": 128,
|
|
26
25
|
"description": "Run parameters: param name -> JSON Schema declaration. Names must be params.<name>-addressable identifiers.",
|
|
27
26
|
"propertyNames": {
|
|
28
27
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
"outputs": {
|
|
35
34
|
"type": "object",
|
|
36
35
|
"minProperties": 1,
|
|
37
|
-
"maxProperties": 64,
|
|
38
36
|
"description": "Named, optionally schema-validated projections of step artifacts, exported when the run completes. Names must be steps.<child>.output.<name>-addressable identifiers. Each entry: { from: steps.<id>.output(.<seg>)*, schema?: <bounded JSON Schema> }. Markdown-frontmatter only.",
|
|
39
37
|
"propertyNames": {
|
|
40
38
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
@@ -52,7 +50,6 @@
|
|
|
52
50
|
"steps": {
|
|
53
51
|
"type": "array",
|
|
54
52
|
"minItems": 1,
|
|
55
|
-
"maxItems": 256,
|
|
56
53
|
"items": {
|
|
57
54
|
"$ref": "#/definitions/step"
|
|
58
55
|
}
|
|
@@ -188,7 +185,6 @@
|
|
|
188
185
|
"max": {
|
|
189
186
|
"type": "integer",
|
|
190
187
|
"minimum": 0,
|
|
191
|
-
"maximum": 100,
|
|
192
188
|
"description": "Maximum retry attempts per unit."
|
|
193
189
|
},
|
|
194
190
|
"on": {
|
|
@@ -213,7 +209,6 @@
|
|
|
213
209
|
"max_units": {
|
|
214
210
|
"type": "integer",
|
|
215
211
|
"minimum": 1,
|
|
216
|
-
"maximum": 10000,
|
|
217
212
|
"description": "Ceiling on total dispatched units across the run (seeded from journaled unit rows)."
|
|
218
213
|
}
|
|
219
214
|
}
|
|
@@ -252,25 +247,21 @@
|
|
|
252
247
|
"type": "array",
|
|
253
248
|
"description": "argv; command[0] is the program, resolved through PATH. Never shell-parsed.",
|
|
254
249
|
"minItems": 1,
|
|
255
|
-
"maxItems": 64,
|
|
256
250
|
"items": {
|
|
257
251
|
"type": "string",
|
|
258
|
-
"minLength": 1
|
|
259
|
-
"maxLength": 4096
|
|
252
|
+
"minLength": 1
|
|
260
253
|
}
|
|
261
254
|
},
|
|
262
255
|
"cwd": {
|
|
263
256
|
"type": "string",
|
|
264
257
|
"description": "Optional RELATIVE working directory inside the unit's working directory (its fresh worktree under `isolation: worktree`). Absolute paths, Windows drive letters, \"~\", and \"..\" segments are rejected here, and containment is re-checked against the resolved base — symlinks included — before the command is spawned.",
|
|
265
258
|
"minLength": 1,
|
|
266
|
-
"maxLength": 1024,
|
|
267
259
|
"pattern": "^(?!/|\\\\|~|[A-Za-z]:)(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$)).+$"
|
|
268
260
|
},
|
|
269
261
|
"pass_env": {
|
|
270
262
|
"type": "array",
|
|
271
263
|
"description": "Extra environment variable NAMES copied through from akm's own environment on top of the default allowlist — for a per-machine toolchain variable (e.g. CARGO_HOME) that no committed `env:` asset could carry. NAMES ONLY: values never appear in a workflow, and unlike `env:` bindings these values are NOT redacted from the command's output, so never list a credential here.",
|
|
272
264
|
"minItems": 1,
|
|
273
|
-
"maxItems": 32,
|
|
274
265
|
"uniqueItems": true,
|
|
275
266
|
"items": {
|
|
276
267
|
"type": "string",
|
|
@@ -398,7 +389,6 @@
|
|
|
398
389
|
"when": {
|
|
399
390
|
"type": "array",
|
|
400
391
|
"minItems": 1,
|
|
401
|
-
"maxItems": 256,
|
|
402
392
|
"items": {
|
|
403
393
|
"$ref": "#/definitions/routeBranch"
|
|
404
394
|
}
|
|
@@ -416,7 +406,6 @@
|
|
|
416
406
|
"max_loops": {
|
|
417
407
|
"type": "integer",
|
|
418
408
|
"minimum": 1,
|
|
419
|
-
"maximum": 100,
|
|
420
409
|
"description": "Evaluator-optimizer loop bound."
|
|
421
410
|
}
|
|
422
411
|
}
|
|
@@ -424,7 +413,6 @@
|
|
|
424
413
|
"inputs": {
|
|
425
414
|
"type": "array",
|
|
426
415
|
"minItems": 1,
|
|
427
|
-
"maxItems": 64,
|
|
428
416
|
"uniqueItems": true,
|
|
429
417
|
"items": {
|
|
430
418
|
"$ref": "#/definitions/reference"
|
|
@@ -1,142 +0,0 @@
|
|
|
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 fs from "node:fs";
|
|
5
|
-
import { writeFileAtomic } from "../../core/common.js";
|
|
6
|
-
import { getCacheDir, getSemanticStatusPath } from "../../core/paths.js";
|
|
7
|
-
import { DETERMINISTIC_EMBED_MODEL_ID, isDeterministicEmbedEnabled } from "../../llm/embedders/deterministic.js";
|
|
8
|
-
import { DEFAULT_LOCAL_MODEL } from "../../llm/embedders/local.js";
|
|
9
|
-
let semanticStatusMutationForTests;
|
|
10
|
-
/** TEST-ONLY. Inject a semantic-status filesystem publication fault. */
|
|
11
|
-
export function _setSemanticStatusMutationForTests(mutation) {
|
|
12
|
-
semanticStatusMutationForTests = mutation;
|
|
13
|
-
}
|
|
14
|
-
export function deriveSemanticProviderFingerprint(embedding) {
|
|
15
|
-
if (isDeterministicEmbedEnabled()) {
|
|
16
|
-
return `deterministic:${DETERMINISTIC_EMBED_MODEL_ID}`;
|
|
17
|
-
}
|
|
18
|
-
if (embedding?.endpoint) {
|
|
19
|
-
// Fingerprint keys on vector identity only (model + dimension). The endpoint
|
|
20
|
-
// is transport/routing and has no bearing on vector compatibility, so moving
|
|
21
|
-
// the same model+dimension to a different host must not force a full re-embed.
|
|
22
|
-
return `remote:${embedding.model}|${embedding.dimension ?? "default"}`;
|
|
23
|
-
}
|
|
24
|
-
return `local:${embedding?.localModel ?? DEFAULT_LOCAL_MODEL}`;
|
|
25
|
-
}
|
|
26
|
-
export function readSemanticStatus() {
|
|
27
|
-
try {
|
|
28
|
-
const raw = JSON.parse(fs.readFileSync(getSemanticStatusPath(), "utf8"));
|
|
29
|
-
if ((raw.status === "pending" ||
|
|
30
|
-
raw.status === "ready-js" ||
|
|
31
|
-
raw.status === "ready-vec" ||
|
|
32
|
-
raw.status === "blocked") &&
|
|
33
|
-
typeof raw.providerFingerprint === "string" &&
|
|
34
|
-
typeof raw.lastCheckedAt === "string") {
|
|
35
|
-
const status = {
|
|
36
|
-
status: raw.status,
|
|
37
|
-
providerFingerprint: raw.providerFingerprint,
|
|
38
|
-
lastCheckedAt: raw.lastCheckedAt,
|
|
39
|
-
};
|
|
40
|
-
if (typeof raw.reason === "string")
|
|
41
|
-
status.reason = raw.reason;
|
|
42
|
-
if (typeof raw.message === "string")
|
|
43
|
-
status.message = raw.message;
|
|
44
|
-
if (typeof raw.entryCount === "number")
|
|
45
|
-
status.entryCount = raw.entryCount;
|
|
46
|
-
if (typeof raw.embeddingCount === "number")
|
|
47
|
-
status.embeddingCount = raw.embeddingCount;
|
|
48
|
-
return status;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// ignore corrupt or missing semantic status
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
export function writeSemanticStatus(status) {
|
|
57
|
-
semanticStatusMutationForTests?.("write");
|
|
58
|
-
const dir = getCacheDir();
|
|
59
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
60
|
-
writeFileAtomic(getSemanticStatusPath(), `${JSON.stringify(status, null, 2)}\n`);
|
|
61
|
-
}
|
|
62
|
-
export function clearSemanticStatus() {
|
|
63
|
-
semanticStatusMutationForTests?.("clear");
|
|
64
|
-
try {
|
|
65
|
-
fs.unlinkSync(getSemanticStatusPath());
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
// ignore missing file
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/** How long a "blocked" status is retained before the system retries. 24 hours. */
|
|
72
|
-
export const BLOCKED_TTL_MS = 24 * 60 * 60 * 1000;
|
|
73
|
-
export function getEffectiveSemanticStatus(config, status = readSemanticStatus()) {
|
|
74
|
-
if (config.semanticSearchMode === "off")
|
|
75
|
-
return "disabled";
|
|
76
|
-
if (!status)
|
|
77
|
-
return "pending";
|
|
78
|
-
const fingerprint = deriveSemanticProviderFingerprint(config.embedding);
|
|
79
|
-
if (status.providerFingerprint !== fingerprint)
|
|
80
|
-
return "pending";
|
|
81
|
-
// Auto-recovery: if blocked status is older than BLOCKED_TTL_MS, treat as pending
|
|
82
|
-
// so the next index run will re-attempt semantic setup.
|
|
83
|
-
if (status.status === "blocked") {
|
|
84
|
-
const checkedAt = new Date(status.lastCheckedAt).getTime();
|
|
85
|
-
if (Number.isNaN(checkedAt) || Date.now() - checkedAt > BLOCKED_TTL_MS) {
|
|
86
|
-
return "pending";
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return status.status;
|
|
90
|
-
}
|
|
91
|
-
export function isSemanticRuntimeReady(status) {
|
|
92
|
-
return status === "ready-js" || status === "ready-vec";
|
|
93
|
-
}
|
|
94
|
-
export function classifySemanticFailure(message) {
|
|
95
|
-
const lower = message.toLowerCase();
|
|
96
|
-
if (lower.includes("401") || lower.includes("403") || lower.includes("auth") || lower.includes("unauthorized")) {
|
|
97
|
-
return "remote-auth";
|
|
98
|
-
}
|
|
99
|
-
if (lower.includes("429") || lower.includes("rate limit") || lower.includes("quota")) {
|
|
100
|
-
return "remote-rate-limit";
|
|
101
|
-
}
|
|
102
|
-
if (lower.includes("eacces") || lower.includes("permission denied")) {
|
|
103
|
-
return "permission-denied";
|
|
104
|
-
}
|
|
105
|
-
// Native library / linker errors must be checked before the generic ONNX
|
|
106
|
-
// match because Alpine/musl linker errors often contain "onnxruntime" in
|
|
107
|
-
// the library path (e.g. onnxruntime_binding.node).
|
|
108
|
-
if (lower.includes("shared library") ||
|
|
109
|
-
lower.includes("glibc") ||
|
|
110
|
-
lower.includes("musl") ||
|
|
111
|
-
lower.includes("libc.so")) {
|
|
112
|
-
return "native-lib-missing";
|
|
113
|
-
}
|
|
114
|
-
if (lower.includes("onnx") || lower.includes("onnxruntime")) {
|
|
115
|
-
return "onnx-runtime-failed";
|
|
116
|
-
}
|
|
117
|
-
if (lower.includes("404") || lower.includes("model not found") || lower.includes("bad request")) {
|
|
118
|
-
return "remote-model";
|
|
119
|
-
}
|
|
120
|
-
if (lower.includes("transformers") ||
|
|
121
|
-
lower.includes("missing-package") ||
|
|
122
|
-
lower.includes("local embedding dependency is unavailable")) {
|
|
123
|
-
return "missing-package";
|
|
124
|
-
}
|
|
125
|
-
if (lower.includes("download")) {
|
|
126
|
-
return "local-model-download";
|
|
127
|
-
}
|
|
128
|
-
if (lower.includes("dimension mismatch")) {
|
|
129
|
-
return "dimension-mismatch";
|
|
130
|
-
}
|
|
131
|
-
if (lower.includes("db") || lower.includes("sqlite") || lower.includes("cache dir")) {
|
|
132
|
-
return "db-open";
|
|
133
|
-
}
|
|
134
|
-
if (lower.includes("timeout") ||
|
|
135
|
-
lower.includes("unreachable") ||
|
|
136
|
-
lower.includes("refused") ||
|
|
137
|
-
lower.includes("network") ||
|
|
138
|
-
lower.includes("fetch")) {
|
|
139
|
-
return "remote-network";
|
|
140
|
-
}
|
|
141
|
-
return "unknown";
|
|
142
|
-
}
|