akm-cli 0.9.10 → 0.9.11
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 +60 -0
- package/STABILITY.md +22 -14
- package/dist/commands/health/checks.js +23 -7
- package/dist/commands/health/improve-metrics.js +12 -0
- package/dist/commands/improve/distill/quality-gate.js +13 -5
- package/dist/commands/improve/eval-cases.js +9 -2
- package/dist/commands/improve/improve.js +19 -4
- package/dist/commands/improve/loop-stages.js +13 -3
- package/dist/commands/tasks/tasks-cli.js +32 -0
- package/dist/commands/tasks/validate.js +186 -0
- package/dist/commands/url-checker.js +75 -16
- package/dist/core/bundle-id.js +7 -1
- package/dist/core/config/schema/engines.js +17 -0
- package/dist/core/improve-result.js +8 -0
- package/dist/core/paths.js +112 -0
- package/dist/indexer/search/search-source.js +3 -2
- package/dist/integrations/agent/engine-resolution.js +92 -3
- package/dist/integrations/agent/execution-lowering.js +15 -2
- package/dist/integrations/agent/runner-dispatch.js +16 -3
- package/dist/integrations/agent/runner.js +2 -0
- package/dist/output/shapes/passthrough.js +1 -0
- package/dist/scripts/akm-migrate-node.js +1043 -822
- package/dist/scripts/akm-migrate.js +1043 -822
- package/dist/tasks/scheduler-sync.js +51 -25
- package/dist/workflows/exec/dispatch-redaction.js +21 -7
- package/docs/integration/bundling-akm.md +1 -1
- package/docs/migration/v0.8-to-v0.9.md +32 -0
- package/docs/reference/cli.md +31 -5
- package/docs/reference/configuration.md +12 -2
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/tasks.md +8 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +8 -0
|
@@ -323,27 +323,9 @@ async function compileTaskSources(input, collector, out, failures) {
|
|
|
323
323
|
});
|
|
324
324
|
const document = projectTaskSourceV4(parsed.v4);
|
|
325
325
|
const qualifiedRef = makeBundleRef(input.bundleName, conceptId);
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
// applyInputDefaults + validateInputs pair akm task run uses
|
|
330
|
-
// (src/tasks/run/load-task.ts). parseTaskSource's own parse-time check
|
|
331
|
-
// (task-source-v4.ts's parseScheduleEntry) already rejects an
|
|
332
|
-
// unknown/malformed entry against the RAW supplied values; this is a
|
|
333
|
-
// deliberate second, independent gate over the DEFAULTED view — the
|
|
334
|
-
// exact set of values the compiled invocation below actually delivers
|
|
335
|
-
// — so a violation fails HERE, recorded as a task failure at sync,
|
|
336
|
-
// rather than surfacing for the first time when the scheduler fires
|
|
337
|
-
// the compiled invocation.
|
|
338
|
-
const contract = parsed.v4.inputs ?? {};
|
|
339
|
-
for (const scheduleEntry of parsed.v4.schedule) {
|
|
340
|
-
const defaultedInputs = applyInputDefaults(contract, { ...scheduleEntry.inputs });
|
|
341
|
-
const errors = validateInputs(contract, defaultedInputs);
|
|
342
|
-
if (errors.length > 0) {
|
|
343
|
-
throw new UsageError(`Task ${JSON.stringify(qualifiedRef)} schedule[${scheduleEntry.ordinal}].inputs does not satisfy ` +
|
|
344
|
-
`its declared inputs once defaults are applied: ${errors.join("; ")}`, "TASK_SOURCE_INVALID");
|
|
345
|
-
}
|
|
346
|
-
}
|
|
326
|
+
// See assertTaskScheduleInputsSatisfyContract's own docblock (below in
|
|
327
|
+
// this file) for why this second, defaults-applied gate exists.
|
|
328
|
+
assertTaskScheduleInputsSatisfyContract(parsed.v4, qualifiedRef);
|
|
347
329
|
await prepareTaskV3Execution(document, {
|
|
348
330
|
taskId: id,
|
|
349
331
|
taskRef: qualifiedRef,
|
|
@@ -380,16 +362,60 @@ async function compileTaskSources(input, collector, out, failures) {
|
|
|
380
362
|
inputs: schedule.inputs,
|
|
381
363
|
})),
|
|
382
364
|
});
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
out.push(binding);
|
|
386
|
-
}
|
|
365
|
+
assertTaskScheduleCronValid(parsed.v4, input.backend);
|
|
366
|
+
out.push(...sourceBindings);
|
|
387
367
|
}
|
|
388
368
|
catch (cause) {
|
|
389
369
|
failures.push(taskFailure(sourcePath, qualifiedRefForFailure, cause));
|
|
390
370
|
}
|
|
391
371
|
}
|
|
392
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* P2b Lane B (spec §4.4, rows B-50/F-B2): validate every v4 `schedule:`
|
|
375
|
+
* entry's `inputs` against the task's OWN declared contract WITH DEFAULTS
|
|
376
|
+
* APPLIED — the same `applyInputDefaults` + `validateInputs` pair
|
|
377
|
+
* `akm task run` uses (`src/tasks/run/load-task.ts`). `parseTaskSource`'s
|
|
378
|
+
* own parse-time check (`task-source-v4.ts`'s `parseScheduleEntry`) already
|
|
379
|
+
* rejects an unknown/malformed entry against the RAW supplied values; this
|
|
380
|
+
* is a deliberate second, independent gate over the DEFAULTED view — the
|
|
381
|
+
* exact set of values a compiled invocation actually delivers — so a
|
|
382
|
+
* violation fails HERE, recorded as a task failure at sync, rather than
|
|
383
|
+
* surfacing for the first time when the scheduler fires the invocation.
|
|
384
|
+
*
|
|
385
|
+
* Extracted so `akm task validate` can run the IDENTICAL gate
|
|
386
|
+
* over a bare file path without a second, potentially-diverging copy of
|
|
387
|
+
* this check. `refLabel` is only the text embedded in the thrown message —
|
|
388
|
+
* `compileTaskSources` passes its bundle-qualified ref; `akm task validate`,
|
|
389
|
+
* which never resolves a bundle for a bare file, passes the file path.
|
|
390
|
+
*/
|
|
391
|
+
export function assertTaskScheduleInputsSatisfyContract(v4, refLabel) {
|
|
392
|
+
const contract = v4.inputs ?? {};
|
|
393
|
+
for (const scheduleEntry of v4.schedule) {
|
|
394
|
+
const defaultedInputs = applyInputDefaults(contract, { ...scheduleEntry.inputs });
|
|
395
|
+
const errors = validateInputs(contract, defaultedInputs);
|
|
396
|
+
if (errors.length > 0) {
|
|
397
|
+
throw new UsageError(`Task ${JSON.stringify(refLabel)} schedule[${scheduleEntry.ordinal}].inputs does not satisfy ` +
|
|
398
|
+
`its declared inputs once defaults are applied: ${errors.join("; ")}`, "TASK_SOURCE_INVALID");
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Validate every v4 `schedule:` entry's `cron` against the active scheduler
|
|
404
|
+
* backend's dialect (`parseSchedule`, `./schedule.ts`) — cron is the most
|
|
405
|
+
* permissive of the three backends, so a task authored on Linux can carry a
|
|
406
|
+
* cron expression launchd/schtasks cannot translate; `compileTaskSources`
|
|
407
|
+
* re-checks against the LOCAL backend on every sync rather than trusting
|
|
408
|
+
* whatever backend the file was authored against.
|
|
409
|
+
*
|
|
410
|
+
* Extracted alongside {@link assertTaskScheduleInputsSatisfyContract}
|
|
411
|
+
* so `akm task validate` shares this exact gate instead of a second copy
|
|
412
|
+
* that could silently drift from what `akm task sync` actually enforces.
|
|
413
|
+
*/
|
|
414
|
+
export function assertTaskScheduleCronValid(v4, backend) {
|
|
415
|
+
for (const scheduleEntry of v4.schedule) {
|
|
416
|
+
parseSchedule(scheduleEntry.cron, backend);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
393
419
|
async function compileWorkflowSources(input, collector, out, evidence, failures) {
|
|
394
420
|
if (input.adapterId !== "akm" && input.adapterId !== "akm-workflow")
|
|
395
421
|
return;
|
|
@@ -15,21 +15,23 @@
|
|
|
15
15
|
* @module workflows/exec/dispatch-redaction
|
|
16
16
|
*/
|
|
17
17
|
import { collectSensitiveValues, isEnvPassthroughValueSafeToExpose, redactSensitiveText, redactSensitiveValue, } from "../../core/redaction.js";
|
|
18
|
+
import { lookupApiKeyFileValue } from "../../integrations/agent/engine-resolution.js";
|
|
18
19
|
/**
|
|
19
20
|
* Every exact value that must never survive into the journal from ONE frozen
|
|
20
21
|
* dispatch: the resolved `env` bindings injected into the child, the selected
|
|
21
|
-
* engine's (and its SDK fallback's) credential env
|
|
22
|
-
* `envPassthrough` value the redaction
|
|
22
|
+
* engine's (and its SDK fallback's) credential — an env value, or a
|
|
23
|
+
* file-backed one (#905) — and any `envPassthrough` value the redaction
|
|
24
|
+
* policy does not consider safe to expose.
|
|
23
25
|
*
|
|
24
26
|
* Shared by the unit path and the gate-judge path. There is deliberately ONE
|
|
25
27
|
* collector: a second, parallel implementation is exactly how a dispatch path
|
|
26
28
|
* silently loses the scrub.
|
|
27
29
|
*
|
|
28
|
-
* The credential values are read from `process.env`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* the set.
|
|
30
|
+
* The credential values are read from `process.env` (or disk, for a file-
|
|
31
|
+
* backed one) AT CALL TIME, so a caller must collect no earlier than the
|
|
32
|
+
* dispatch whose outcome it scrubs. A snapshot taken when the dispatch was
|
|
33
|
+
* merely *planned* can predate a credential the dispatch then resolves live,
|
|
34
|
+
* leaving the exact value it must remove out of the set.
|
|
33
35
|
*/
|
|
34
36
|
export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
35
37
|
const values = new Set([...Object.values(env ?? {}), ...(dispatch.sensitiveValues ?? [])]);
|
|
@@ -42,6 +44,13 @@ export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
|
42
44
|
if (value)
|
|
43
45
|
values.add(value);
|
|
44
46
|
}
|
|
47
|
+
// #905: file-backed credential — best-effort read, never throws, so a
|
|
48
|
+
// broken apiKeyFile is reported by the real dispatch, not this collector.
|
|
49
|
+
if (runner.apiKeyFile) {
|
|
50
|
+
const value = lookupApiKeyFileValue(runner.apiKeyFile);
|
|
51
|
+
if (value)
|
|
52
|
+
values.add(value);
|
|
53
|
+
}
|
|
45
54
|
return;
|
|
46
55
|
}
|
|
47
56
|
for (const name of runner.profile.envPassthrough ?? []) {
|
|
@@ -55,6 +64,11 @@ export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
|
55
64
|
if (value)
|
|
56
65
|
values.add(value);
|
|
57
66
|
}
|
|
67
|
+
if (runner.fallbackApiKeyFile) {
|
|
68
|
+
const value = lookupApiKeyFileValue(runner.fallbackApiKeyFile);
|
|
69
|
+
if (value)
|
|
70
|
+
values.add(value);
|
|
71
|
+
}
|
|
58
72
|
}
|
|
59
73
|
};
|
|
60
74
|
addCredential(dispatch.runner);
|
|
@@ -259,7 +259,7 @@ rather than rely on `$HOME`-derived defaults (names verified against
|
|
|
259
259
|
| `AKM_CONFIG_DIR` | `config.json`'s directory. |
|
|
260
260
|
| `AKM_DATA_DIR` | Durable, non-regenerable data: **`index.db` and `state.db` live here.** This is the directory a migration snapshot's safety copy sits beside. |
|
|
261
261
|
| `AKM_CACHE_DIR` | Regenerable cache: registry downloads, config backups, task logs. Safe to discard between image builds (not between boots of the same running install). |
|
|
262
|
-
| `AKM_STATE_DIR` | **Not** where `state.db` lives, despite the name — this is the XDG "state" directory
|
|
262
|
+
| `AKM_STATE_DIR` | **Not** where `state.db` lives, despite the name — this is the XDG "state" directory. Holds scheduled-task invocation context, companion-plugin hook state (Claude Code / OpenCode hook logs), and, per stash, `akm improve`'s machine-local writers (`improve/distill-rejected/`, `improve/eval-cases/`, `improve/measurement/verdicts/`) and whole-run lock (`locks/`) — see [Storage locations](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/storage-locations.md). Set it anyway if you schedule akm tasks inside the image, so that context is captured consistently rather than falling back to `$HOME/.local/state/akm`. |
|
|
263
263
|
|
|
264
264
|
Set all five to paths that persist across container restarts (a mounted
|
|
265
265
|
volume), or `akm migrate apply` will see an empty `state.db` on every boot
|
|
@@ -112,6 +112,38 @@ IR and freeze the durable plan v4 family's executable `irVersion: 5` format.
|
|
|
112
112
|
That is the only executable stored plan. Do not copy an old workflow database
|
|
113
113
|
expecting old runs to resume; start new runs from current authored sources.
|
|
114
114
|
|
|
115
|
+
## Storage relocations within the 0.9.x line
|
|
116
|
+
|
|
117
|
+
0.9.11 (itlackey/akm#890) moves five machine-local `akm improve` writers out
|
|
118
|
+
of `$STASH/.akm` — where they never belonged, per the "must travel with the
|
|
119
|
+
content" rule in [Storage locations](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/storage-locations.md)
|
|
120
|
+
— into `$STATE`/`$CACHE`, namespaced per stash so two stashes on one machine
|
|
121
|
+
never collide:
|
|
122
|
+
|
|
123
|
+
| Old path | New path |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `$STASH/.akm/distill-rejected/` | `$STATE/improve/distill-rejected/<stash>/` |
|
|
126
|
+
| `$STASH/.akm/eval-cases/` | `$STATE/improve/eval-cases/<stash>/` |
|
|
127
|
+
| `$STASH/.akm/measurement/verdicts/` | `$STATE/improve/measurement/verdicts/<stash>/` |
|
|
128
|
+
| `$STASH/.akm/unresolved-sources/` | `$CACHE/index/unresolved-sources/<stash>/` |
|
|
129
|
+
| `$STASH/.akm/improve.lock` (+ `.improve.lock.operations.sensitive`) | `$STATE/locks/<stash>/improve.lock` (+ `.improve.lock.operations.sensitive`) |
|
|
130
|
+
|
|
131
|
+
Any script that reads the old paths directly — `scripts/akm-eval/src/proactive-verdict.ts`
|
|
132
|
+
(verdicts), `scripts/akm-eval/README.md`'s eval-cases note, or a custom
|
|
133
|
+
snapshot/backup tool — must read the new ones instead; the pilot treatment
|
|
134
|
+
file at `$STASH/.akm/measurement/` (sibling to `verdicts/`) is unaffected, it
|
|
135
|
+
was never a writer output. `akm migrate status`/`apply [--dry-run]` covers
|
|
136
|
+
every configured LOCAL bundle (the default stash first, then every other
|
|
137
|
+
filesystem-backed bundle — a `git`/`website`/`npm` bundle is cache-backed,
|
|
138
|
+
never touched), and reports and relocates any files still sitting at the old
|
|
139
|
+
paths (same-filesystem rename, or copy-then-delete across filesystems). A
|
|
140
|
+
lock file is only ever deleted once the same staleness check `akm improve`
|
|
141
|
+
itself uses says its holder is dead; a lock a live run still holds (or one
|
|
142
|
+
this process cannot read) is left in place and reported instead. The whole
|
|
143
|
+
step is idempotent — a second run reports nothing pending.
|
|
144
|
+
`$STASH/.akm/memory-cleanup/` did not move; it is the one confirmed exception
|
|
145
|
+
to the rule (see Storage locations, above).
|
|
146
|
+
|
|
115
147
|
## Recovery
|
|
116
148
|
|
|
117
149
|
If the new setup is wrong, stop AKM, move the new current directories aside,
|
package/docs/reference/cli.md
CHANGED
|
@@ -2457,10 +2457,10 @@ shell commands. It manages on-disk task definitions under
|
|
|
2457
2457
|
(cron / launchd / schtasks). Task source v4 YAML (`version: 4`) is the only
|
|
2458
2458
|
executable source contract this release accepts; `akm task add` writes v4 —
|
|
2459
2459
|
see the canonical [Tasks reference](tasks.md). The
|
|
2460
|
-
group is `add | run | explain | sync | doctor | history | prune`
|
|
2461
|
-
no `list` or `remove`; use `akm search --type task` /
|
|
2462
|
-
to inspect, and edit the file + `akm task sync` to
|
|
2463
|
-
schedule.
|
|
2460
|
+
group is `add | run | explain | validate | sync | doctor | history | prune`
|
|
2461
|
+
— there is no `list` or `remove`; use `akm search --type task` /
|
|
2462
|
+
`akm show tasks/<id>` to inspect, and edit the file + `akm task sync` to
|
|
2463
|
+
change or remove a schedule.
|
|
2464
2464
|
|
|
2465
2465
|
```sh
|
|
2466
2466
|
akm search --type task # List tasks (cross-bundle)
|
|
@@ -2472,6 +2472,7 @@ akm task add nightly --schedule "@daily" --command "akm improve" --disabled # r
|
|
|
2472
2472
|
akm task add nightly --schedule "@daily" --command "akm improve" --force # overwrite an existing task id
|
|
2473
2473
|
akm task run <id> # Execute now (what the scheduler calls)
|
|
2474
2474
|
akm task explain <ref> # Read-only: declared inputs, target, schedule — spawns nothing
|
|
2475
|
+
akm task validate <path> # Read-only: parse one task file by path, report sync's diagnostic
|
|
2475
2476
|
akm task history [<id>] [--id <id>] [--limit <n>] # Recent runs from state.db (positional id == --id)
|
|
2476
2477
|
akm task sync # Reconcile on-disk YAML with scheduler
|
|
2477
2478
|
akm task sync --dry-run # Preview the reconcile — zero scheduler writes
|
|
@@ -2494,6 +2495,30 @@ it never spawns anything, writes history, or touches the scheduler. A
|
|
|
2494
2495
|
secret-shaped value prints as `<redacted>`. See
|
|
2495
2496
|
[`akm task explain`](tasks.md#akm-task-explain).
|
|
2496
2497
|
|
|
2498
|
+
`akm task validate <path>` parses ONE task file by filesystem path — not a
|
|
2499
|
+
concept ref or id, and the file need not live in any configured bundle —
|
|
2500
|
+
and reports the same diagnostic `akm task sync` would produce for it,
|
|
2501
|
+
INCLUDING sync's own cron-dialect check and its per-schedule-entry
|
|
2502
|
+
input-contract check (so a file `sync` would reject can never be reported
|
|
2503
|
+
`valid`/`converts` here): `{ok, path, sourceVersion, outcome, reason?,
|
|
2504
|
+
resolved?}` where `outcome` is `valid` (parses as task source v4 directly
|
|
2505
|
+
and passes both sync checks), `converts` (task v2/v3 that the deterministic
|
|
2506
|
+
migrator converts in memory and which then also passes both sync checks),
|
|
2507
|
+
`blocked` (task v2/v3 the migrator itself cannot convert — needs a human
|
|
2508
|
+
decision), `invalid` (the YAML doesn't parse, or the document fails schema
|
|
2509
|
+
validation, or it parsed but fails one of the two sync checks), or
|
|
2510
|
+
`not-a-task` (the YAML parses but never declares a `version:` field — not
|
|
2511
|
+
shaped like a task source). `resolved` is the compiled task shape
|
|
2512
|
+
`akm task sync` itself would build a scheduler binding from — id, the
|
|
2513
|
+
compiled schema version, resolved `uses`/`run` target, declared `inputs`
|
|
2514
|
+
contract, and `schedule` bindings — present only on `valid`/`converts`.
|
|
2515
|
+
Unlike `akm task explain`, it never runs execution lowering: a command-kind
|
|
2516
|
+
task validates the same whether or not the local config has an engine
|
|
2517
|
+
configured. Exits 0 for `valid`/`converts`, 1 for
|
|
2518
|
+
`blocked`/`invalid`/`not-a-task`, 2 for a missing or unreadable path.
|
|
2519
|
+
**Read-only**: it never touches the scheduler and never requires the file to
|
|
2520
|
+
be indexed or wired into a bundle.
|
|
2521
|
+
|
|
2497
2522
|
`akm task run` is what cron / launchd / schtasks invoke at the scheduled
|
|
2498
2523
|
time. Each run is recorded as a row in the durable `task_history` table
|
|
2499
2524
|
(`state.db`), surfaced by `akm task history` — **not** by `akm log`; there is
|
|
@@ -2539,7 +2564,8 @@ the AKM storage path or installed runtime path therefore requires an explicit
|
|
|
2539
2564
|
operates on the primary/default bundle. `add`, `history`, `sync`, `run`, and
|
|
2540
2565
|
`explain` all accept `--bundle <bundle>` to schedule, reconcile, or inspect
|
|
2541
2566
|
tasks that live in another configured bundle (`doctor` reports scheduler-wide
|
|
2542
|
-
state and takes no `--bundle`
|
|
2567
|
+
state and takes no `--bundle`; `validate` takes a bare filesystem path
|
|
2568
|
+
instead of a ref, so it has no bundle to target either):
|
|
2543
2569
|
|
|
2544
2570
|
```sh
|
|
2545
2571
|
akm task add nightly --schedule "@daily" --command "akm improve" --bundle team-bundle
|
|
@@ -217,7 +217,8 @@ and is never rescued by that fallback.
|
|
|
217
217
|
Index passes select engines through `index.defaults.engine` or
|
|
218
218
|
`index.<pass>.engine`. Per-pass `model`, `timeoutMs`, and `llm` fields are
|
|
219
219
|
invocation overrides; `enabled: false` disables that pass. Connection fields
|
|
220
|
-
such as `endpoint`, `provider`, and `
|
|
220
|
+
such as `endpoint`, `provider`, `apiKey`, and `apiKeyFile` belong only on
|
|
221
|
+
named engines.
|
|
221
222
|
|
|
222
223
|
`workflow.maxConcurrency` is the native workflow engine ceiling. An explicit
|
|
223
224
|
value is clamped to `1..64`. When absent, AKM derives the cap once from the CPU
|
|
@@ -494,7 +495,7 @@ generic walker.
|
|
|
494
495
|
| `AKM_BUNDLE_DIR` | Override the bundle directory |
|
|
495
496
|
| `AKM_DATA_DIR` | Override the data directory — `index.db`, durable `state.db`, and `akm.lock` (or set `XDG_DATA_HOME`) |
|
|
496
497
|
| `AKM_CACHE_DIR` | Override the cache directory — regenerable caches (or set `XDG_CACHE_HOME`) |
|
|
497
|
-
| `AKM_STATE_DIR` | Override the state directory — task-scheduler invocation state (or set `XDG_STATE_HOME`) |
|
|
498
|
+
| `AKM_STATE_DIR` | Override the state directory — task-scheduler invocation state, and (per stash) `akm improve`'s machine-local writers and whole-run lock (or set `XDG_STATE_HOME`) |
|
|
498
499
|
| `AKM_SQLITE_JOURNAL_MODE` | SQLite journal mode: `WAL` (default), `DELETE`, or `TRUNCATE` |
|
|
499
500
|
| `AKM_VERBOSE` | Truthy value enables the same diagnostics as `--verbose` |
|
|
500
501
|
| `AKM_DEBUG` | `1` prints a stack trace on unexpected internal errors |
|
|
@@ -503,6 +504,15 @@ For an engine named `fast`, its fallback variable is
|
|
|
503
504
|
`AKM_ENGINE_FAST_API_KEY`. An explicit `apiKey` symbolic reference is
|
|
504
505
|
authoritative and does not fall through to another variable.
|
|
505
506
|
|
|
507
|
+
`engines.<name>.apiKeyFile` is a file-backed alternative to `apiKey`, for a
|
|
508
|
+
host that refuses to put secrets in the process environment (a container
|
|
509
|
+
runtime's mounted secret, for example). It is a plain filesystem path — `~`
|
|
510
|
+
expands to the home directory — read at dispatch time and trimmed of one
|
|
511
|
+
trailing newline; the raw path is safe to keep in `config.json` since it is
|
|
512
|
+
not itself a secret. Setting both `apiKey` and `apiKeyFile` on the same
|
|
513
|
+
engine is rejected. A missing, unreadable, or empty file fails the call
|
|
514
|
+
closed, naming the engine and path but never the file's content.
|
|
515
|
+
|
|
506
516
|
Use `AKM_SQLITE_JOURNAL_MODE=DELETE` or `TRUNCATE` when WAL is unavailable,
|
|
507
517
|
such as on some NFS/SMB mounts. With the default `WAL` setting, AKM detects a
|
|
508
518
|
network filesystem for the data directory and falls back to `DELETE`.
|
|
@@ -16,7 +16,7 @@ AKM adds no network destinations of its own. The requests it *does* make all go
|
|
|
16
16
|
2. **Registry metadata and bundle packages** from sources you explicitly configure (GitHub, npm, git remotes, websites) — those hosts receive the fetch/clone/crawl requests, and website sources receive requests for the pages you crawl.
|
|
17
17
|
3. **`akm upgrade`** — fetches the latest release from GitHub releases (GitHub sees the request).
|
|
18
18
|
4. **`akm setup`** — a single DNS lookup for `github.com` to decide whether to skip network-dependent steps (Ollama detection, remote embedding probes) when offline. No HTTP request is made by this probe; if it succeeds, akm proceeds with the network-dependent steps you already configured.
|
|
19
|
-
5. **`akm improve` dead-link checks** — a full-scope improve run (the default for a bare `akm improve`) sends best-effort `HEAD` requests (following redirects, with a short timeout
|
|
19
|
+
5. **`akm improve` dead-link checks** — a full-scope improve run (the default for a bare `akm improve`) sends best-effort `HEAD` requests (following redirects, with a short per-request timeout, checked at a bounded concurrency rather than all at once) to every URL found in the bodies of the knowledge assets it is improving, to flag dead links. The hosts of those URLs see a `HEAD` request; no asset content is sent. Keep URLs you don't want probed out of knowledge-asset bodies, or run improve with an explicit narrower scope.
|
|
20
20
|
|
|
21
21
|
In every case the receiving endpoint is one you configured or invoked; the data leaving your machine is the data you directed AKM to send there.
|
|
22
22
|
|
package/docs/reference/tasks.md
CHANGED
|
@@ -385,6 +385,14 @@ for full before/after examples and recovery guidance.
|
|
|
385
385
|
- `akm task explain <ref>` prints a task's declared inputs, resolved target,
|
|
386
386
|
effective execution settings, and schedule bindings without running
|
|
387
387
|
anything — see [`akm task explain`](#akm-task-explain) above.
|
|
388
|
+
- `akm task validate <path>` parses one task file by filesystem path (the
|
|
389
|
+
file need not live in a configured bundle) and reports the same
|
|
390
|
+
`valid`/`converts`/`blocked`/`invalid`/`not-a-task` diagnostic
|
|
391
|
+
`akm task sync` would produce for it — including sync's own cron-dialect
|
|
392
|
+
check and its per-schedule-entry input-contract check — without touching
|
|
393
|
+
the scheduler and without requiring a configured engine, even for a
|
|
394
|
+
command-kind task. The envelope's own `sourceVersion` field names the
|
|
395
|
+
file's originally declared schema version (2, 3, or 4).
|
|
388
396
|
- `akm task add` writes a task source v4 document and installs it after
|
|
389
397
|
validation. `--params` renders typed `inputs:` declarations instead of a
|
|
390
398
|
`with:` bag; `--schedule` is required on every invocation, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.11",
|
|
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
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"type": "string",
|
|
35
35
|
"pattern": "^\\$[A-Za-z_][A-Za-z0-9_]*$|^\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}$"
|
|
36
36
|
},
|
|
37
|
+
"apiKeyFile": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"minLength": 1
|
|
40
|
+
},
|
|
37
41
|
"temperature": {
|
|
38
42
|
"type": "number"
|
|
39
43
|
},
|
|
@@ -1719,6 +1723,10 @@
|
|
|
1719
1723
|
"type": "string",
|
|
1720
1724
|
"pattern": "^\\$[A-Za-z_][A-Za-z0-9_]*$|^\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}$"
|
|
1721
1725
|
},
|
|
1726
|
+
"apiKeyFile": {
|
|
1727
|
+
"type": "string",
|
|
1728
|
+
"minLength": 1
|
|
1729
|
+
},
|
|
1722
1730
|
"temperature": {
|
|
1723
1731
|
"type": "number"
|
|
1724
1732
|
},
|