akm-cli 0.9.17-alpha.6 → 0.9.17-alpha.8

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +285 -0
  2. package/STABILITY.md +2 -2
  3. package/dist/akm +62 -29
  4. package/dist/akm-migrate +38 -19
  5. package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
  6. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +5 -3
  7. package/dist/commands/improve/consolidate.js +11 -0
  8. package/dist/commands/improve/improve-cli.js +27 -7
  9. package/dist/commands/improve/ledger.js +7 -3
  10. package/dist/commands/improve/loop-stages.js +4 -3
  11. package/dist/commands/improve/preparation.js +40 -10
  12. package/dist/commands/improve/reflect.js +46 -22
  13. package/dist/commands/improve/retrieval-gate.js +127 -0
  14. package/dist/commands/improve/retrieval-scope.js +77 -0
  15. package/dist/commands/read/curate.js +41 -30
  16. package/dist/commands/read/show.js +55 -2
  17. package/dist/commands/sources/info.js +3 -0
  18. package/dist/commands/tasks/tasks-cli.js +10 -12
  19. package/dist/commands/tasks/tasks.js +57 -56
  20. package/dist/commands/tasks/validate.js +27 -46
  21. package/dist/core/adapter/adapters/akm-adapter.js +2 -0
  22. package/dist/core/adapter/adapters/akm-metadata.js +31 -0
  23. package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
  24. package/dist/core/improve-result.js +4 -1
  25. package/dist/core/non-task-input.js +20 -0
  26. package/dist/core/paths.js +0 -4
  27. package/dist/indexer/db/graph-db.js +0 -32
  28. package/dist/indexer/graph/graph-extraction.js +3 -1
  29. package/dist/indexer/indexer.js +1 -3
  30. package/dist/indexer/links/declared-links.js +90 -0
  31. package/dist/indexer/scan/doc-to-entry.js +1 -0
  32. package/dist/indexer/usage/usage-events.js +34 -0
  33. package/dist/llm/graph-extract.js +26 -37
  34. package/dist/output/shapes/helpers.js +3 -0
  35. package/dist/output/text/show-format.js +16 -0
  36. package/dist/scripts/akm-migrate-node.js +6377 -6437
  37. package/dist/scripts/akm-migrate.js +6860 -6920
  38. package/dist/storage/repositories/index-entries-repository.js +12 -6
  39. package/dist/storage/repositories/index-entry-schema.js +18 -1
  40. package/dist/storage/repositories/index-links-repository.js +143 -0
  41. package/dist/storage/repositories/index-schema.js +27 -0
  42. package/dist/storage/repositories/proposals-repository.js +4 -0
  43. package/dist/tasks/backends/cron.js +80 -43
  44. package/dist/tasks/backends/launchd.js +28 -15
  45. package/dist/tasks/backends/schtasks.js +25 -10
  46. package/dist/tasks/run/load-task.js +1 -1
  47. package/dist/tasks/scheduler-binding.js +4 -2
  48. package/dist/tasks/scheduler-invocation.js +127 -235
  49. package/dist/tasks/scheduler-sync.js +13 -8
  50. package/dist/tasks/source/parse-task-source.js +22 -126
  51. package/dist/tasks/source/task-to-v4.js +463 -87
  52. package/docs/migration/release-notes/0.9.17.md +7 -5
  53. package/docs/migration/v0.9.1-to-v0.9.2.md +7 -3
  54. package/docs/reference/cli.md +26 -10
  55. package/docs/reference/tasks.md +58 -40
  56. package/package.json +1 -1
  57. package/dist/tasks/source/task-to-v3.js +0 -507
@@ -5,59 +5,32 @@
5
5
  * The task source version router.
6
6
  *
7
7
  * Runs the bounded YAML front end ONCE (`readBoundedTaskSourceYaml`), reads
8
- * `root.version`, and either dispatches into `parseTaskSourceV4Document` or
9
- * routes through the in-memory read shim below — no second parse of the v4
10
- * grammar itself, no re-serialization back to disk, no synthetic document
11
- * (the shim adds a pure bytes-in/bytes-out detour, never a disk write).
12
- *
13
- * The terminal routing table:
8
+ * `root.version`, and dispatches into `parseTaskSourceV4Document`. The
9
+ * runtime reads only task source v4 (#987):
14
10
  *
15
11
  * | root `version` | outcome |
16
12
  * |------------------------|-----------------------------------------------------------------|
17
- * | `4`, no retired `schedule[].enabled` | `parseTaskSourceV4Document` — the current grammar |
18
- * | `4`, some `schedule[]` entry carries `enabled` | in-memory read shim (below): the SAME `planTaskToV4File` call `akm migrate apply` uses for this exact case (`./task-to-v4.ts`'s `version === 4` branch, which strips every `schedule[].enabled` and reports `source-enablement-removed`) runs on the bytes already in hand; the result is parsed and returned with a one-line stderr deprecation warning (once per file per process). The value is never read either way — `enabled: false` cannot suppress a granted task and `enabled: true` cannot schedule an ungranted one, since activation is host-local `scheduler.enabled`. Version 4 is supported, so if the planner cannot produce a valid document it is an ordinary grammar defect: falls back to `TASK_SOURCE_INVALID` with the v4 parser's own error, not the unmigratable-version decision |
19
- * | `2` or `3` | in-memory read shim (below): the SAME pure planners `akm migrate apply` uses (`./task-to-v3.ts`, `./task-to-v4.ts`) convert the bytes already in hand to v4 in memory; the result is parsed and returned with a one-line stderr deprecation warning (once per file per process). If the deterministic conversion itself fails (an unmigratable shape — the file needs a human decision, not a re-run), falls back to `TASK_SCHEMA_VERSION_UNSUPPORTED` naming the specific blocked reason — the shim removes friction for the deterministic case, it never hides a real problem |
13
+ * | `4` | `parseTaskSourceV4Document` — the current grammar |
14
+ * | `4`, some `schedule[]` entry carries `enabled` (0.9.15's grammar) | `TASK_SOURCE_INVALID` naming `akm migrate apply`, which removes the key |
15
+ * | `2` or `3` | `TASK_SCHEMA_VERSION_UNSUPPORTED` naming `akm migrate apply`, which converts the file |
20
16
  * | any other number | `TASK_SCHEMA_VERSION_UNSUPPORTED`, naming the migrator |
21
17
  * | absent / not a number | `parseTaskSourceV4Document` — its own `TASK_SOURCE_INVALID` "version is required and must be 4" / "must be exactly 4" wording |
22
18
  *
19
+ * `akm migrate apply` (`scripts/akm-migrate/`) is the one place a v2/v3
20
+ * document, or a v4 document carrying the retired `schedule[].enabled`, is
21
+ * converted: it rewrites the file once, under a backup. Nothing here converts
22
+ * in memory. Every caller reports the refusal for that one file — `akm task
23
+ * sync` keeps reconciling every other task (#867).
24
+ *
23
25
  * A missing or non-numeric `version:` is a MALFORMED v4 document, not a
24
26
  * legacy one — it routes into the v4 parser so the field error names the
25
- * one grammar `src` still accepts, rather than a generic "unsupported"
26
- * message that would send the user to the migrator for a document that was
27
- * never task v2 or v3 in the first place.
28
- *
29
- * task v2 and task v3 sources are no longer read as their own standing
30
- * grammar anywhere else in `src` — the only readers of that grammar are the
31
- * pure, byte-producing planners (`./task-to-v3.ts`, `./task-to-v4.ts`, and
32
- * the frozen v3 reader `./task-source-v3-frozen.ts`), reached either through
33
- * this shim (bytes in, bytes out, never touches disk) or through
34
- * `akm migrate apply` / `akm-migrate` (`scripts/akm-migrate`, which
35
- * additionally rewrites the file on disk once the user asks for that).
36
- * Policy: a deterministic byte transform is the tool's job, not the user's —
37
- * upgrading past a schema bump must not silently break a scheduled task, so
38
- * v2/v3 files keep reading successfully at the cost of a one-line
39
- * deprecation warning, and `akm migrate apply` remains available to rewrite
40
- * the file and silence it. Activation itself is host-local (scheduler
41
- * config, `src/core/activation-policy.ts`) and this shim never touches it:
42
- * the v3->v4 planner never hoists the retired `akm.enabled` field to v4's
43
- * top level and never carries a schedule entry's `enabled` key, so the
44
- * document this shim hands back carries no enablement at all — the same
45
- * shape a native v4 document has. A declared `version: 4` document that
46
- * still carries a `schedule[].enabled` key (0.9.15's v4 grammar accepted
47
- * it; this release's does not) gets the identical treatment: routed
48
- * through `planTaskToV4File`'s own `version === 4` branch, which strips
49
- * every `schedule[].enabled` key without reading its value and reports
50
- * `source-enablement-removed`, then re-parsed and returned with the same
51
- * one-line deprecation warning. The front end's own pre-version failures
27
+ * one grammar `src` accepts. The front end's own pre-version failures
52
28
  * (source not a string, source too large, YAML parse/warning/expansion)
53
29
  * render with the label `task source`.
54
30
  */
55
31
  import { UsageError } from "../../core/errors.js";
56
- import { warnOnce } from "../../core/warn.js";
57
32
  import { readBoundedTaskSourceYaml } from "./bounded-document.js";
58
- import { parseTaskSourceV4, parseTaskSourceV4Document, TASK_SOURCE_V4_VERSION, } from "./task-source-v4.js";
59
- import { planTaskToV3File } from "./task-to-v3.js";
60
- import { planTaskToV4File } from "./task-to-v4.js";
33
+ import { parseTaskSourceV4Document, TASK_SOURCE_V4_VERSION } from "./task-source-v4.js";
61
34
  /** Read the root `version` field without over-accepting non-number values (e.g. the string `"4"`). */
62
35
  export function peekTaskSourceVersion(root) {
63
36
  if (root === null || typeof root !== "object" || Array.isArray(root))
@@ -66,71 +39,19 @@ export function peekTaskSourceVersion(root) {
66
39
  return typeof value === "number" ? value : undefined;
67
40
  }
68
41
  const TASK_MIGRATE_HINT = "Run `akm migrate apply --dry-run` to preview the task-v3 to task-source-v4 conversion, then run `akm migrate apply`.";
69
- /**
70
- * Thrown only when the deterministic conversion itself could not produce a
71
- * task source v4 document — a case where a person must decide the intended
72
- * behavior (e.g. an ambiguous shell command), not one the migrator can just
73
- * be re-run to fix. `reason`/`detail` are the SAME blocked outcome
74
- * `akm migrate status`/`apply` reports for this file, so the message names
75
- * the actual decision instead of pointing at a command that will report the
76
- * identical block.
77
- */
78
- function unmigratableVersionError(filePath, version, reason, detail) {
79
- return new UsageError(`TASK_SCHEMA_VERSION_UNSUPPORTED: Task at ${filePath} uses task schema version ${version} and needs a human decision before it can run — the deterministic migrator cannot convert it automatically (${reason}${detail ? `: ${detail}` : ""}).`, "TASK_SCHEMA_VERSION_UNSUPPORTED", "Review the file and resolve the ambiguity by hand, then it will convert normally; `akm migrate status` reports the same reason.");
42
+ /** A v2/v3 document: `akm migrate apply` converts it; this release reads only v4. */
43
+ function legacyVersionError(filePath, version) {
44
+ return new UsageError(`TASK_SCHEMA_VERSION_UNSUPPORTED: Task at ${filePath} uses task schema version ${version}; this release reads only version 4. Run \`akm migrate apply\` to convert it.`, "TASK_SCHEMA_VERSION_UNSUPPORTED", TASK_MIGRATE_HINT);
80
45
  }
81
46
  function unsupportedVersionError(filePath, version) {
82
47
  return new UsageError(`TASK_SCHEMA_VERSION_UNSUPPORTED: Task at ${filePath} uses task schema version ${version}, which this release does not accept.`, "TASK_SCHEMA_VERSION_UNSUPPORTED", TASK_MIGRATE_HINT);
83
48
  }
84
- /**
85
- * Plan the SAME bytes already in hand through the pure v3->v4 (and, for v2,
86
- * chained v2->v3->v4) migration planner(s) — never touches disk, never
87
- * writes the file, never re-reads it from disk. `version === 4` runs the
88
- * identical bytes straight through `planTaskToV4File`'s own `version === 4`
89
- * branch instead (the retired `schedule[].enabled` case, `./task-to-v4.ts`),
90
- * so there is exactly one helper for every version this shim reads, not a
91
- * second one for the v4-only case. Returns the produced v4 YAML text, or the
92
- * blocked reason/detail when the deterministic conversion cannot proceed
93
- * (an unmigratable v2/v3 shape, or a v4 document `planTaskToV4File` cannot
94
- * revalidate once `schedule[].enabled` is stripped) — the caller falls back
95
- * to the same hard error this gate threw before the shim existed, now
96
- * naming that reason.
97
- */
98
- function planInMemoryV4Bytes(version, yaml, filePath, workspaceRoot) {
99
- const bytes = Buffer.from(yaml, "utf8");
100
- // `writable`/`onDiskWritable` gate the DISK apply path's "don't touch a
101
- // read-only file" check inside the planners; this shim never writes
102
- // anything to disk, so that check does not apply here and must not block
103
- // an otherwise-legal read of a task file that happens to be read-only.
104
- const baseInput = {
105
- filePath,
106
- bytes,
107
- mode: 0o644,
108
- writable: true,
109
- onDiskWritable: true,
110
- ...(workspaceRoot ? { containmentRoot: workspaceRoot } : {}),
111
- };
112
- let v3Bytes;
113
- if (version === 3 || version === 4) {
114
- v3Bytes = bytes;
115
- }
116
- else {
117
- const v3Outcome = planTaskToV3File(baseInput);
118
- if (v3Outcome.status !== "changed")
119
- return { reason: v3Outcome.reason, detail: v3Outcome.detail };
120
- v3Bytes = v3Outcome.after;
121
- }
122
- const v4Outcome = planTaskToV4File({ ...baseInput, bytes: v3Bytes });
123
- if (v4Outcome.status !== "changed")
124
- return { reason: v4Outcome.reason, detail: v4Outcome.detail };
125
- return v4Outcome.after.toString("utf8");
126
- }
127
49
  /**
128
50
  * True when `root`'s `schedule:` is a sequence with at least one mapping
129
51
  * entry that carries an `enabled` key, regardless of that key's value or
130
52
  * type — the shape 0.9.15's v4 grammar accepted and this release's does
131
- * not (`schedule[].enabled`). The value is never inspected: activation is
132
- * host-local `scheduler.enabled`, so this is purely a presence check that
133
- * decides whether to route through the in-memory shim.
53
+ * not (`schedule[].enabled`). Activation is host-local `scheduler.enabled`,
54
+ * so the value is never read; `akm migrate apply` removes the key.
134
55
  */
135
56
  export function v4ScheduleHasRetiredEnabledKey(root) {
136
57
  if (root === null || typeof root !== "object" || Array.isArray(root))
@@ -140,42 +61,17 @@ export function v4ScheduleHasRetiredEnabledKey(root) {
140
61
  return false;
141
62
  return schedule.some((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry) && Object.hasOwn(entry, "enabled"));
142
63
  }
143
- /** Parse task source YAML, routing per the terminal table above. */
64
+ /** Parse task source YAML, routing per the table above. */
144
65
  export function parseTaskSource(input) {
145
66
  const { root, lineAt } = readBoundedTaskSourceYaml(input, { sourceLabel: "task source" });
146
67
  const version = peekTaskSourceVersion(root);
147
68
  if (version !== undefined && version !== TASK_SOURCE_V4_VERSION) {
148
- if (version === 2 || version === 3) {
149
- const shimmed = planInMemoryV4Bytes(version, input.yaml, input.filePath, input.workspaceRoot);
150
- if (typeof shimmed === "string") {
151
- const v4 = parseTaskSourceV4({
152
- yaml: shimmed,
153
- filePath: input.filePath,
154
- ...(input.workspaceRoot ? { workspaceRoot: input.workspaceRoot } : {}),
155
- });
156
- warnOnce(`task-source:v${version}-shim:${input.filePath}`, `akm: task ${input.filePath} uses schema v${version} — auto-read as v4; run \`akm migrate apply\` to rewrite it and silence this`);
157
- return Object.freeze({ version: 4, v4 });
158
- }
159
- throw unmigratableVersionError(input.filePath, version, shimmed.reason, shimmed.detail);
160
- }
69
+ if (version === 2 || version === 3)
70
+ throw legacyVersionError(input.filePath, version);
161
71
  throw unsupportedVersionError(input.filePath, version);
162
72
  }
163
73
  if (version === TASK_SOURCE_V4_VERSION && v4ScheduleHasRetiredEnabledKey(root)) {
164
- const shimmed = planInMemoryV4Bytes(4, input.yaml, input.filePath, input.workspaceRoot);
165
- if (typeof shimmed === "string") {
166
- const v4 = parseTaskSourceV4({
167
- yaml: shimmed,
168
- filePath: input.filePath,
169
- ...(input.workspaceRoot ? { workspaceRoot: input.workspaceRoot } : {}),
170
- });
171
- warnOnce(`task-source:v4-schedule-enabled-shim:${input.filePath}`, `akm: task ${input.filePath} uses the retired schedule[].enabled field — auto-read with it ignored; run \`akm migrate apply\` to rewrite it and silence this`);
172
- return Object.freeze({ version: 4, v4 });
173
- }
174
- // Version 4 is supported; a blocked outcome here means the file itself
175
- // is malformed (`generated-v4-validation-failed`), not that this
176
- // version needs a human decision — throw the v4 grammar error, not
177
- // `unmigratableVersionError`.
178
- throw new UsageError(shimmed.detail ?? shimmed.reason, "TASK_SOURCE_INVALID");
74
+ throw new UsageError(`Invalid task source v4 at ${input.filePath}: schedule[].enabled was removed (scheduler activation is host-local config). Run \`akm migrate apply\` to rewrite it.`, "TASK_SOURCE_INVALID", TASK_MIGRATE_HINT);
179
75
  }
180
76
  const documentOptions = {
181
77
  filePath: input.filePath,